Compare commits

..

2 Commits

Author SHA1 Message Date
leehuwuj 670e2631f3 bump @llamaindex/server 2025-04-02 17:20:32 +07:00
leehuwuj afb519d231 fix llamacloud api and markdown issue 2025-04-02 16:51:21 +07:00
573 changed files with 2826 additions and 24116 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"create-llama": patch
---
fix: add trycatch for generating error
+5
View File
@@ -0,0 +1,5 @@
---
"create-llama": patch
---
bump: chat-ui and tailwind v4
+24 -27
View File
@@ -1,13 +1,12 @@
name: E2E Tests for create-llama package
name: E2E Tests
on:
push:
branches: [main]
paths-ignore:
- "python/llama-index-server/**"
pull_request:
branches: [main]
paths-ignore:
- "python/llama-index-server/**"
env:
POETRY_VERSION: "1.6.1"
jobs:
e2e-python:
@@ -33,10 +32,10 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH # Ensure uv is available in subsequent steps
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- uses: pnpm/action-setup@v3
@@ -51,15 +50,15 @@ jobs:
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
working-directory: packages/create-llama
working-directory: .
- name: Build create-llama
run: pnpm run build
working-directory: packages/create-llama
working-directory: .
- name: Install
run: pnpm run pack-install
working-directory: packages/create-llama
working-directory: .
- name: Run Playwright tests for Python
run: pnpm run e2e:python
@@ -68,15 +67,13 @@ jobs:
LLAMA_CLOUD_API_KEY: ${{ secrets.LLAMA_CLOUD_API_KEY }}
FRAMEWORK: ${{ matrix.frameworks }}
DATASOURCE: ${{ matrix.datasources }}
PYTHONIOENCODING: utf-8
PYTHONLEGACYWINDOWSSTDIO: utf-8
working-directory: packages/create-llama
working-directory: .
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-python-${{ matrix.os }}-${{ matrix.frameworks }}-${{ matrix.datasources }}
path: packages/create-llama/playwright-report/
path: ./playwright-report/
overwrite: true
retention-days: 30
@@ -86,10 +83,10 @@ jobs:
strategy:
fail-fast: true
matrix:
node-version: [20, 22]
node-version: [18, 20]
python-version: ["3.11"]
os: [macos-latest, windows-latest, ubuntu-22.04]
frameworks: ["nextjs"]
frameworks: ["nextjs", "express"]
datasources: ["--no-files", "--example-file", "--llamacloud"]
defaults:
run:
@@ -103,10 +100,10 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH # Ensure uv is available in subsequent steps
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- uses: pnpm/action-setup@v3
@@ -121,15 +118,15 @@ jobs:
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
working-directory: packages/create-llama
working-directory: .
- name: Build create-llama
run: pnpm run build
working-directory: packages/create-llama
working-directory: .
- name: Install
run: pnpm run pack-install
working-directory: packages/create-llama
working-directory: .
- name: Run Playwright tests for TypeScript
run: pnpm run e2e:typescript
@@ -138,12 +135,12 @@ jobs:
LLAMA_CLOUD_API_KEY: ${{ secrets.LLAMA_CLOUD_API_KEY }}
FRAMEWORK: ${{ matrix.frameworks }}
DATASOURCE: ${{ matrix.datasources }}
working-directory: packages/create-llama
working-directory: .
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-typescript-${{ matrix.os }}-${{ matrix.frameworks }}-${{ matrix.datasources }}-node${{ matrix.node-version }}
path: packages/create-llama/playwright-report/
path: ./playwright-report/
overwrite: true
retention-days: 30
@@ -35,10 +35,8 @@ jobs:
uses: chartboost/ruff-action@v1
with:
args: "format --check"
src: "python/llama-index-server"
- name: Run Python lint
uses: chartboost/ruff-action@v1
with:
args: "check"
src: "python/llama-index-server"
@@ -5,7 +5,7 @@ on:
branches:
- main
paths:
- "python/llama-index-server/**"
- "llama-index-server/**"
- ".github/workflows/release_llama_index_server.yml"
pull_request:
types:
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./python/llama-index-server
working-directory: ./llama-index-server
if: |
github.event_name == 'push' &&
!startsWith(github.ref, 'refs/heads/release/llama-index-server-v')
@@ -80,7 +80,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./python/llama-index-server
working-directory: ./llama-index-server
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
@@ -114,7 +114,7 @@ jobs:
with:
python_version: "3.11"
pypi_token: ${{ secrets.PYPI_TOKEN }}
package_directory: "python/llama-index-server"
package_directory: "llama-index-server"
poetry_install_options: "--without dev"
- name: Create GitHub Release
@@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: python/llama-index-server
working-directory: llama-index-server
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
@@ -50,7 +50,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: python/llama-index-server
working-directory: llama-index-server
steps:
- uses: actions/checkout@v4
@@ -82,7 +82,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: python/llama-index-server
working-directory: llama-index-server
steps:
- uses: actions/checkout@v4
- name: Install Poetry
@@ -108,4 +108,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: llama-index-server
path: python/llama-index-server/dist/
path: llama-index-server/dist/
+26
View File
@@ -6,6 +6,10 @@ node_modules
.pnpm-store
.pnp.js
# testing
coverage
.coverage
# next.js
.next/
out/
@@ -31,9 +35,31 @@ yarn-error.log*
dist/
lib/
# e2e
.cache
test-results/
playwright-report/
blob-report/
playwright/.cache/
.tsbuildinfo
e2e/cache
# intellij
**/.idea
# Python
.mypy_cache/
venv/
.venv/
dist/
.__pycache__
__pycache__
.python-version
.ui
# build artifacts
create-llama-*.tgz
# vscode
.vscode
!.vscode/settings.json
+1 -1
View File
@@ -1,3 +1,3 @@
pnpm format
pnpm lint
uvx ruff format --check packages/create-llama/templates/
uvx ruff format --check templates/
@@ -1,84 +1,5 @@
# create-llama
## 0.5.11
### Patch Changes
- 3960618: chore: create-llama monorepo
- 8fe5fc2: chore: add llamaindex server package
## 0.5.10
### Patch Changes
- 0a2e12a: Use uv as the default package manager
## 0.5.9
### Patch Changes
- 4bc53ac: Bump new chat ui and update deep research component
- 4bc53ac: Support generate UI for deep research use case (Typescript)
## 0.5.8
### Patch Changes
- 765181a: chore: test typescript e2e with node 20 and 22
## 0.5.7
### Patch Changes
- 5988657: chore: bump llmaindex
## 0.5.6
### Patch Changes
- d363ced: Bump llamaindex server packages
## 0.5.5
### Patch Changes
- ee85320: The default custom deep research component does not work.
## 0.5.4
### Patch Changes
- 7c3b279: Support code generation of event components using an LLM (Python)
## 0.5.3
### Patch Changes
- 76ec360: Update templates to use new chat ui config
## 0.5.2
### Patch Changes
- c9f8f8d: Use custom component for deep research use case
## 0.5.1
### Patch Changes
- 08b3e07: Simplify the local index code.
## 0.5.0
### Minor Changes
- 54c9e2f: Simplified generated code using LlamaIndexServer
### Patch Changes
- 0e4ecfa: fix: add trycatch for generating error
- ee69ce7: bump: chat-ui and tailwind v4
## 0.4.0
### Minor Changes
+1 -8
View File
@@ -55,7 +55,7 @@ Then re-start your app. Remember you'll need to re-run `generate` if you add new
If you're using the Python backend, you can trigger indexing of your data by calling:
```bash
uv run generate
poetry run generate
```
## Customizing the AI models
@@ -130,11 +130,4 @@ Pro mode is ideal for developers who want fine-grained control over their projec
- [TS/JS docs](https://ts.llamaindex.ai/)
- [Python docs](https://docs.llamaindex.ai/en/stable/)
## LlamaIndex Server
The generated code is using the LlamaIndex Server, which serves LlamaIndex Workflows and Agent Workflows via an API server. See the following docs for more information:
- [LlamaIndex Server For TypeScript](./packages/server/README.md)
- [LlamaIndex Server For Python](./python/llama-index-server/README.md)
Inspired by and adapted from [create-next-app](https://github.com/vercel/next.js/tree/canary/packages/create-next-app)
@@ -90,7 +90,7 @@ export async function createApp({
// Install backend
await installTemplate({ ...args, backend: true });
if (frontend && framework === "fastapi" && template !== "llamaindexserver") {
if (frontend && framework === "fastapi") {
// install frontend
const frontendRoot = path.join(root, ".frontend");
await makeDir(frontendRoot);
@@ -110,7 +110,7 @@ export async function createApp({
console.log();
}
if (toolsRequireConfig(tools) && template !== "llamaindexserver") {
if (toolsRequireConfig(tools)) {
const configFile =
framework === "fastapi" ? "config/tools.yaml" : "config/tools.json";
console.log(
@@ -195,47 +195,32 @@ async function createAndCheckLlamaProject({
const pyprojectPath = path.join(projectPath, "pyproject.toml");
expect(fs.existsSync(pyprojectPath)).toBeTruthy();
// Modify environment for the command
const commandEnv = {
const env = {
...process.env,
POETRY_VIRTUALENVS_IN_PROJECT: "true",
};
console.log("Running uv venv...");
// Run poetry install
try {
const { stdout: venvStdout, stderr: venvStderr } = await execAsync(
"uv venv",
{ cwd: projectPath, env: commandEnv },
const { stdout: installStdout, stderr: installStderr } = await execAsync(
"poetry install",
{ cwd: projectPath, env },
);
console.log("uv venv stdout:", venvStdout);
console.error("uv venv stderr:", venvStderr);
console.log("poetry install stdout:", installStdout);
console.error("poetry install stderr:", installStderr);
} catch (error) {
console.error("Error running uv venv:", error);
throw error; // Re-throw error to fail the test
console.error("Error running poetry install:", error);
throw error;
}
console.log("Running uv sync...");
try {
const { stdout: syncStdout, stderr: syncStderr } = await execAsync(
"uv sync --all-extras",
{ cwd: projectPath, env: commandEnv },
);
console.log("uv sync stdout:", syncStdout);
console.error("uv sync stderr:", syncStderr);
} catch (error) {
console.error("Error running uv sync:", error);
throw error; // Re-throw error to fail the test
}
console.log("Running uv run mypy ....");
// Run poetry run mypy
try {
const { stdout: mypyStdout, stderr: mypyStderr } = await execAsync(
"uv run mypy .",
{ cwd: projectPath, env: commandEnv },
"poetry run mypy .",
{ cwd: projectPath, env },
);
console.log("uv run mypy stdout:", mypyStdout);
console.error("uv run mypy stderr:", mypyStderr);
// Assuming mypy success means no output or specific success message
// Adjust checks based on actual expected mypy output
console.log("poetry run mypy stdout:", mypyStdout);
console.error("poetry run mypy stderr:", mypyStderr);
} catch (error) {
console.error("Error running mypy:", error);
throw error;
@@ -16,17 +16,15 @@ const templateFramework: TemplateFramework = process.env.FRAMEWORK
const dataSource: string = "--example-file";
const templateUI: TemplateUI = "shadcn";
const templatePostInstallAction: TemplatePostInstallAction = "runApp";
const appType: AppType = "--frontend";
const appType: AppType = templateFramework === "fastapi" ? "--frontend" : "";
const userMessage = "Write a blog post about physical standards for letters";
const templateUseCases = ["financial_report", "agentic_rag", "deep_research"];
const templateUseCases = ["financial_report", "blog", "form_filling"];
for (const useCase of templateUseCases) {
test.describe(`Test use case ${useCase} ${templateFramework} ${dataSource} ${templateUI} ${appType} ${templatePostInstallAction}`, async () => {
test.describe(`Test multiagent template ${useCase} ${templateFramework} ${dataSource} ${templateUI} ${appType} ${templatePostInstallAction}`, async () => {
test.skip(
process.platform !== "linux" ||
process.env.DATASOURCE === "--no-files" ||
templateFramework === "express",
"The llamaindexserver template currently only works with nextjs, fastapi. We also only run on Linux to speed up tests.",
process.platform !== "linux" || process.env.DATASOURCE === "--no-files",
"The multiagent template currently only works with files. We also only run on Linux to speed up tests.",
);
let port: number;
let cwd: string;
@@ -40,7 +38,7 @@ for (const useCase of templateUseCases) {
cwd = await createTestDir();
const result = await runCreateLlama({
cwd,
templateType: "llamaindexserver",
templateType: "multiagent",
templateFramework,
dataSource,
vectorDb,
@@ -65,9 +63,7 @@ for (const useCase of templateUseCases) {
templateFramework === "express",
);
await page.goto(`http://localhost:${port}`);
await expect(page.getByText("Built by LlamaIndex")).toBeVisible({
timeout: 5 * 60 * 1000,
});
await expect(page.getByText("Built by LlamaIndex")).toBeVisible();
});
test("Frontend should be able to submit a message and receive the start of a streamed response", async ({
@@ -76,9 +72,9 @@ for (const useCase of templateUseCases) {
test.skip(
templatePostInstallAction !== "runApp" ||
useCase === "financial_report" ||
useCase === "deep_research" ||
useCase === "form_filling" ||
templateFramework === "express",
"Skip chat tests for financial report and deep research.",
"Skip chat tests for financial report and form filling.",
);
await page.goto(`http://localhost:${port}`);
await page.fill("form textarea", userMessage);
@@ -90,12 +86,6 @@ for (const useCase of templateUseCases) {
await page.click("form button[type=submit]");
const response = await responsePromise;
console.log(`Response status: ${response.status()}`);
const responseBody = await response
.text()
.catch((e) => `Error reading body: ${e}`);
console.log(`Response body: ${responseBody}`);
expect(response.ok()).toBeTruthy();
});
@@ -74,7 +74,7 @@ test.describe("Test resolve TS dependencies", () => {
// Install dependencies using pnpm
try {
const { stderr: installStderr } = await execAsync(
"pnpm install --prefer-offline --ignore-workspace",
"pnpm install --prefer-offline",
{
cwd: appDir,
},
@@ -113,12 +113,7 @@ export async function runCreateLlama({
if (observability) {
commandArgs.push("--observability", observability);
}
if (
(templateType === "multiagent" ||
templateType === "reflex" ||
templateType === "llamaindexserver") &&
useCase
) {
if ((templateType === "multiagent" || templateType === "reflex") && useCase) {
commandArgs.push("--use-case", useCase);
}
@@ -44,7 +44,6 @@ const renderEnvVar = (envVars: EnvVar[]): string => {
const getVectorDBEnvs = (
vectorDb?: TemplateVectorDB,
framework?: TemplateFramework,
template?: TemplateType,
): EnvVar[] => {
if (!vectorDb || !framework) {
return [];
@@ -169,7 +168,7 @@ const getVectorDBEnvs = (
description:
"The organization ID for the LlamaCloud project (uses default organization if not specified)",
},
...(framework === "nextjs" && template !== "llamaindexserver"
...(framework === "nextjs"
? // activate index selector per default (not needed for non-NextJS backends as it's handled by createFrontendEnvFile)
[
{
@@ -224,15 +223,13 @@ Otherwise, use CHROMA_HOST and CHROMA_PORT config above`,
},
];
default:
return template !== "llamaindexserver"
? [
{
name: "STORAGE_CACHE_DIR",
description: "The directory to store the local storage cache.",
value: ".cache",
},
]
: [];
return [
{
name: "STORAGE_CACHE_DIR",
description: "The directory to store the local storage cache.",
value: ".cache",
},
];
}
};
@@ -385,42 +382,38 @@ const getModelEnvs = (modelConfig: ModelConfig): EnvVar[] => {
const getFrameworkEnvs = (
framework: TemplateFramework,
template: TemplateType,
port?: number,
): EnvVar[] => {
const sPort = port?.toString() || "8000";
const result: EnvVar[] =
template !== "llamaindexserver"
? [
{
name: "FILESERVER_URL_PREFIX",
description:
"FILESERVER_URL_PREFIX is the URL prefix of the server storing the images generated by the interpreter.",
value:
framework === "nextjs"
? // FIXME: if we are using nextjs, port should be 3000
"http://localhost:3000/api/files"
: `http://localhost:${sPort}/api/files`,
},
]
: [];
const result: EnvVar[] = [
{
name: "FILESERVER_URL_PREFIX",
description:
"FILESERVER_URL_PREFIX is the URL prefix of the server storing the images generated by the interpreter.",
value:
framework === "nextjs"
? // FIXME: if we are using nextjs, port should be 3000
"http://localhost:3000/api/files"
: `http://localhost:${sPort}/api/files`,
},
];
if (framework === "fastapi") {
result.push(
...[
{
name: "APP_HOST",
description: "The address to start the FastAPI app.",
description: "The address to start the backend app.",
value: "0.0.0.0",
},
{
name: "APP_PORT",
description: "The port to start the FastAPI app.",
description: "The port to start the backend app.",
value: sPort,
},
],
);
}
if (framework === "nextjs" && template !== "llamaindexserver") {
if (framework === "nextjs") {
result.push({
name: "NEXT_PUBLIC_CHAT_API",
description:
@@ -576,41 +569,25 @@ export const createBackendEnvFile = async (
| "port"
| "tools"
| "observability"
| "useLlamaParse"
>,
) => {
// Init env values
const envFileName = ".env";
const envVars: EnvVar[] = [
...(opts.useLlamaParse
? [
{
name: "LLAMA_CLOUD_API_KEY",
description: `The Llama Cloud API key.`,
value: opts.llamaCloudKey,
},
]
: []),
...getVectorDBEnvs(opts.vectorDb, opts.framework, opts.template),
...getToolEnvs(opts.tools),
...getFrameworkEnvs(opts.framework, opts.template, opts.port),
{
name: "LLAMA_CLOUD_API_KEY",
description: `The Llama Cloud API key.`,
value: opts.llamaCloudKey,
},
// Add environment variables of each component
...(opts.template === "llamaindexserver"
? [
{
name: "OPENAI_API_KEY",
description: "The OpenAI API key to use.",
value: opts.modelConfig.apiKey,
},
]
: [
// don't use this stuff for llama-indexserver
...getModelEnvs(opts.modelConfig),
...getEngineEnvs(),
...getTemplateEnvs(opts.template),
...getObservabilityEnvs(opts.observability),
...getSystemPromptEnv(opts.tools, opts.dataSources, opts.template),
]),
...getModelEnvs(opts.modelConfig),
...getEngineEnvs(),
...getVectorDBEnvs(opts.vectorDb, opts.framework),
...getFrameworkEnvs(opts.framework, opts.port),
...getToolEnvs(opts.tools),
...getTemplateEnvs(opts.template),
...getObservabilityEnvs(opts.observability),
...getSystemPromptEnv(opts.tools, opts.dataSources, opts.template),
];
// Render and write env file
const content = renderEnvVar(envVars);
@@ -1,7 +1,7 @@
import { callPackageManager } from "./install";
import path from "path";
import picocolors, { cyan } from "picocolors";
import { cyan } from "picocolors";
import fsExtra from "fs-extra";
import { writeLoadersConfig } from "./datasources";
@@ -9,6 +9,7 @@ import { createBackendEnvFile, createFrontendEnvFile } from "./env-variables";
import { PackageManager } from "./get-pkg-manager";
import { installLlamapackProject } from "./llama-pack";
import { makeDir } from "./make-dir";
import { isHavingPoetryLockFile, tryPoetryRun } from "./poetry";
import { installPythonTemplate } from "./python";
import { downloadAndExtractRepo } from "./repo";
import { ConfigFileType, writeToolsConfig } from "./tools";
@@ -21,7 +22,6 @@ import {
TemplateVectorDB,
} from "./types";
import { installTSTemplate } from "./typescript";
import { isHavingUvLockFile, tryUvRun } from "./uv";
const checkForGenerateScript = (
modelConfig: ModelConfig,
@@ -41,11 +41,7 @@ const checkForGenerateScript = (
missingSettings.push("your LLAMA_CLOUD_API_KEY");
}
if (
vectorDb !== undefined &&
vectorDb !== "none" &&
vectorDb !== "llamacloud"
) {
if (vectorDb !== "none" && vectorDb !== "llamacloud") {
missingSettings.push("your Vector DB environment variables");
}
@@ -64,7 +60,7 @@ async function generateContextData(
if (packageManager) {
const runGenerate = `${cyan(
framework === "fastapi"
? "uv run generate"
? "poetry run generate"
: `${packageManager} run generate`,
)}`;
@@ -78,21 +74,15 @@ async function generateContextData(
if (!missingSettings.length) {
// If all the required environment variables are set, run the generate script
if (framework === "fastapi") {
if (isHavingUvLockFile()) {
if (isHavingPoetryLockFile()) {
console.log(`Running ${runGenerate} to generate the context data.`);
const result = tryUvRun("generate");
const result = tryPoetryRun("poetry run generate");
if (!result) {
console.log(`Failed to run ${runGenerate}.`);
process.exit(1);
}
console.log(`Generated context data`);
return;
} else {
console.log(
picocolors.yellow(
`\nWarning: uv.lock not found. Dependency installation might be incomplete. Skipping context generation.\nIf dependencies were installed, try running '${runGenerate}' manually.\n`,
),
);
}
} else {
console.log(`Running ${runGenerate} to generate the context data.`);
@@ -102,14 +92,14 @@ async function generateContextData(
}
const settingsMessage = `After setting ${missingSettings.join(" and ")}, run ${runGenerate} to generate the context data.`;
console.log(picocolors.yellow(`\n${settingsMessage}\n\n`));
console.log(`\n${settingsMessage}\n\n`);
}
}
const downloadFile = async (url: string, destPath: string) => {
const response = await fetch(url);
const fileBuffer = await response.arrayBuffer();
await fsExtra.writeFile(destPath, new Uint8Array(fileBuffer));
await fsExtra.writeFile(destPath, Buffer.from(fileBuffer));
};
const prepareContextData = async (
@@ -176,17 +166,6 @@ export const installTemplate = async (
if (props.framework === "fastapi") {
await installPythonTemplate(props);
} else {
await installTSTemplate(props);
}
// write configurations
if (props.template !== "llamaindexserver") {
await writeToolsConfig(
props.root,
props.tools,
props.framework === "fastapi" ? ConfigFileType.YAML : ConfigFileType.JSON,
);
if (props.vectorDb !== "llamacloud") {
// write loaders configuration (currently Python only)
// not needed for LlamaCloud as it has its own loaders
@@ -196,13 +175,26 @@ export const installTemplate = async (
props.useLlamaParse,
);
}
} else {
await installTSTemplate(props);
}
// write tools configuration
await writeToolsConfig(
props.root,
props.tools,
props.framework === "fastapi" ? ConfigFileType.YAML : ConfigFileType.JSON,
);
if (props.backend) {
// This is a backend, so we need to copy the test data and create the env file.
// Copy the environment file to the target directory.
if (props.template !== "community" && props.template !== "llamapack") {
if (
props.template === "streaming" ||
props.template === "multiagent" ||
props.template === "reflex"
) {
await createBackendEnvFile(props.root, props);
}
@@ -143,6 +143,6 @@ export const installLlamapackProject = async ({
await copyData({ root });
await installLlamapackExample({ root, llamapack });
if (postInstallAction === "runApp" || postInstallAction === "dependencies") {
installPythonDependencies();
installPythonDependencies({ noRoot: true });
}
};
@@ -3,16 +3,15 @@ import path from "path";
import { cyan, red } from "picocolors";
import { parse, stringify } from "smol-toml";
import terminalLink from "terminal-link";
import { isUvAvailable, tryUvSync } from "./uv";
import { assetRelocator, copy } from "./copy";
import { templatesDir } from "./dir";
import { isPoetryAvailable, tryPoetryInstall } from "./poetry";
import { Tool } from "./tools";
import {
InstallTemplateArgs,
ModelConfig,
TemplateDataSource,
TemplateObservability,
TemplateType,
TemplateVectorDB,
} from "./types";
@@ -30,7 +29,6 @@ const getAdditionalDependencies = (
dataSources?: TemplateDataSource[],
tools?: Tool[],
templateType?: TemplateType,
observability?: TemplateObservability,
) => {
const dependencies: Dependency[] = [];
@@ -39,21 +37,21 @@ const getAdditionalDependencies = (
case "mongo": {
dependencies.push({
name: "llama-index-vector-stores-mongodb",
version: ">=0.3.2,<0.4.0",
version: "^0.6.0",
});
break;
}
case "pg": {
dependencies.push({
name: "llama-index-vector-stores-postgres",
version: ">=0.3.2,<0.4.0",
version: "^0.3.2",
});
break;
}
case "pinecone": {
dependencies.push({
name: "llama-index-vector-stores-pinecone",
version: ">=0.4.1,<0.5.0",
version: "^0.4.1",
constraints: {
python: ">=3.11,<3.13",
},
@@ -63,25 +61,25 @@ const getAdditionalDependencies = (
case "milvus": {
dependencies.push({
name: "llama-index-vector-stores-milvus",
version: ">=0.3.0,<0.4.0",
version: "^0.3.0",
});
dependencies.push({
name: "pymilvus",
version: ">=2.4.4,<3.0.0",
version: "2.4.4",
});
break;
}
case "astra": {
dependencies.push({
name: "llama-index-vector-stores-astra-db",
version: ">=0.4.0,<0.5.0",
version: "^0.4.0",
});
break;
}
case "qdrant": {
dependencies.push({
name: "llama-index-vector-stores-qdrant",
version: ">=0.4.0,<0.5.0",
version: "^0.4.0",
constraints: {
python: ">=3.11,<3.13",
},
@@ -91,21 +89,21 @@ const getAdditionalDependencies = (
case "chroma": {
dependencies.push({
name: "llama-index-vector-stores-chroma",
version: ">=0.4.0,<0.5.0",
version: "^0.4.0",
});
break;
}
case "weaviate": {
dependencies.push({
name: "llama-index-vector-stores-weaviate",
version: ">=1.2.3,<2.0.0",
version: "^1.2.3",
});
break;
}
case "llamacloud":
dependencies.push({
name: "llama-index-indices-managed-llama-cloud",
version: ">=0.6.3,<0.7.0",
version: "^0.6.3",
});
break;
}
@@ -118,28 +116,28 @@ const getAdditionalDependencies = (
case "file":
dependencies.push({
name: "docx2txt",
version: ">=0.8,<0.9",
version: "^0.8",
});
break;
case "web":
dependencies.push({
name: "llama-index-readers-web",
version: ">=0.3.0,<0.4.0",
version: "^0.3.0",
});
break;
case "db":
dependencies.push({
name: "llama-index-readers-database",
version: ">=0.3.0,<0.4.0",
version: "^0.3.0",
});
dependencies.push({
name: "pymysql",
version: ">=1.1.0,<2.0.0",
version: "^1.1.0",
extras: ["rsa"],
});
dependencies.push({
name: "psycopg2-binary",
version: ">=2.9.9,<3.0.0",
version: "^2.9.9",
});
break;
}
@@ -158,122 +156,155 @@ const getAdditionalDependencies = (
case "ollama":
dependencies.push({
name: "llama-index-llms-ollama",
version: ">=0.5.0,<0.6.0",
version: "0.3.0",
});
dependencies.push({
name: "llama-index-embeddings-ollama",
version: ">=0.6.0,<0.7.0",
version: "0.3.0",
});
break;
case "openai":
if (templateType !== "multiagent") {
dependencies.push({
name: "llama-index-llms-openai",
version: ">=0.3.2,<0.4.0",
version: "^0.3.2",
});
dependencies.push({
name: "llama-index-embeddings-openai",
version: ">=0.3.1,<0.4.0",
version: "^0.3.1",
});
dependencies.push({
name: "llama-index-agent-openai",
version: ">=0.4.0,<0.5.0",
version: "^0.4.0",
});
}
break;
case "groq":
// Fastembed==0.2.0 does not support python3.13 at the moment
// Fixed the python version less than 3.13
dependencies.push({
name: "python",
version: "^3.11,<3.13",
});
dependencies.push({
name: "llama-index-llms-groq",
version: ">=0.3.0,<0.4.0",
version: "0.2.0",
});
dependencies.push({
name: "llama-index-embeddings-fastembed",
version: ">=0.3.0,<0.4.0",
version: "^0.2.0",
});
break;
case "anthropic":
// Fastembed==0.2.0 does not support python3.13 at the moment
// Fixed the python version less than 3.13
dependencies.push({
name: "python",
version: "^3.11,<3.13",
});
dependencies.push({
name: "llama-index-llms-anthropic",
version: ">=0.6.0,<0.7.0",
version: "0.3.0",
});
dependencies.push({
name: "llama-index-embeddings-fastembed",
version: ">=0.3.0,<0.4.0",
version: "^0.2.0",
});
break;
case "gemini":
dependencies.push({
name: "llama-index-llms-gemini",
version: ">=0.4.0,<0.5.0",
version: "0.3.4",
});
dependencies.push({
name: "llama-index-embeddings-gemini",
version: ">=0.3.0,<0.4.0",
version: "^0.2.0",
});
break;
case "mistral":
dependencies.push({
name: "llama-index-llms-mistralai",
version: ">=0.4.0,<0.5.0",
version: "0.2.1",
});
dependencies.push({
name: "llama-index-embeddings-mistralai",
version: ">=0.3.0,<0.4.0",
version: "0.2.0",
});
break;
case "azure-openai":
dependencies.push({
name: "llama-index-llms-azure-openai",
version: ">=0.3.0,<0.4.0",
version: "0.2.0",
});
dependencies.push({
name: "llama-index-embeddings-azure-openai",
version: ">=0.3.0,<0.4.0",
version: "0.2.4",
});
break;
case "huggingface":
dependencies.push({
name: "llama-index-llms-huggingface",
version: ">=0.5.0,<0.6.0",
version: "^0.3.5",
});
dependencies.push({
name: "llama-index-embeddings-huggingface",
version: ">=0.5.0,<0.6.0",
version: "^0.3.1",
});
dependencies.push({
name: "optimum",
version: ">=1.23.3,<2.0.0",
version: "^1.23.3",
extras: ["onnxruntime"],
});
break;
case "t-systems":
dependencies.push({
name: "llama-index-agent-openai",
version: ">=0.4.0,<0.5.0",
version: "0.3.0",
});
dependencies.push({
name: "llama-index-llms-openai-like",
version: ">=0.3.0,<0.4.0",
version: "0.2.0",
});
break;
}
if (observability && observability !== "none") {
if (observability === "traceloop") {
dependencies.push({
name: "traceloop-sdk",
version: ">=0.15.11,<0.16.0",
});
return dependencies;
};
const mergePoetryDependencies = (
dependencies: Dependency[],
existingDependencies: Record<string, Omit<Dependency, "name"> | string>,
) => {
for (const dependency of dependencies) {
let value = existingDependencies[dependency.name] ?? {};
// default string value is equal to attribute "version"
if (typeof value === "string") {
value = { version: value };
}
if (observability === "llamatrace") {
dependencies.push({
name: "llama-index-callbacks-arize-phoenix",
version: ">=0.3.0,<0.4.0",
});
value.version = dependency.version ?? value.version;
value.extras = dependency.extras ?? value.extras;
// Merge constraints if they exist
if (dependency.constraints) {
value = { ...value, ...dependency.constraints };
}
if (value.version === undefined) {
throw new Error(
`Dependency "${dependency.name}" is missing attribute "version"!`,
);
}
// Serialize as object if there are any additional properties
if (Object.keys(value).length > 1) {
existingDependencies[dependency.name] = value;
} else {
// Otherwise, serialize just the version string
existingDependencies[dependency.name] = value.version;
}
}
return dependencies;
};
const copyRouterCode = async (root: string, tools: Tool[]) => {
@@ -298,100 +329,19 @@ export const addDependencies = async (
// Parse toml file
const file = path.join(projectDir, FILENAME);
const fileContent = await fs.readFile(file, "utf8");
let fileParsed: any;
try {
fileParsed = parse(fileContent);
} catch (parseError) {
console.error(`Error parsing ${FILENAME}:`, parseError);
throw new Error(
`Failed to parse ${FILENAME}. Please ensure it's valid TOML.`,
);
}
const fileParsed = parse(fileContent);
// Ensure [project] and [project.dependencies] exist
if (!fileParsed.project) {
fileParsed.project = {};
}
if (
!fileParsed.project.dependencies ||
!Array.isArray(fileParsed.project.dependencies)
) {
// If dependencies exist but aren't an array, log a warning or error.
// For now, we'll overwrite it, assuming the intent is to use the standard array format.
console.warn(
`[project.dependencies] in ${FILENAME} is not an array. It will be overwritten.`,
);
fileParsed.project.dependencies = [];
}
const existingDependencies: string[] = fileParsed.project.dependencies;
const addedDeps: string[] = [];
const updatedDeps: string[] = [];
// Add or update dependencies
for (const newDep of dependencies) {
let depString = newDep.name;
if (newDep.extras && newDep.extras.length > 0) {
depString += `[${newDep.extras.join(",")}]`;
}
if (newDep.version) {
depString += newDep.version;
}
let found = false;
for (let i = 0; i < existingDependencies.length; i++) {
const existingDepNameMatch =
existingDependencies[i].match(/^([a-zA-Z0-9._-]+)/);
if (
existingDepNameMatch &&
existingDepNameMatch[1].toLowerCase() === depString.toLowerCase()
) {
// Found existing dependency, update it
if (existingDependencies[i] !== depString) {
updatedDeps.push(`${existingDependencies[i]} -> ${depString}`);
existingDependencies[i] = depString;
}
found = true;
break;
}
}
if (!found) {
// Add new dependency
existingDependencies.push(depString);
addedDeps.push(depString);
}
// Handle python version constraints separately (if any)
if (newDep.constraints?.python) {
if (
!fileParsed.project["requires-python"] ||
fileParsed.project["requires-python"] !== newDep.constraints.python
) {
// This simple overwrite might not be ideal; merging constraints is complex.
// For now, let's just set it if the new dependency has one.
console.log(
`Setting requires-python = "${newDep.constraints.python}" from dependency ${newDep.name}`,
);
fileParsed.project["requires-python"] = newDep.constraints.python;
}
}
}
// Modify toml dependencies
const tool = fileParsed.tool as any;
const existingDependencies = tool.poetry.dependencies;
mergePoetryDependencies(dependencies, existingDependencies);
// Write toml file
const newFileContent = stringify(fileParsed);
await fs.writeFile(file, newFileContent);
if (addedDeps.length > 0) {
console.log(`\nAdded dependencies to ${cyan(FILENAME)}:`);
addedDeps.forEach((dep) => console.log(` ${dep}`));
}
if (updatedDeps.length > 0) {
console.log(`\nUpdated dependencies in ${cyan(FILENAME)}:`);
updatedDeps.forEach((dep) => console.log(` ${dep}`));
}
if (addedDeps.length > 0 || updatedDeps.length > 0) {
console.log(""); // Newline for spacing
}
const dependenciesString = dependencies.map((d) => d.name).join(", ");
console.log(`\nAdded ${dependenciesString} to ${cyan(FILENAME)}\n`);
} catch (error) {
console.log(
`Error while updating dependencies for Poetry project file ${FILENAME}\n`,
@@ -400,16 +350,18 @@ export const addDependencies = async (
}
};
export const installPythonDependencies = () => {
if (isUvAvailable()) {
export const installPythonDependencies = (
{ noRoot }: { noRoot: boolean } = { noRoot: false },
) => {
if (isPoetryAvailable()) {
console.log(
`Installing Python dependencies using uv. This may take a while...`,
`Installing python dependencies using poetry. This may take a while...`,
);
const installSuccessful = tryUvSync();
const installSuccessful = tryPoetryInstall(noRoot);
if (!installSuccessful) {
console.error(
red(
"Installing dependencies using uv failed. Please check the error log above and ensure uv is installed correctly.",
"Installing dependencies using poetry failed. Please check error log above and try running create-llama again.",
),
);
process.exit(1);
@@ -417,34 +369,57 @@ export const installPythonDependencies = () => {
} else {
console.error(
red(
`uv is not available in the current environment. Please check ${terminalLink(
"uv Installation",
`https://github.com/astral-sh/uv#installation`,
)} to install uv first, then run create-llama again.`,
`Poetry is not available in the current environment. Please check ${terminalLink(
"Poetry Installation",
`https://python-poetry.org/docs/#installation`,
)} to install poetry first, then run create-llama again.`,
),
);
process.exit(1);
}
};
const installLegacyPythonTemplate = async ({
export const installPythonTemplate = async ({
appName,
root,
template,
framework,
vectorDb,
postInstallAction,
modelConfig,
dataSources,
tools,
useLlamaParse,
useCase,
observability,
}: Pick<
InstallTemplateArgs,
| "appName"
| "root"
| "template"
| "framework"
| "vectorDb"
| "postInstallAction"
| "modelConfig"
| "dataSources"
| "tools"
| "useLlamaParse"
| "useCase"
| "observability"
>) => {
console.log("\nInitializing Python project with template:", template, "\n");
let templatePath;
if (template === "reflex") {
templatePath = path.join(templatesDir, "types", "reflex");
} else {
templatePath = path.join(templatesDir, "types", "streaming", framework);
}
await copy("**", root, {
parents: true,
cwd: templatePath,
rename: assetRelocator,
});
const compPath = path.join(templatesDir, "components");
const enginePath = path.join(root, "app", "engine");
@@ -534,7 +509,34 @@ const installLegacyPythonTemplate = async ({
}
}
console.log("Adding additional dependencies");
const addOnDependencies = getAdditionalDependencies(
modelConfig,
vectorDb,
dataSources,
tools,
template,
);
if (observability && observability !== "none") {
if (observability === "traceloop") {
addOnDependencies.push({
name: "traceloop-sdk",
version: "^0.15.11",
});
}
if (observability === "llamatrace") {
addOnDependencies.push({
name: "llama-index-callbacks-arize-phoenix",
version: "^0.3.0",
constraints: {
python: ">=3.11,<3.13",
},
});
}
const templateObservabilityPath = path.join(
templatesDir,
"components",
@@ -546,133 +548,6 @@ const installLegacyPythonTemplate = async ({
cwd: templateObservabilityPath,
});
}
};
const installLlamaIndexServerTemplate = async ({
root,
useCase,
useLlamaParse,
}: Pick<InstallTemplateArgs, "root" | "useCase" | "useLlamaParse">) => {
if (!useCase) {
console.log(
red(
`There is no use case selected. Please pick a use case to use via --use-case flag.`,
),
);
process.exit(1);
}
await copy("workflow.py", path.join(root, "app"), {
parents: true,
cwd: path.join(templatesDir, "components", "workflows", "python", useCase),
});
// Copy custom UI component code
await copy(`*`, path.join(root, "components"), {
parents: true,
cwd: path.join(templatesDir, "components", "ui", "workflows", useCase),
});
if (useLlamaParse) {
await copy("index.py", path.join(root, "app"), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"vectordbs",
"llamaindexserver",
"llamacloud",
"python",
),
});
// TODO: Consider moving generate.py to app folder.
await copy("generate.py", path.join(root), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"vectordbs",
"llamaindexserver",
"llamacloud",
"python",
),
});
}
// Copy README.md
await copy("README-template.md", path.join(root), {
parents: true,
cwd: path.join(templatesDir, "components", "workflows", "python", useCase),
rename: assetRelocator,
});
};
export const installPythonTemplate = async ({
appName,
root,
template,
framework,
vectorDb,
postInstallAction,
modelConfig,
dataSources,
tools,
useLlamaParse,
useCase,
observability,
}: Pick<
InstallTemplateArgs,
| "appName"
| "root"
| "template"
| "framework"
| "vectorDb"
| "postInstallAction"
| "modelConfig"
| "dataSources"
| "tools"
| "useLlamaParse"
| "useCase"
| "observability"
>) => {
console.log("\nInitializing Python project with template:", template, "\n");
let templatePath;
if (template === "reflex") {
templatePath = path.join(templatesDir, "types", "reflex");
} else {
templatePath = path.join(templatesDir, "types", template, framework);
}
await copy("**", root, {
parents: true,
cwd: templatePath,
rename: assetRelocator,
});
if (template === "llamaindexserver") {
await installLlamaIndexServerTemplate({
root,
useCase,
useLlamaParse,
});
} else {
await installLegacyPythonTemplate({
root,
template,
vectorDb,
dataSources,
tools,
useCase,
observability,
});
}
console.log("Adding additional dependencies");
const addOnDependencies = getAdditionalDependencies(
modelConfig,
vectorDb,
dataSources,
tools,
template,
);
await addDependencies(root, addOnDependencies);
@@ -34,24 +34,14 @@ export function runReflexApp(appPath: string, port: number) {
"--frontend-port",
port.toString(),
];
return createProcess("uv", commandArgs, {
return createProcess("poetry", commandArgs, {
stdio: "inherit",
cwd: appPath,
});
}
export function runFastAPIApp(
appPath: string,
port: number,
template: TemplateType,
) {
let commandArgs: string[];
if (template === "streaming") {
commandArgs = ["run", "dev"];
} else {
commandArgs = ["run", "fastapi", "dev", "--port", `${port}`];
}
return createProcess("uv", commandArgs, {
export function runFastAPIApp(appPath: string, port: number) {
return createProcess("poetry", ["run", "dev"], {
stdio: "inherit",
cwd: appPath,
env: { ...process.env, APP_PORT: `${port}` },
@@ -83,7 +73,7 @@ export async function runApp(
: framework === "fastapi"
? runFastAPIApp
: runTSApp;
await appRunner(appPath, port || defaultPort, template);
await appRunner(appPath, port || defaultPort);
} catch (error) {
console.error("Failed to run app:", error);
throw error;
@@ -41,7 +41,7 @@ export const supportedTools: Tool[] = [
dependencies: [
{
name: "llama-index-tools-google",
version: ">=0.3.0,<0.4.0",
version: "^0.3.0",
},
],
supportedFrameworks: ["fastapi"],
@@ -62,7 +62,7 @@ export const supportedTools: Tool[] = [
dependencies: [
{
name: "duckduckgo-search",
version: ">=6.3.5,<7.0.0",
version: "^6.3.5",
},
],
supportedFrameworks: ["fastapi"], // TODO: Re-enable this tool once the duck-duck-scrape TypeScript library works again
@@ -82,7 +82,7 @@ For better results, you can specify the region parameter to get results from a s
dependencies: [
{
name: "llama-index-tools-wikipedia",
version: ">=0.3.0,<0.4.0",
version: "^0.3.0",
},
],
supportedFrameworks: ["fastapi", "express", "nextjs"],
@@ -102,11 +102,11 @@ For better results, you can specify the region parameter to get results from a s
dependencies: [
{
name: "xhtml2pdf",
version: ">=0.2.14,<0.3.0",
version: "^0.2.14",
},
{
name: "markdown",
version: ">=3.7.0,<4.0.0",
version: "^3.7",
},
],
type: ToolType.LOCAL,
@@ -124,7 +124,7 @@ For better results, you can specify the region parameter to get results from a s
dependencies: [
{
name: "e2b_code_interpreter",
version: ">=1.1.1,<1.2.0",
version: "1.0.3",
},
],
supportedFrameworks: ["fastapi", "express", "nextjs"],
@@ -155,7 +155,7 @@ For better results, you can specify the region parameter to get results from a s
dependencies: [
{
name: "e2b_code_interpreter",
version: ">=1.1.1,<1.2.0",
version: "1.0.3",
},
],
supportedFrameworks: ["fastapi", "express", "nextjs"],
@@ -184,7 +184,7 @@ For better results, you can specify the region parameter to get results from a s
},
{
name: "jsonschema",
version: ">=4.22.0,<5.0.0",
version: "^4.22.0",
},
{
name: "llama-index-tools-requests",
@@ -247,11 +247,11 @@ For better results, you can specify the region parameter to get results from a s
dependencies: [
{
name: "pandas",
version: ">=2.2.3,<3.0.0",
version: "^2.2.3",
},
{
name: "tabulate",
version: ">=0.9.0,<1.0.0",
version: "^0.9.0",
},
],
},
@@ -24,8 +24,7 @@ export type TemplateType =
| "community"
| "llamapack"
| "multiagent"
| "reflex"
| "llamaindexserver";
| "reflex";
export type TemplateFramework = "nextjs" | "express" | "fastapi";
export type TemplateUI = "html" | "shadcn";
export type TemplateVectorDB =
@@ -56,8 +55,7 @@ export type TemplateUseCase =
| "deep_research"
| "form_filling"
| "extractor"
| "contract_review"
| "agentic_rag";
| "contract_review";
// Config for both file and folder
export type FileSourceConfig =
| {
@@ -8,104 +8,42 @@ import { templatesDir } from "./dir";
import { PackageManager } from "./get-pkg-manager";
import { InstallTemplateArgs, ModelProvider, TemplateVectorDB } from "./types";
const installLlamaIndexServerTemplate = async ({
root,
useCase,
vectorDb,
}: Pick<InstallTemplateArgs, "root" | "useCase" | "vectorDb">) => {
if (!useCase) {
console.log(
red(
`There is no use case selected. Please pick a use case to use via --use-case flag.`,
),
);
process.exit(1);
}
if (!vectorDb) {
console.log(
red(
`There is no vector db selected. Please pick a vector db to use via --vector-db flag.`,
),
);
process.exit(1);
}
await copy("workflow.ts", path.join(root, "src", "app"), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"workflows",
"typescript",
useCase,
),
});
// copy workflow UI components to output/components folder
await copy("*", path.join(root, "components"), {
parents: true,
cwd: path.join(templatesDir, "components", "ui", "workflows", useCase),
});
if (vectorDb === "llamacloud") {
await copy("generate.ts", path.join(root, "src"), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"vectordbs",
"llamaindexserver",
"llamacloud",
"typescript",
),
});
await copy("index.ts", path.join(root, "src", "app"), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"vectordbs",
"llamaindexserver",
"llamacloud",
"typescript",
),
rename: () => "data.ts",
});
}
// Copy README.md
await copy("README-template.md", path.join(root), {
parents: true,
cwd: path.join(
templatesDir,
"components",
"workflows",
"typescript",
useCase,
),
rename: assetRelocator,
});
};
const installLegacyTSTemplate = async ({
/**
* Install a LlamaIndex internal template to a given `root` directory.
*/
export const installTSTemplate = async ({
appName,
root,
packageManager,
isOnline,
template,
backend,
framework,
ui,
vectorDb,
postInstallAction,
backend,
observability,
tools,
dataSources,
useLlamaParse,
useCase,
modelConfig,
relativeEngineDestPath,
}: InstallTemplateArgs & {
backend: boolean;
relativeEngineDestPath: string;
}) => {
}: InstallTemplateArgs & { backend: boolean }) => {
console.log(bold(`Using ${packageManager}.`));
/**
* Copy the template files to the target directory.
*/
console.log("\nInitializing project with template:", template, "\n");
const templatePath = path.join(templatesDir, "types", "streaming", framework);
const copySource = ["**"];
await copy(copySource, root, {
parents: true,
cwd: templatePath,
rename: assetRelocator,
});
/**
* If next.js is used, update its configuration if necessary
*/
@@ -160,6 +98,10 @@ const installLegacyTSTemplate = async ({
}
const compPath = path.join(templatesDir, "components");
const relativeEngineDestPath =
framework === "nextjs"
? path.join("app", "api", "chat")
: path.join("src", "controllers");
const enginePath = path.join(root, relativeEngineDestPath, "engine");
// copy llamaindex code for TS templates
@@ -294,75 +236,6 @@ const installLegacyTSTemplate = async ({
await fs.rm(path.join(root, "app", "api"), { recursive: true });
await fs.rm(path.join(root, "config"), { recursive: true, force: true });
}
};
/**
* Install a LlamaIndex internal template to a given `root` directory.
*/
export const installTSTemplate = async ({
appName,
root,
packageManager,
isOnline,
template,
framework,
ui,
vectorDb,
postInstallAction,
backend,
observability,
tools,
dataSources,
useLlamaParse,
useCase,
modelConfig,
}: InstallTemplateArgs & { backend: boolean }) => {
console.log(bold(`Using ${packageManager}.`));
/**
* Copy the template files to the target directory.
*/
console.log("\nInitializing project with template:", template, "\n");
const templatePath = path.join(templatesDir, "types", template, framework);
const copySource = ["**"];
await copy(copySource, root, {
parents: true,
cwd: templatePath,
rename: assetRelocator,
});
const relativeEngineDestPath =
framework === "nextjs"
? path.join("app", "api", "chat")
: path.join("src", "controllers");
if (template === "llamaindexserver") {
await installLlamaIndexServerTemplate({
root,
useCase,
vectorDb,
});
} else {
await installLegacyTSTemplate({
appName,
root,
packageManager,
isOnline,
template,
backend,
framework,
ui,
vectorDb,
observability,
tools,
dataSources,
useLlamaParse,
useCase,
modelConfig,
relativeEngineDestPath,
});
}
const packageJson = await updatePackageJson({
root,
@@ -375,7 +248,6 @@ export const installTSTemplate = async ({
vectorDb,
backend,
modelConfig,
template,
});
if (
@@ -390,27 +262,27 @@ const providerDependencies: {
[key in ModelProvider]?: Record<string, string>;
} = {
openai: {
"@llamaindex/openai": "^0.2.0",
"@llamaindex/openai": "^0.1.52",
},
gemini: {
"@llamaindex/google": "^0.2.0",
"@llamaindex/google": "^0.0.7",
},
ollama: {
"@llamaindex/ollama": "^0.1.0",
"@llamaindex/ollama": "^0.0.40",
},
mistral: {
"@llamaindex/mistral": "^0.2.0",
"@llamaindex/mistral": "^0.0.5",
},
"azure-openai": {
"@llamaindex/openai": "^0.2.0",
"@llamaindex/openai": "^0.1.52",
},
groq: {
"@llamaindex/groq": "^0.0.61",
"@llamaindex/huggingface": "^0.1.0", // groq uses huggingface as default embedding model
"@llamaindex/groq": "^0.0.51",
"@llamaindex/huggingface": "^0.0.36", // groq uses huggingface as default embedding model
},
anthropic: {
"@llamaindex/anthropic": "^0.3.0",
"@llamaindex/huggingface": "^0.1.0", // anthropic uses huggingface as default embedding model
"@llamaindex/anthropic": "^0.1.0",
"@llamaindex/huggingface": "^0.0.36", // anthropic uses huggingface as default embedding model
},
};
@@ -459,7 +331,6 @@ async function updatePackageJson({
vectorDb,
backend,
modelConfig,
template,
}: Pick<
InstallTemplateArgs,
| "root"
@@ -470,7 +341,6 @@ async function updatePackageJson({
| "observability"
| "vectorDb"
| "modelConfig"
| "template"
> & {
relativeEngineDestPath: string;
backend: boolean;
@@ -482,7 +352,7 @@ async function updatePackageJson({
packageJson.name = appName;
packageJson.version = "0.1.0";
if (relativeEngineDestPath && template !== "llamaindexserver") {
if (relativeEngineDestPath) {
// TODO: move script to {root}/scripts for all frameworks
// add generate script if using context engine
packageJson.scripts = {
@@ -6,7 +6,7 @@ LlamaIndexServer is a FastAPI-based application that allows you to quickly launc
- Serving a workflow as a chatbot
- Built on FastAPI for high performance and easy API development
- Optional built-in chat UI with extendable UI components
- Optional built-in chat UI
- Prebuilt development code
## Installation
@@ -43,10 +43,8 @@ def create_workflow() -> Workflow:
app = LlamaIndexServer(
workflow_factory=create_workflow, # Supports Workflow or AgentWorkflow
env="dev", # Enable development mode
ui_config={ # Configure the chat UI, optional
"app_title": "Weather Bot",
"starter_questions": ["What is the weather in LA?", "Will it rain in SF?"],
},
include_ui=True, # Include chat UI
starter_questions=["What can you do?", "How do I use this?"],
verbose=True
)
```
@@ -76,16 +74,12 @@ The LlamaIndexServer accepts the following configuration parameters:
- `logger`: Optional logger instance (defaults to uvicorn logger)
- `use_default_routers`: Whether to include default routers (chat, static file serving)
- `env`: Environment setting ('dev' enables CORS and UI by default)
- `ui_config`: UI configuration as a dictionary or UIConfig object with options:
- `enabled`: Whether to enable the chat UI (default: True)
- `app_title`: The title of the chat application (default: "LlamaIndex Server")
- `starter_questions`: List of starter questions for the chat UI (default: None)
- `ui_path`: Path for downloaded UI static files (default: ".ui")
- `component_dir`: The directory for custom UI components rendering events emitted by the workflow. The default is None, which does not render custom UI components.
- `llamacloud_index_selector`: Whether to show the LlamaCloud index selector in the chat UI (default: False). Requires `LLAMA_CLOUD_API_KEY` to be set.
- `include_ui`: Whether to include the chat UI
- `starter_questions`: List of starter questions for the chat UI
- `verbose`: Enable verbose logging
- `api_prefix`: API route prefix (default: "/api")
- `server_url`: The deployment URL of the server (default is None)
- `ui_path`: Path for downloaded UI static files (default: ".ui")
## Default Routers and Features
@@ -107,11 +101,6 @@ When enabled, the server provides a chat interface at the root path (`/`) with:
- Real-time chat interface
- API endpoint integration
### Custom UI Components
You can add custom UI components for your workflow by providing `component_dir` config and adding custom .jsx or .tsx files to the directory.
See [Custom UI Components](https://github.com/run-llama/create-llama/blob/main/llama-index-server/docs/custom_ui_component.md) for more details.
## Development Mode
In development mode (`env="dev"`), the server:
@@ -0,0 +1,3 @@
from .server import LlamaIndexServer
__all__ = ["LlamaIndexServer"]
@@ -134,20 +134,3 @@ class SourceNodes(BaseModel):
cls, source_nodes: List[NodeWithScore]
) -> List["SourceNodes"]:
return [cls.from_source_node(node) for node in source_nodes]
class ComponentDefinition(BaseModel):
type: str
code: str
filename: str
class UIEvent(Event):
type: str
data: BaseModel
def to_response(self) -> dict:
return {
"type": self.type,
"data": self.data.model_dump(),
}
@@ -6,7 +6,6 @@ from typing import AsyncGenerator, Callable, Union
from fastapi import APIRouter, BackgroundTasks, HTTPException
from fastapi.responses import StreamingResponse
from llama_index.core.agent.workflow.workflow_events import AgentStream
from llama_index.core.workflow import StopEvent, Workflow
from llama_index.server.api.callbacks import (
@@ -100,10 +99,7 @@ async def _stream_content(
event: Union[AgentStream, StopEvent],
) -> AsyncGenerator[str, None]:
if isinstance(event, AgentStream):
# Normally, if the stream is a tool call, the delta is always empty
# so it's not a text stream.
if len(event.tool_calls) == 0:
yield event.delta
yield event.delta
elif isinstance(event, StopEvent):
if isinstance(event.result, str):
yield event.result
@@ -5,7 +5,7 @@ from typing import Optional
import requests
CHAT_UI_VERSION = "0.1.5"
CHAT_UI_VERSION = "0.0.6"
def download_chat_ui(
@@ -1,58 +1,23 @@
import json
import logging
import os
from typing import Any, Callable, Optional, Union
from typing import Any, Callable, Optional
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from llama_index.core.workflow import Workflow
from llama_index.server.api.routers import chat_router, custom_components_router
from llama_index.server.api.routers.chat import chat_router
from llama_index.server.chat_ui import download_chat_ui
from llama_index.server.settings import server_settings
from pydantic import BaseModel, Field
class UIConfig(BaseModel):
enabled: bool = Field(default=True, description="Whether to enable the chat UI")
app_title: str = Field(
default="LlamaIndex Server", description="The title of the chat UI"
)
starter_questions: Optional[list[str]] = Field(
default=None, description="The starter questions for the chat UI"
)
llamacloud_index_selector: bool = Field(
default=False,
description="Whether to show the LlamaCloud index selector in the chat UI (need to set the LLAMA_CLOUD_API_KEY environment variable)",
)
ui_path: str = Field(
default=".ui", description="The path that stores static files for the chat UI"
)
component_dir: Optional[str] = Field(
default=None, description="The directory to custom UI components code"
)
def get_config_content(self) -> str:
return json.dumps(
{
"CHAT_API": f"{server_settings.api_url}/chat",
"STARTER_QUESTIONS": self.starter_questions or [],
"LLAMA_CLOUD_API": f"{server_settings.api_url}/chat/config/llamacloud"
if self.llamacloud_index_selector and os.getenv("LLAMA_CLOUD_API_KEY")
else None,
"APP_TITLE": self.app_title,
"COMPONENTS_API": f"{server_settings.api_url}/components"
if self.component_dir
else None,
},
indent=2,
)
class LlamaIndexServer(FastAPI):
workflow_factory: Callable[..., Workflow]
include_ui: Optional[bool]
starter_questions: Optional[list[str]]
verbose: bool = False
ui_config: UIConfig
ui_path: str = ".ui"
def __init__(
self,
@@ -60,7 +25,8 @@ class LlamaIndexServer(FastAPI):
logger: Optional[logging.Logger] = None,
use_default_routers: Optional[bool] = True,
env: Optional[str] = None,
ui_config: Optional[Union[UIConfig, dict]] = None,
include_ui: Optional[bool] = None,
starter_questions: Optional[list[str]] = None,
server_url: Optional[str] = None,
api_prefix: Optional[str] = None,
verbose: bool = False,
@@ -75,7 +41,8 @@ class LlamaIndexServer(FastAPI):
logger: The logger to use.
use_default_routers: Whether to use the default routers (chat, mount `data` and `output` directories).
env: The environment to run the server in.
ui_config: The configuration for the chat UI.
include_ui: Whether to show an chat UI in the root path.
starter_questions: A list of starter questions to display in the chat UI.
server_url: The URL of the server.
api_prefix: The prefix for the API endpoints.
verbose: Whether to show verbose logs.
@@ -85,13 +52,9 @@ class LlamaIndexServer(FastAPI):
self.workflow_factory = workflow_factory
self.logger = logger or logging.getLogger("uvicorn")
self.verbose = verbose
self.include_ui = include_ui # Store the explicitly passed value first
self.starter_questions = starter_questions
self.use_default_routers = use_default_routers or True
if ui_config is None:
self.ui_config = UIConfig()
elif isinstance(ui_config, dict):
self.ui_config = UIConfig(**ui_config)
else:
self.ui_config = ui_config
# Update the settings
if server_url:
@@ -104,15 +67,27 @@ class LlamaIndexServer(FastAPI):
if str(env).lower() == "dev":
self.allow_cors("*")
if self.ui_config.enabled is None:
self.ui_config.enabled = True
if self.include_ui is None:
self.include_ui = True
if self.include_ui is None:
self.include_ui = False
if self.ui_config.enabled is None:
self.ui_config.enabled = False
if self.ui_config.enabled:
if self.include_ui:
self.mount_ui()
@property
def _ui_config(self) -> dict:
config = {
"CHAT_API": f"{server_settings.api_url}/chat",
"STARTER_QUESTIONS": self.starter_questions,
}
is_llamacloud_configured = os.getenv("LLAMA_CLOUD_API_KEY") is not None
if is_llamacloud_configured:
config["LLAMA_CLOUD_API"] = (
f"{server_settings.api_url}/chat/config/llamacloud"
)
return config
# Default routers
def add_default_routers(self) -> None:
self.add_chat_router()
@@ -131,39 +106,18 @@ class LlamaIndexServer(FastAPI):
prefix=server_settings.api_prefix,
)
def add_components_router(self) -> None:
"""
Add the UI router.
"""
if self.ui_config.component_dir is None:
raise ValueError("component_dir must be specified to add components router")
self.include_router(
custom_components_router(self.ui_config.component_dir, self.logger),
prefix=server_settings.api_prefix,
)
def mount_ui(self) -> None:
"""
Mount the UI.
"""
# Check if the static folder exists
if self.ui_config.enabled:
# Component dir
if self.ui_config.component_dir:
if not os.path.exists(self.ui_config.component_dir):
os.makedirs(self.ui_config.component_dir)
self.add_components_router()
# UI static files
if not os.path.exists(self.ui_config.ui_path):
os.makedirs(self.ui_config.ui_path)
if self.include_ui:
if not os.path.exists(self.ui_path):
self.logger.warning(
f"UI files not found, downloading UI to {self.ui_config.ui_path}"
f"UI files not found, downloading UI to {self.ui_path}"
)
download_chat_ui(logger=self.logger, target_path=self.ui_config.ui_path)
self._mount_static_files(
directory=self.ui_config.ui_path, path="/", html=True
)
download_chat_ui(logger=self.logger, target_path=self.ui_path)
self._mount_static_files(directory=self.ui_path, path="/", html=True)
self._override_ui_config()
def _override_ui_config(self) -> None:
@@ -171,12 +125,12 @@ class LlamaIndexServer(FastAPI):
Override the UI config by writing a complete configuration file.
"""
try:
config_path = os.path.join(self.ui_config.ui_path, "config.js")
config_path = os.path.join(self.ui_path, "config.js")
if not os.path.exists(config_path):
self.logger.error("Config file not found")
return
config_content = (
f"window.LLAMAINDEX = {self.ui_config.get_config_content()};"
f"window.LLAMAINDEX = {json.dumps(self._ui_config, indent=2)};"
)
with open(config_path, "w") as f:
f.write(config_content)
@@ -149,8 +149,7 @@ def _create_index(
"type": "OPENAI_EMBEDDING",
"component": {
"api_key": os.getenv("OPENAI_API_KEY"), # editable
"model_name": Settings.embed_model.model_name
or "text-embedding-3-small",
"model_name": os.getenv("EMBEDDING_MODEL"),
},
},
"transform_config": {
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,7 @@ license = "MIT"
name = "llama-index-server"
packages = [{include = "llama_index/"}]
readme = "README.md"
version = "0.1.14"
version = "0.1.6"
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
@@ -34,7 +34,7 @@ fastapi = {extras = ["standard"], version = "^0.115.11"}
cachetools = "^5.5.2"
requests = "^2.32.3"
pydantic-settings = "^2.8.1"
llama-index-core = "^0.12.28"
llama-index-core = "0.12.25"
llama-index-readers-file = "^0.4.6"
llama-index-indices-managed-llama-cloud = "0.6.3"
@@ -62,4 +62,3 @@ types-setuptools = "67.1.0.0"
xhtml2pdf = "^0.2.17"
pytest-cov = "^6.0.0"
llama-cloud = "^0.1.17"
@@ -0,0 +1,106 @@
import pytest
from httpx import ASGITransport, AsyncClient
from llama_index.core.agent.workflow import AgentWorkflow
from llama_index.core.llms import MockLLM
from llama_index.server import LlamaIndexServer
def fetch_weather(city: str) -> str:
"""Fetch the weather for a given city."""
return f"The weather in {city} is sunny."
def _agent_workflow() -> AgentWorkflow:
# Use MockLLM instead of default OpenAI
mock_llm = MockLLM()
return AgentWorkflow.from_tools_or_functions(
tools_or_functions=[fetch_weather],
verbose=True,
llm=mock_llm,
)
@pytest.fixture()
def server() -> LlamaIndexServer:
"""Fixture to create a LlamaIndexServer instance."""
return LlamaIndexServer(
workflow_factory=_agent_workflow,
verbose=True,
use_default_routers=True,
mount_ui=False,
env="dev",
)
@pytest.mark.asyncio()
async def test_server_has_chat_route(server: LlamaIndexServer) -> None:
"""Test that the server has the chat API route."""
chat_route_exists = any(route.path == "/api/chat" for route in server.routes)
assert chat_route_exists, "Chat API route not found in server routes"
@pytest.mark.asyncio()
async def test_server_swagger_docs(server: LlamaIndexServer) -> None:
"""Test that the server serves Swagger UI docs."""
async with AsyncClient(
transport=ASGITransport(app=server), base_url="http://test"
) as ac:
response = await ac.get("/docs")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
assert "Swagger UI" in response.text
@pytest.mark.asyncio()
async def test_ui_is_downloaded(server: LlamaIndexServer) -> None:
"""
Test if the UI is downloaded and mounted correctly.
"""
import os
import shutil
# Clean up any existing static directory first
if os.path.exists(".ui"):
shutil.rmtree(".ui")
# Create a new server with UI enabled
ui_server = LlamaIndexServer(
workflow_factory=_agent_workflow,
verbose=True,
use_default_routers=True,
env="dev",
include_ui=True,
)
# Verify that static directory was created with index.html
assert os.path.exists("./.ui"), "Static directory was not created"
assert os.path.isdir("./.ui"), "Static path is not a directory"
assert os.path.exists("./.ui/index.html"), "index.html was not downloaded"
# Check if the UI is mounted and accessible
async with AsyncClient(
transport=ASGITransport(app=ui_server), base_url="http://test"
) as ac:
response = await ac.get("/")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
# Clean up after test
shutil.rmtree("./.ui")
@pytest.mark.asyncio()
async def test_ui_is_accessible(server: LlamaIndexServer) -> None:
"""
Test if the UI is accessible.
"""
# Manually trigger UI mounting
server.mount_ui()
async with AsyncClient(
transport=ASGITransport(app=server), base_url="http://test"
) as ac:
response = await ac.get("/")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
+84 -37
View File
@@ -1,39 +1,86 @@
{
"name": "create-llama-monorepo",
"version": "1.0.0",
"private": true,
"description": "Monorepo for create-llama",
"keywords": [
"rag",
"llamaindex"
],
"repository": {
"type": "git",
"url": "https://github.com/run-llama/create-llama"
},
"license": "MIT",
"workspaces": [
"packages/*"
],
"scripts": {
"prepare": "husky",
"new-snapshot": "pnpm -r build && changeset version --snapshot",
"new-version": "pnpm -r build && changeset version",
"release": "pnpm -r build && changeset publish",
"release-snapshot": "pnpm -r build && changeset publish --tag snapshot",
"build": "pnpm -r build",
"e2e": "pnpm -r e2e",
"dev": "pnpm -r dev",
"format": "pnpm -r format",
"format:write": "pnpm -r format:write",
"lint": "pnpm -r lint"
},
"devDependencies": {
"@changesets/cli": "^2.27.1",
"husky": "^9.0.10"
},
"packageManager": "pnpm@9.0.5",
"engines": {
"node": ">=16.14.0"
}
"name": "create-llama",
"version": "0.4.0",
"description": "Create LlamaIndex-powered apps with one command",
"keywords": [
"rag",
"llamaindex",
"next.js"
],
"repository": {
"type": "git",
"url": "https://github.com/run-llama/create-llama",
"directory": "packages/create-llama"
},
"license": "MIT",
"bin": {
"create-llama": "./dist/index.js"
},
"files": [
"dist"
],
"scripts": {
"build": "bash ./scripts/build.sh",
"build:ncc": "pnpm run clean && ncc build ./index.ts -o ./dist/ --minify --no-cache --no-source-map-register",
"clean": "rimraf --glob ./dist ./templates/**/__pycache__ ./templates/**/node_modules ./templates/**/poetry.lock",
"dev": "ncc build ./index.ts -w -o dist/",
"e2e": "playwright test",
"e2e:python": "playwright test e2e/shared e2e/python",
"e2e:typescript": "playwright test e2e/shared e2e/typescript",
"format": "prettier --ignore-unknown --cache --check .",
"format:write": "prettier --ignore-unknown --write .",
"lint": "eslint . --ignore-pattern dist --ignore-pattern e2e/cache",
"new-snapshot": "pnpm run build && changeset version --snapshot",
"new-version": "pnpm run build && changeset version",
"pack-install": "bash ./scripts/pack.sh",
"prepare": "husky",
"release": "pnpm run build && changeset publish",
"release-snapshot": "pnpm run build && changeset publish --tag snapshot"
},
"dependencies": {
"@types/async-retry": "1.4.2",
"@types/ci-info": "2.0.0",
"@types/cross-spawn": "6.0.0",
"@types/fs-extra": "11.0.4",
"@types/node": "^20.11.7",
"@types/prompts": "2.4.2",
"@types/tar": "6.1.5",
"@types/validate-npm-package-name": "3.0.0",
"async-retry": "1.3.1",
"async-sema": "3.0.1",
"ci-info": "github:watson/ci-info#f43f6a1cefff47fb361c88cf4b943fdbcaafe540",
"commander": "12.1.0",
"cross-spawn": "7.0.3",
"fast-glob": "3.3.1",
"fs-extra": "11.2.0",
"global-agent": "^3.0.0",
"got": "10.7.0",
"ollama": "^0.5.0",
"ora": "^8.0.1",
"picocolors": "1.0.0",
"prompts": "2.4.2",
"smol-toml": "^1.1.4",
"tar": "6.1.15",
"terminal-link": "^3.0.0",
"update-check": "1.5.4",
"validate-npm-package-name": "3.0.0",
"yaml": "2.4.1"
},
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@playwright/test": "^1.41.1",
"@vercel/ncc": "0.38.1",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.10.0",
"husky": "^9.0.10",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"rimraf": "^5.0.5",
"typescript": "^5.3.3",
"wait-port": "^1.1.0"
},
"packageManager": "pnpm@9.0.5",
"engines": {
"node": ">=16.14.0"
}
}
-65
View File
@@ -1,65 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules
.pnp
.pnpm-store
.pnp.js
# testing
coverage
.coverage
# next.js
.next/
out/
build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# build
dist/
lib/
# e2e
.cache
test-results/
playwright-report/
blob-report/
playwright/.cache/
.tsbuildinfo
e2e/cache
# intellij
**/.idea
# Python
.mypy_cache/
venv/
.venv/
dist/
.__pycache__
__pycache__
.python-version
.ui
# build artifacts
create-llama-*.tgz
# copied from root
README.md
LICENSE.md
-42
View File
@@ -1,42 +0,0 @@
// Migrate poetry to uv
import { execSync } from "child_process";
import fs from "fs";
import { red } from "picocolors";
export function isUvAvailable(): boolean {
try {
execSync("uv --version", { stdio: "ignore" });
return true;
} catch (_) {}
return false;
}
export function tryUvSync(): boolean {
try {
console.log("Syncing environment with pyproject.toml...");
execSync(`uv sync`, {
stdio: "inherit",
});
return true;
} catch (_) {}
return false;
}
export function tryUvRun(command: string): boolean {
try {
// Use uv run <command>
execSync(`uv run ${command}`, { stdio: "inherit" });
return true;
} catch (error) {
console.error(red(`Failed to run ${command}. Error: ${error}`));
return false;
}
}
export function isHavingUvLockFile(): boolean {
try {
// Check if uv.lock exists in the current directory
return fs.existsSync("uv.lock");
} catch (_) {}
return false;
}
-83
View File
@@ -1,83 +0,0 @@
{
"name": "create-llama",
"version": "0.5.11",
"description": "Create LlamaIndex-powered apps with one command",
"keywords": [
"rag",
"llamaindex",
"next.js"
],
"repository": {
"type": "git",
"url": "https://github.com/run-llama/create-llama",
"directory": "packages/create-llama"
},
"license": "MIT",
"bin": {
"create-llama": "./dist/index.js"
},
"files": [
"dist",
"README.md",
"LICENSE.md"
],
"scripts": {
"copy": "cp -r ../../README.md ../../LICENSE.md .",
"build": "bash ./scripts/build.sh",
"build:ncc": "pnpm run clean && ncc build ./index.ts -o ./dist/ --minify --no-cache --no-source-map-register",
"postbuild": "pnpm run copy",
"clean": "rimraf --glob ./dist ./templates/**/__pycache__ ./templates/**/node_modules ./templates/**/poetry.lock",
"dev": "ncc build ./index.ts -w -o dist/",
"e2e": "playwright test",
"e2e:python": "playwright test e2e/shared e2e/python",
"e2e:typescript": "playwright test e2e/shared e2e/typescript",
"format": "prettier --ignore-unknown --cache --check .",
"format:write": "prettier --ignore-unknown --write .",
"lint": "eslint . --ignore-pattern dist --ignore-pattern e2e/cache",
"pack-install": "bash ./scripts/pack.sh"
},
"dependencies": {
"@types/async-retry": "1.4.2",
"@types/ci-info": "2.0.0",
"@types/cross-spawn": "6.0.0",
"@types/fs-extra": "11.0.4",
"@types/node": "^20.11.7",
"@types/prompts": "2.4.2",
"@types/tar": "6.1.5",
"@types/validate-npm-package-name": "3.0.0",
"async-retry": "1.3.1",
"async-sema": "3.0.1",
"ci-info": "github:watson/ci-info#f43f6a1cefff47fb361c88cf4b943fdbcaafe540",
"commander": "12.1.0",
"cross-spawn": "7.0.3",
"fast-glob": "3.3.1",
"fs-extra": "11.2.0",
"global-agent": "^3.0.0",
"got": "10.7.0",
"ollama": "^0.5.0",
"ora": "^8.0.1",
"picocolors": "1.0.0",
"prompts": "2.4.2",
"smol-toml": "^1.1.4",
"tar": "6.1.15",
"terminal-link": "^3.0.0",
"update-check": "1.5.4",
"validate-npm-package-name": "3.0.0",
"yaml": "2.4.1"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.10.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"@playwright/test": "^1.41.1",
"@vercel/ncc": "0.38.1",
"rimraf": "^5.0.5",
"typescript": "^5.3.3",
"wait-port": "^1.1.0"
},
"packageManager": "pnpm@9.0.5",
"engines": {
"node": ">=16.14.0"
}
}
@@ -1,33 +0,0 @@
[project]
name = "app"
version = "0.1.0"
description = ""
authors = [ { name = "Marcus Schiesser", email = "mail@marcusschiesser.de" } ]
readme = "README.md"
requires-python = ">=3.11,<4.0"
dependencies = [
"fastapi>=0.109.1",
"python-dotenv>=1.0.0",
"pydantic<2.10",
"llama-index>=0.12.1",
"cachetools>=5.3.3",
"reflex>=0.6.2.post1",
]
[project.scripts]
generate = "app.engine.generate:generate_datasource"
[project.optional-dependencies]
dev = [
"mypy>=1.8.0",
"pytest>=8.3.5",
"pytest-asyncio>=0.25.3",
"docx2txt>=0.8",
"llama-index-llms-openai>=0.3.2",
"llama-index-embeddings-openai>=0.3.1",
"llama-index-agent-openai>=0.4.0",
]
[build-system]
requires = [ "hatchling>=1.24" ]
build-backend = "hatchling.build"

Some files were not shown because too many files have changed in this diff Show More