From 4371c46c4c204468051f9b664238cd566f11e45c Mon Sep 17 00:00:00 2001 From: Marcus Schiesser <mail@marcusschiesser.de> Date: Thu, 26 Oct 2023 16:33:02 +0700 Subject: [PATCH] add express example, framework selector and use existing package.json (just update it) --- packages/create-llama/create-app.ts | 10 +- packages/create-llama/index.ts | 31 +++++- packages/create-llama/templates/index.ts | 99 ++++++------------- .../simple/express/README-template.md | 19 ++++ .../templates/simple/express/eslintrc.json | 3 + .../templates/simple/express/index.ts | 17 ++++ .../templates/simple/express/package.json | 22 +++++ .../express/src/controllers/llm.controller.ts | 42 ++++++++ .../simple/express/src/routes/llm.route.ts | 8 ++ .../templates/simple/express/tsconfig.json | 11 +++ .../templates/simple/nextjs/package.json | 27 +++++ packages/create-llama/templates/types.ts | 8 +- 12 files changed, 213 insertions(+), 84 deletions(-) create mode 100644 packages/create-llama/templates/simple/express/README-template.md create mode 100644 packages/create-llama/templates/simple/express/eslintrc.json create mode 100644 packages/create-llama/templates/simple/express/index.ts create mode 100644 packages/create-llama/templates/simple/express/package.json create mode 100644 packages/create-llama/templates/simple/express/src/controllers/llm.controller.ts create mode 100644 packages/create-llama/templates/simple/express/src/routes/llm.route.ts create mode 100644 packages/create-llama/templates/simple/express/tsconfig.json create mode 100644 packages/create-llama/templates/simple/nextjs/package.json diff --git a/packages/create-llama/create-app.ts b/packages/create-llama/create-app.ts index 18e181179..8efef515f 100644 --- a/packages/create-llama/create-app.ts +++ b/packages/create-llama/create-app.ts @@ -8,25 +8,24 @@ import { getOnline } from "./helpers/is-online"; import { isWriteable } from "./helpers/is-writeable"; import { makeDir } from "./helpers/make-dir"; -import type { TemplateMode, TemplateType } from "./templates"; +import type { TemplateFramework, TemplateType } from "./templates"; import { installTemplate } from "./templates"; export async function createApp({ + framework, appPath, packageManager, - tailwind, eslint, srcDir, importAlias, }: { + framework: TemplateFramework; appPath: string; packageManager: PackageManager; - tailwind: boolean; eslint: boolean; srcDir: boolean; importAlias: string; }): Promise<void> { - const mode: TemplateMode = "nextjs"; const template: TemplateType = "simple"; const root = path.resolve(appPath); @@ -64,10 +63,9 @@ export async function createApp({ appName, root, template, - mode, + framework, packageManager, isOnline, - tailwind, eslint, srcDir, importAlias, diff --git a/packages/create-llama/index.ts b/packages/create-llama/index.ts index 01fac2d50..9ff2ee674 100644 --- a/packages/create-llama/index.ts +++ b/packages/create-llama/index.ts @@ -177,8 +177,8 @@ async function run(): Promise<void> { >; const defaults: typeof preferences = { + framework: "nextjs", eslint: true, - tailwind: true, app: true, srcDir: false, importAlias: "@/*", @@ -187,6 +187,33 @@ async function run(): Promise<void> { const getPrefOrDefault = (field: string) => preferences[field] ?? defaults[field]; + if (!program.framework) { + if (ciInfo.isCI) { + program.framework = getPrefOrDefault("framework"); + } else { + const { framework } = await prompts( + { + type: "select", + name: "framework", + message: "Which framework would you like to use?", + choices: [ + { title: "NextJS", value: "nextjs" }, + { title: "Express", value: "express" }, + ], + initial: 0, + }, + { + onCancel: () => { + console.error("Exiting."); + process.exit(1); + }, + }, + ); + program.framework = framework; + preferences.framework = framework; + } + } + if ( !process.argv.includes("--eslint") && !process.argv.includes("--no-eslint") @@ -248,9 +275,9 @@ async function run(): Promise<void> { } await createApp({ + framework: program.framework, appPath: resolvedProjectPath, packageManager, - tailwind: true, eslint: program.eslint, srcDir: program.srcDir, importAlias: program.importAlias, diff --git a/packages/create-llama/templates/index.ts b/packages/create-llama/templates/index.ts index ca013db06..d9de01f8d 100644 --- a/packages/create-llama/templates/index.ts +++ b/packages/create-llama/templates/index.ts @@ -8,21 +8,19 @@ import fs from "fs/promises"; import os from "os"; import path from "path"; import { bold, cyan } from "picocolors"; -import { version } from "../package.json" +import { version } from "../package.json"; import { GetTemplateFileArgs, InstallTemplateArgs } from "./types"; -const NEXT_VERSION = "13.5.6"; - /** * Get the file path for a given file in a template, e.g. "next.config.js". */ export const getTemplateFile = ({ template, - mode, + framework, file, }: GetTemplateFileArgs): string => { - return path.join(__dirname, template, mode, file); + return path.join(__dirname, template, framework, file); }; export const SRC_DIR_NAMES = ["app", "pages", "styles"]; @@ -36,8 +34,7 @@ export const installTemplate = async ({ packageManager, isOnline, template, - mode, - tailwind, + framework, eslint, srcDir, importAlias, @@ -48,14 +45,9 @@ export const installTemplate = async ({ * Copy the template files to the target directory. */ console.log("\nInitializing project with template:", template, "\n"); - const templatePath = path.join(__dirname, template, mode); + const templatePath = path.join(__dirname, template, framework); const copySource = ["**"]; if (!eslint) copySource.push("!eslintrc.json"); - if (!tailwind) - copySource.push( - mode == "nextjs" ? "tailwind.config.ts" : "!tailwind.config.js", - "!postcss.config.js", - ); await copy(copySource, root, { parents: true, @@ -148,7 +140,7 @@ export const installTemplate = async ({ ), ); - if (tailwind) { + if (framework === "nextjs") { const tailwindConfigFile = path.join(root, "tailwind.config.ts"); await fs.writeFile( tailwindConfigFile, @@ -160,64 +152,31 @@ export const installTemplate = async ({ } } - /** Create a package.json for the new project and write it to disk. */ - const packageJson: any = { - name: appName, - version: "0.1.0", - private: true, - scripts: { - dev: "next dev", - build: "next build", - start: "next start", - lint: "next lint", - }, - /** - * Default dependencies. - */ - dependencies: { - react: "^18", - "react-dom": "^18", - next: NEXT_VERSION, - llamaindex: version, - }, - devDependencies: {}, - }; - /** - * TypeScript projects will have type definitions and other devDependencies. + * Update the package.json scripts. */ - packageJson.devDependencies = { - ...packageJson.devDependencies, - typescript: "^5", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - }; + const packageJsonFile = path.join(root, "package.json"); + const packageJson: any = JSON.parse( + await fs.readFile(packageJsonFile, "utf8"), + ); + packageJson.name = appName; + packageJson.version = "0.1.0"; - /* Add Tailwind CSS dependencies. */ - if (tailwind) { - packageJson.devDependencies = { - ...packageJson.devDependencies, - autoprefixer: "^10", - postcss: "^8", - tailwindcss: "^3", - }; - } + packageJson.dependencies = { + ...packageJson.dependencies, + llamaindex: version, + }; - /* Default ESLint dependencies. */ - if (eslint) { - packageJson.devDependencies = { - ...packageJson.devDependencies, - eslint: "^8", - "eslint-config-next": NEXT_VERSION, - }; + if (!eslint) { + // Remove packages starting with "eslint" from devDependencies + packageJson.devDependencies = Object.fromEntries( + Object.entries(packageJson.devDependencies).filter( + ([key]) => !key.startsWith("eslint"), + ), + ); } - - const devDeps = Object.keys(packageJson.devDependencies).length; - if (!devDeps) delete packageJson.devDependencies; - await fs.writeFile( - path.join(root, "package.json"), + packageJsonFile, JSON.stringify(packageJson, null, 2) + os.EOL, ); @@ -225,11 +184,9 @@ export const installTemplate = async ({ for (const dependency in packageJson.dependencies) console.log(`- ${cyan(dependency)}`); - if (devDeps) { - 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(); diff --git a/packages/create-llama/templates/simple/express/README-template.md b/packages/create-llama/templates/simple/express/README-template.md new file mode 100644 index 000000000..b00c2e8d8 --- /dev/null +++ b/packages/create-llama/templates/simple/express/README-template.md @@ -0,0 +1,19 @@ +1. Install the dependencies +``` +pnpm install +``` + +2. Run the server +``` +pnpm run dev +``` + +3. Call the API to LLM Chat +``` +curl --location 'localhost:3000/api/llm' \ +--header 'Content-Type: application/json' \ +--data '{ + "message": "Hello", + "chatHistory": [] +}' +``` \ No newline at end of file diff --git a/packages/create-llama/templates/simple/express/eslintrc.json b/packages/create-llama/templates/simple/express/eslintrc.json new file mode 100644 index 000000000..c19581799 --- /dev/null +++ b/packages/create-llama/templates/simple/express/eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "eslint:recommended" +} \ No newline at end of file diff --git a/packages/create-llama/templates/simple/express/index.ts b/packages/create-llama/templates/simple/express/index.ts new file mode 100644 index 000000000..157555572 --- /dev/null +++ b/packages/create-llama/templates/simple/express/index.ts @@ -0,0 +1,17 @@ +import express, { Express, Request, Response } from "express"; +import llmRouter from "./src/routes/llm.route"; + +const app: Express = express(); +const port = 3000; + +app.use(express.json()); + +app.get("/", (req: Request, res: Response) => { + res.send("LlamaIndex Express Server"); +}); + +app.use("/api/llm", llmRouter); + +app.listen(port, () => { + console.log(`⚡️[server]: Server is running at http://localhost:${port}`); +}); diff --git a/packages/create-llama/templates/simple/express/package.json b/packages/create-llama/templates/simple/express/package.json new file mode 100644 index 000000000..3b57d610e --- /dev/null +++ b/packages/create-llama/templates/simple/express/package.json @@ -0,0 +1,22 @@ +{ + "name": "llama-index-express", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "build": "tsc", + "start": "node dist/index.js", + "dev": "concurrently \"tsc --watch\" \"nodemon -q dist/index.js\"" + }, + "dependencies": { + "express": "^4", + "llamaindex": "0.0.31" + }, + "devDependencies": { + "@types/express": "^4", + "@types/node": "^20", + "concurrently": "^8", + "nodemon": "^3", + "typescript": "^5", + "eslint": "^8" + } +} \ No newline at end of file diff --git a/packages/create-llama/templates/simple/express/src/controllers/llm.controller.ts b/packages/create-llama/templates/simple/express/src/controllers/llm.controller.ts new file mode 100644 index 000000000..54fa51b13 --- /dev/null +++ b/packages/create-llama/templates/simple/express/src/controllers/llm.controller.ts @@ -0,0 +1,42 @@ +import { ChatMessage, OpenAI, SimpleChatEngine } from "llamaindex"; +import { NextFunction, Request, Response } from "express"; + +export const chat = async (req: Request, res: Response, next: NextFunction) => { + try { + const { + message, + chatHistory, + }: { + message: string; + chatHistory: ChatMessage[]; + } = req.body; + if (!message || !chatHistory) { + return res.status(400).json({ + error: "message, chatHistory are required in the request body", + }); + } + + const llm = new OpenAI({ + model: "gpt-3.5-turbo", + }); + + const chatEngine = new SimpleChatEngine({ + llm, + }); + + const response = await chatEngine.chat(message, chatHistory); + const result: ChatMessage = { + role: "assistant", + content: response.response, + }; + + return res.status(200).json({ + result, + }); + } catch (error) { + console.error("[LlamaIndex]", error); + return res.status(500).json({ + error: (error as Error).message, + }); + } +}; diff --git a/packages/create-llama/templates/simple/express/src/routes/llm.route.ts b/packages/create-llama/templates/simple/express/src/routes/llm.route.ts new file mode 100644 index 000000000..3711c71b9 --- /dev/null +++ b/packages/create-llama/templates/simple/express/src/routes/llm.route.ts @@ -0,0 +1,8 @@ +import express from "express"; +import { chat } from "../controllers/llm.controller"; + +const llmRouter = express.Router(); + +llmRouter.route("/").post(chat); + +export default llmRouter; diff --git a/packages/create-llama/templates/simple/express/tsconfig.json b/packages/create-llama/templates/simple/express/tsconfig.json new file mode 100644 index 000000000..fd70902d6 --- /dev/null +++ b/packages/create-llama/templates/simple/express/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} diff --git a/packages/create-llama/templates/simple/nextjs/package.json b/packages/create-llama/templates/simple/nextjs/package.json new file mode 100644 index 000000000..afb59904c --- /dev/null +++ b/packages/create-llama/templates/simple/nextjs/package.json @@ -0,0 +1,27 @@ +{ + "name": "llama-index-nextjs", + "version": "1.0.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "react": "^18", + "react-dom": "^18", + "next": "^13", + "llamaindex": "0.0.31" + }, + "devDependencies": { + "typescript": "^5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "autoprefixer": "^10", + "postcss": "^8", + "tailwindcss": "^3", + "eslint": "^8", + "eslint-config-next": "^13" + } +} \ No newline at end of file diff --git a/packages/create-llama/templates/types.ts b/packages/create-llama/templates/types.ts index 5312d80dd..9cd44c968 100644 --- a/packages/create-llama/templates/types.ts +++ b/packages/create-llama/templates/types.ts @@ -1,11 +1,11 @@ import { PackageManager } from "../helpers/get-pkg-manager"; export type TemplateType = "simple"; -export type TemplateMode = "nextjs"; +export type TemplateFramework = "nextjs" | "express"; export interface GetTemplateFileArgs { template: TemplateType; - mode: TemplateMode; + framework: TemplateFramework; file: string; } @@ -14,11 +14,9 @@ export interface InstallTemplateArgs { root: string; packageManager: PackageManager; isOnline: boolean; - template: TemplateType; - mode: TemplateMode; + framework: TemplateFramework; eslint: boolean; - tailwind: boolean; srcDir: boolean; importAlias: string; } -- GitLab