diff --git a/.changeset/silly-bugs-fold.md b/.changeset/silly-bugs-fold.md new file mode 100644 index 0000000000000000000000000000000000000000..b34dfa9408e9f0fe068848a47839f59a63564b2f --- /dev/null +++ b/.changeset/silly-bugs-fold.md @@ -0,0 +1,5 @@ +--- +"create-llama": patch +--- + +Added option to automatically install dependencies (for Python and TS) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index f87865ebf51a688a2ad3154f8c9ac471b81a9943..cc4dbadce9c2973115149b25c37e80c97a68ae85 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -8,6 +8,9 @@ on: - ".github/workflows/e2e.yml" branches: [main] +env: + POETRY_VERSION: "1.6.1" + jobs: e2e: name: create-llama @@ -16,10 +19,19 @@ jobs: fail-fast: true matrix: node-version: [18, 20] + python-version: ["3.11"] os: [macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - name: Set up python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: ${{ env.POETRY_VERSION }} - uses: pnpm/action-setup@v2 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 diff --git a/packages/create-llama/create-app.ts b/packages/create-llama/create-app.ts index 65ff0a9f7cbda75dc85e1f57bd65f5bbc7d04c54..a0d437010b0b1499e5ee2d1f3ea987f7ea7cf713 100644 --- a/packages/create-llama/create-app.ts +++ b/packages/create-llama/create-app.ts @@ -34,6 +34,7 @@ export async function createApp({ communityProjectPath, vectorDb, externalPort, + installDependencies, }: InstallAppArgs): Promise<void> { const root = path.resolve(appPath); @@ -75,6 +76,7 @@ export async function createApp({ communityProjectPath, vectorDb, externalPort, + installDependencies, }; if (frontend) { diff --git a/packages/create-llama/e2e/utils.ts b/packages/create-llama/e2e/utils.ts index 8bbc1330e7519052827f0909da371d43628c5dbc..a792c13e4a889dd172cd3cc559e817e644381dea 100644 --- a/packages/create-llama/e2e/utils.ts +++ b/packages/create-llama/e2e/utils.ts @@ -104,6 +104,7 @@ export function runCreateLlama( "--use-npm", "--external-port", externalPort, + "--install-dependencies", ].join(" "); console.log(`running command '${command}' in ${cwd}`); execSync(command, { diff --git a/packages/create-llama/helpers/index.ts b/packages/create-llama/helpers/index.ts index 3f8dad54b473c1f5057b4be4ecc1895117e387a9..858d01d95c60db391577f556df612b925a11ff2f 100644 --- a/packages/create-llama/helpers/index.ts +++ b/packages/create-llama/helpers/index.ts @@ -7,6 +7,7 @@ import { cyan } from "picocolors"; import { COMMUNITY_OWNER, COMMUNITY_REPO } from "./constant"; import { PackageManager } from "./get-pkg-manager"; +import { isHavingPoetryLockFile, tryPoetryRun } from "./poetry"; import { installPythonTemplate } from "./python"; import { downloadAndExtractRepo } from "./repo"; import { @@ -89,18 +90,23 @@ const copyTestData = async ( if (packageManager && engine === "context") { const runGenerate = `${cyan( framework === "fastapi" - ? "python app/engine/generate.py" + ? "poetry run python app/engine/generate.py" : `${packageManager} run generate`, )}`; const hasOpenAiKey = openAiKey || process.env["OPENAI_API_KEY"]; const hasVectorDb = vectorDb && vectorDb !== "none"; - const shouldRunGenerateAfterInstall = - hasOpenAiKey && framework !== "fastapi" && vectorDb === "none"; - if (shouldRunGenerateAfterInstall) { - console.log(`\nRunning ${runGenerate} to generate the context data.\n`); - await callPackageManager(packageManager, true, ["run", "generate"]); - console.log(); - return; + if (framework === "fastapi") { + if (hasOpenAiKey && vectorDb === "none" && isHavingPoetryLockFile()) { + console.log(`Running ${runGenerate} to generate the context data.`); + tryPoetryRun("python app/engine/generate.py"); + return; + } + } else { + if (hasOpenAiKey && vectorDb === "none") { + console.log(`Running ${runGenerate} to generate the context data.`); + await callPackageManager(packageManager, true, ["run", "generate"]); + return; + } } const settings = []; diff --git a/packages/create-llama/helpers/poetry.ts b/packages/create-llama/helpers/poetry.ts new file mode 100644 index 0000000000000000000000000000000000000000..a42b2be02d6ea8ba386c59ef34968c7194572f73 --- /dev/null +++ b/packages/create-llama/helpers/poetry.ts @@ -0,0 +1,34 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { execSync } from "child_process"; +import fs from "fs"; + +export function isPoetryAvailable(): boolean { + try { + execSync("poetry --version", { stdio: "ignore" }); + return true; + } catch (_) {} + return false; +} + +export function tryPoetryInstall(): boolean { + try { + execSync("poetry install", { stdio: "inherit" }); + return true; + } catch (_) {} + return false; +} + +export function tryPoetryRun(command: string): boolean { + try { + execSync(`poetry run ${command}`, { stdio: "inherit" }); + return true; + } catch (_) {} + return false; +} + +export function isHavingPoetryLockFile(): boolean { + try { + return fs.existsSync("poetry.lock"); + } catch (_) {} + return false; +} diff --git a/packages/create-llama/helpers/python.ts b/packages/create-llama/helpers/python.ts index 3c631b6ee39603400b33487fb328f9cd6aaed0d2..4b28231013b9252f5a86ffcaa11253e0765daed1 100644 --- a/packages/create-llama/helpers/python.ts +++ b/packages/create-llama/helpers/python.ts @@ -1,8 +1,10 @@ import fs from "fs/promises"; import path from "path"; -import { cyan } from "picocolors"; +import { cyan, yellow } from "picocolors"; import { parse, stringify } from "smol-toml"; +import terminalLink from "terminal-link"; import { copy } from "./copy"; +import { isPoetryAvailable, tryPoetryInstall } from "./poetry"; import { InstallTemplateArgs, TemplateVectorDB } from "./types"; interface Dependency { @@ -96,9 +98,15 @@ export const installPythonTemplate = async ({ framework, engine, vectorDb, + installDependencies, }: Pick< InstallTemplateArgs, - "root" | "framework" | "template" | "engine" | "vectorDb" + | "root" + | "framework" + | "template" + | "engine" + | "vectorDb" + | "installDependencies" >) => { console.log("\nInitializing Python project with template:", template, "\n"); const templatePath = path.join( @@ -146,7 +154,28 @@ export const installPythonTemplate = async ({ const addOnDependencies = getAdditionalDependencies(vectorDb); await addDependencies(root, addOnDependencies); - console.log( - "\nPython project, dependencies won't be installed automatically.\n", - ); + // install python dependencies + if (installDependencies) { + if (isPoetryAvailable()) { + console.log( + `Installing python dependencies using poetry. This may take a while...`, + ); + const installSuccessful = tryPoetryInstall(); + if (!installSuccessful) { + console.warn( + yellow("Install failed. Please install dependencies manually."), + ); + } + } else { + console.warn( + yellow( + `Poetry is not available in the current environment. The Python dependencies will not be installed automatically. +Please check ${terminalLink( + "Poetry Installation", + `https://python-poetry.org/docs/#installation`, + )} to install poetry first, then install the dependencies manually.`, + ), + ); + } + } }; diff --git a/packages/create-llama/helpers/types.ts b/packages/create-llama/helpers/types.ts index e245c8644a2ee6c67f8814164e9a2b21023abafc..6c85c1c912c52622d027efc3df6ccf49a3b17957 100644 --- a/packages/create-llama/helpers/types.ts +++ b/packages/create-llama/helpers/types.ts @@ -23,4 +23,5 @@ export interface InstallTemplateArgs { communityProjectPath?: string; vectorDb?: TemplateVectorDB; externalPort?: number; + installDependencies?: boolean; } diff --git a/packages/create-llama/helpers/typescript.ts b/packages/create-llama/helpers/typescript.ts index 9d498b406988379b35958e899d17596359825e4b..81b895042a16958115773d658dd582a8d427b25f 100644 --- a/packages/create-llama/helpers/typescript.ts +++ b/packages/create-llama/helpers/typescript.ts @@ -39,6 +39,7 @@ export const installTSTemplate = async ({ customApiPath, forBackend, vectorDb, + installDependencies, }: InstallTemplateArgs) => { console.log(bold(`Using ${packageManager}.`)); @@ -210,15 +211,17 @@ export const installTSTemplate = async ({ JSON.stringify(packageJson, null, 2) + os.EOL, ); - console.log("\nInstalling dependencies:"); - for (const dependency in packageJson.dependencies) - console.log(`- ${cyan(dependency)}`); + if (installDependencies) { + console.log("\nInstalling dependencies:"); + for (const dependency in packageJson.dependencies) + console.log(`- ${cyan(dependency)}`); - console.log("\nInstalling devDependencies:"); - for (const dependency in packageJson.devDependencies) - console.log(`- ${cyan(dependency)}`); + console.log("\nInstalling devDependencies:"); + for (const dependency in packageJson.devDependencies) + console.log(`- ${cyan(dependency)}`); - console.log(); + console.log(); - await callPackageManager(packageManager, isOnline); + await callPackageManager(packageManager, isOnline); + } }; diff --git a/packages/create-llama/index.ts b/packages/create-llama/index.ts index ebdcd1ee26cabad35f55fe8c5389a24d5cb04bc3..4be39f65f63aebdb13c6c41653c25223950791dc 100644 --- a/packages/create-llama/index.ts +++ b/packages/create-llama/index.ts @@ -117,6 +117,13 @@ const program = new Commander.Command(packageJson.name) ` Select external port. +`, + ) + .option( + "--install-dependencies", + ` + +Whether install dependencies (backend/frontend) automatically or not. `, ) .allowUnknownOption() @@ -224,6 +231,7 @@ async function run(): Promise<void> { communityProjectPath: program.communityProjectPath, vectorDb: program.vectorDb, externalPort: program.externalPort, + installDependencies: program.installDependencies, }); conf.set("preferences", preferences); } diff --git a/packages/create-llama/questions.ts b/packages/create-llama/questions.ts index ea130e36fa1e32795611dc667913c5d24be1e486..c6fd984aae27d7ee6f4c7b7f3fcc24c3db52228f 100644 --- a/packages/create-llama/questions.ts +++ b/packages/create-llama/questions.ts @@ -211,6 +211,19 @@ export const askQuestions = async ( } } + if (program.installDependencies === undefined) { + const { installDependencies } = await prompts({ + onState: onPromptState, + type: "toggle", + name: "installDependencies", + message: `Would you like to install dependencies automatically? This may take a while`, + initial: getPrefOrDefault("installDependencies"), + active: "Yes", + inactive: "No", + }); + program.installDependencies = Boolean(installDependencies); + } + if (!program.model) { if (ciInfo.isCI) { program.model = getPrefOrDefault("model");