Skip to content

Simplify FastAPI fullstack template by include frontend code and a build script #423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b980b6
rebase
leehuwuj Nov 13, 2024
2693eb1
simply
leehuwuj Nov 13, 2024
bed4979
add static mount
leehuwuj Nov 13, 2024
98f8054
update log
leehuwuj Nov 18, 2024
c103816
Merge remote-tracking branch 'origin/main' into lee/fullstack
leehuwuj Nov 18, 2024
4af77c6
add readme
leehuwuj Nov 18, 2024
51a8cdf
update CL scripts
leehuwuj Nov 18, 2024
e9554fa
remove frontend for express
leehuwuj Nov 18, 2024
72b8dc1
add support pnpm
leehuwuj Nov 18, 2024
57e3e77
remove e2e test frontend for express
leehuwuj Nov 18, 2024
875f1ff
Fix issue on CI
leehuwuj Nov 18, 2024
60f2c2f
Merge remote-tracking branch 'origin/main' into lee/fullstack
leehuwuj Nov 18, 2024
b1a9db2
fix e2e
leehuwuj Nov 18, 2024
7c8757d
remove e2e frontend tests for express
leehuwuj Nov 19, 2024
78c7798
improve code
leehuwuj Nov 19, 2024
18e7c0e
better run command
leehuwuj Nov 19, 2024
8aa26e9
remove externalPort
leehuwuj Nov 19, 2024
61117be
improve run script
leehuwuj Nov 19, 2024
0c0bbf0
improve code
leehuwuj Nov 19, 2024
96f9f72
add changeset and fix run script issue in Windows
leehuwuj Nov 19, 2024
3f61cc5
fix Windows issue
leehuwuj Nov 19, 2024
acb293c
remove shell
leehuwuj Nov 19, 2024
f373311
simplify reflex port
leehuwuj Nov 19, 2024
26dfec6
remove backend port reflex
leehuwuj Nov 19, 2024
60f546e
update dev mode
leehuwuj Nov 19, 2024
1b993b9
update runner script
leehuwuj Nov 19, 2024
e2e53e2
add prod support and update docs
leehuwuj Nov 19, 2024
6c8497e
add timeout for sending request in proxy
leehuwuj Nov 19, 2024
e72b9cc
fix mypy
leehuwuj Nov 19, 2024
424e0c1
update docs and remove cors
leehuwuj Nov 20, 2024
ed0f2b6
remove build
leehuwuj Nov 20, 2024
d3e0fb0
update for reflex
leehuwuj Nov 20, 2024
603f576
Update .changeset/popular-dryers-check.md
marcusschiesser Nov 20, 2024
8079ba4
remove legacy fullstack files
leehuwuj Nov 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/popular-dryers-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-llama": patch
---

Improve DX for Python template (use one deployment instead of two)
25 changes: 8 additions & 17 deletions create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { getOnline } from "./helpers/is-online";
import { isWriteable } from "./helpers/is-writeable";
import { makeDir } from "./helpers/make-dir";

import fs from "fs";
import terminalLink from "terminal-link";
import type { InstallTemplateArgs, TemplateObservability } from "./helpers";
import { installTemplate } from "./helpers";
Expand Down Expand Up @@ -35,7 +34,7 @@ export async function createApp({
communityProjectConfig,
llamapack,
vectorDb,
externalPort,
port,
postInstallAction,
dataSources,
tools,
Expand Down Expand Up @@ -81,7 +80,7 @@ export async function createApp({
communityProjectConfig,
llamapack,
vectorDb,
externalPort,
port,
postInstallAction,
dataSources,
tools,
Expand All @@ -90,28 +89,20 @@ export async function createApp({
agents,
};

if (frontend) {
// install backend
const backendRoot = path.join(root, "backend");
await makeDir(backendRoot);
await installTemplate({ ...args, root: backendRoot, backend: true });
// Install backend
await installTemplate({ ...args, backend: true });

if (frontend && framework === "fastapi") {
// install frontend
const frontendRoot = path.join(root, "frontend");
const frontendRoot = path.join(root, ".frontend");
await makeDir(frontendRoot);
await installTemplate({
...args,
root: frontendRoot,
framework: "nextjs",
customApiPath: `http://localhost:${externalPort ?? 8000}/api/chat`,
customApiPath: `http://localhost:${port ?? 8000}/api/chat`,
backend: false,
});
// copy readme for fullstack
await fs.promises.copyFile(
path.join(templatesDir, "README-fullstack.md"),
path.join(root, "README.md"),
);
} else {
await installTemplate({ ...args, backend: true });
}

await writeDevcontainer(root, templatesDir, framework, frontend);
Expand Down
4 changes: 0 additions & 4 deletions e2e/python/resolve_dependencies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ if (
vectorDb,
tools: "none",
port: 3000,
externalPort: 8000,
postInstallAction: "none",
templateUI: undefined,
appType: "--no-frontend",
Expand Down Expand Up @@ -101,7 +100,6 @@ if (
vectorDb: "none",
tools: tool,
port: 3000,
externalPort: 8000,
postInstallAction: "none",
templateUI: undefined,
appType: "--no-frontend",
Expand Down Expand Up @@ -135,7 +133,6 @@ if (
vectorDb: "none",
tools: "none",
port: 3000,
externalPort: 8000,
postInstallAction: "none",
templateUI: undefined,
appType: "--no-frontend",
Expand Down Expand Up @@ -169,7 +166,6 @@ if (
vectorDb: "none",
tools: "none",
port: 3000,
externalPort: 8000,
postInstallAction: "none",
templateUI: undefined,
appType: "--no-frontend",
Expand Down
11 changes: 4 additions & 7 deletions e2e/shared/extractor_template.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,22 @@ if (
dataSource === "--example-file"
) {
test.describe("Test extractor template", async () => {
let frontendPort: number;
let backendPort: number;
let appPort: number;
let name: string;
let appProcess: ChildProcess;
let cwd: string;

// Create extractor app
test.beforeAll(async () => {
cwd = await createTestDir();
frontendPort = Math.floor(Math.random() * 10000) + 10000;
backendPort = frontendPort + 1;
appPort = Math.floor(Math.random() * 10000) + 10000;
const result = await runCreateLlama({
cwd,
templateType: "extractor",
templateFramework: "fastapi",
dataSource: "--example-file",
vectorDb: "none",
port: frontendPort,
externalPort: backendPort,
port: appPort,
postInstallAction: "runApp",
});
name = result.projectName;
Expand All @@ -54,7 +51,7 @@ if (
expect(dirExists).toBeTruthy();
});
test("Frontend should have a title", async ({ page }) => {
await page.goto(`http://localhost:${frontendPort}`);
await page.goto(`http://localhost:${appPort}`);
await expect(page.getByText("Built by LlamaIndex")).toBeVisible({
timeout: 2000 * 60,
});
Expand Down
14 changes: 9 additions & 5 deletions e2e/shared/multiagent_template.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const templateFramework: TemplateFramework = process.env.FRAMEWORK
const dataSource: string = "--example-file";
const templateUI: TemplateUI = "shadcn";
const templatePostInstallAction: TemplatePostInstallAction = "runApp";
const appType: AppType = templateFramework === "nextjs" ? "" : "--frontend";
const appType: AppType = templateFramework === "fastapi" ? "--frontend" : "";
const userMessage = "Write a blog post about physical standards for letters";
const templateAgents = ["financial_report", "blog", "form_filling"];

Expand All @@ -27,7 +27,6 @@ for (const agents of templateAgents) {
"The multiagent template currently only works with files. We also only run on Linux to speed up tests.",
);
let port: number;
let externalPort: number;
let cwd: string;
let name: string;
let appProcess: ChildProcess;
Expand All @@ -36,7 +35,6 @@ for (const agents of templateAgents) {

test.beforeAll(async () => {
port = Math.floor(Math.random() * 10000) + 10000;
externalPort = port + 1;
cwd = await createTestDir();
const result = await runCreateLlama({
cwd,
Expand All @@ -45,7 +43,6 @@ for (const agents of templateAgents) {
dataSource,
vectorDb,
port,
externalPort,
postInstallAction: templatePostInstallAction,
templateUI,
appType,
Expand All @@ -61,6 +58,10 @@ for (const agents of templateAgents) {
});

test("Frontend should have a title", async ({ page }) => {
test.skip(
templatePostInstallAction !== "runApp" ||
templateFramework === "express",
);
await page.goto(`http://localhost:${port}`);
await expect(page.getByText("Built by LlamaIndex")).toBeVisible();
});
Expand All @@ -69,7 +70,10 @@ for (const agents of templateAgents) {
page,
}) => {
test.skip(
agents === "financial_report" || agents === "form_filling",
templatePostInstallAction !== "runApp" ||
agents === "financial_report" ||
agents === "form_filling" ||
templateFramework === "express",
"Skip chat tests for financial report and form filling.",
);
await page.goto(`http://localhost:${port}`);
Expand Down
16 changes: 9 additions & 7 deletions e2e/shared/streaming_template.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const templatePostInstallAction: TemplatePostInstallAction = "runApp";
const llamaCloudProjectName = "create-llama";
const llamaCloudIndexName = "e2e-test";

const appType: AppType = templateFramework === "nextjs" ? "" : "--frontend";
const appType: AppType = templateFramework === "fastapi" ? "--frontend" : "";
const userMessage =
dataSource !== "--no-files" ? "Physical standard for letters" : "Hello";

Expand All @@ -35,7 +35,6 @@ test.describe(`Test streaming template ${templateFramework} ${dataSource} ${temp
}

let port: number;
let externalPort: number;
let cwd: string;
let name: string;
let appProcess: ChildProcess;
Expand All @@ -44,7 +43,6 @@ test.describe(`Test streaming template ${templateFramework} ${dataSource} ${temp

test.beforeAll(async () => {
port = Math.floor(Math.random() * 10000) + 10000;
externalPort = port + 1;
cwd = await createTestDir();
const result = await runCreateLlama({
cwd,
Expand All @@ -53,7 +51,6 @@ test.describe(`Test streaming template ${templateFramework} ${dataSource} ${temp
dataSource,
vectorDb,
port,
externalPort,
postInstallAction: templatePostInstallAction,
templateUI,
appType,
Expand All @@ -68,16 +65,21 @@ test.describe(`Test streaming template ${templateFramework} ${dataSource} ${temp
const dirExists = fs.existsSync(path.join(cwd, name));
expect(dirExists).toBeTruthy();
});

test("Frontend should have a title", async ({ page }) => {
test.skip(templatePostInstallAction !== "runApp");
test.skip(
templatePostInstallAction !== "runApp" || templateFramework === "express",
);
await page.goto(`http://localhost:${port}`);
await expect(page.getByText("Built by LlamaIndex")).toBeVisible();
});

test("Frontend should be able to submit a message and receive a response", async ({
page,
}) => {
test.skip(templatePostInstallAction !== "runApp");
test.skip(
templatePostInstallAction !== "runApp" || templateFramework === "express",
);
await page.goto(`http://localhost:${port}`);
await page.fill("form textarea", userMessage);
const [response] = await Promise.all([
Expand All @@ -102,7 +104,7 @@ test.describe(`Test streaming template ${templateFramework} ${dataSource} ${temp
test.skip(templatePostInstallAction !== "runApp");
test.skip(templateFramework === "nextjs");
const response = await request.post(
`http://localhost:${externalPort}/api/chat/request`,
`http://localhost:${port}/api/chat/request`,
{
data: {
messages: [
Expand Down
1 change: 0 additions & 1 deletion e2e/typescript/resolve_dependencies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ test.describe("Test resolve TS dependencies", () => {
dataSource: dataSource,
vectorDb: vectorDb,
port: 3000,
externalPort: 8000,
postInstallAction: "none",
templateUI: undefined,
appType: templateFramework === "nextjs" ? "" : "--no-frontend",
Expand Down
24 changes: 1 addition & 23 deletions e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export type RunCreateLlamaOptions = {
dataSource: string;
vectorDb: TemplateVectorDB;
port: number;
externalPort: number;
postInstallAction: TemplatePostInstallAction;
templateUI?: TemplateUI;
appType?: AppType;
Expand All @@ -44,7 +43,6 @@ export async function runCreateLlama({
dataSource,
vectorDb,
port,
externalPort,
postInstallAction,
templateUI,
appType,
Expand Down Expand Up @@ -93,8 +91,6 @@ export async function runCreateLlama({
"--use-pnpm",
"--port",
port,
"--external-port",
externalPort,
"--post-install-action",
postInstallAction,
"--tools",
Expand Down Expand Up @@ -142,12 +138,7 @@ export async function runCreateLlama({

// Wait for app to start
if (postInstallAction === "runApp") {
await checkAppHasStarted(
appType === "--frontend",
templateFramework,
port,
externalPort,
);
await waitPorts([port]);
} else if (postInstallAction === "dependencies") {
await waitForProcess(appProcess, 1000 * 60); // wait 1 min for dependencies to be resolved
} else {
Expand All @@ -167,19 +158,6 @@ export async function createTestDir() {
return cwd;
}

// eslint-disable-next-line max-params
async function checkAppHasStarted(
frontend: boolean,
framework: TemplateFramework,
port: number,
externalPort: number,
) {
const portsToWait = frontend
? [port, externalPort]
: [framework === "nextjs" ? port : externalPort];
await waitPorts(portsToWait);
}

async function waitPorts(ports: number[]): Promise<void> {
const waitForPort = async (port: number): Promise<void> => {
await waitPort({
Expand Down
28 changes: 6 additions & 22 deletions helpers/devcontainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,21 @@ import { TemplateFramework } from "./types";
function renderDevcontainerContent(
templatesDir: string,
framework: TemplateFramework,
frontend: boolean,
) {
const devcontainerJson: any = JSON.parse(
fs.readFileSync(path.join(templatesDir, "devcontainer.json"), "utf8"),
);

// Modify postCreateCommand
if (frontend) {
devcontainerJson.postCreateCommand =
framework === "fastapi"
? "cd backend && poetry install && cd ../frontend && npm install"
: "cd backend && npm install && cd ../frontend && npm install";
} else {
devcontainerJson.postCreateCommand =
framework === "fastapi" ? "poetry install" : "npm install";
}
devcontainerJson.postCreateCommand =
framework === "fastapi" ? "poetry install" : "npm install";

// Modify containerEnv
if (framework === "fastapi") {
if (frontend) {
devcontainerJson.containerEnv = {
...devcontainerJson.containerEnv,
PYTHONPATH: "${PYTHONPATH}:${workspaceFolder}/backend",
};
} else {
devcontainerJson.containerEnv = {
...devcontainerJson.containerEnv,
PYTHONPATH: "${PYTHONPATH}:${workspaceFolder}",
};
}
devcontainerJson.containerEnv = {
...devcontainerJson.containerEnv,
PYTHONPATH: "${PYTHONPATH}:${workspaceFolder}",
};
}

return JSON.stringify(devcontainerJson, null, 2);
Expand All @@ -54,7 +39,6 @@ export const writeDevcontainer = async (
const devcontainerContent = renderDevcontainerContent(
templatesDir,
framework,
frontend,
);
fs.mkdirSync(devcontainerDir);
await fs.promises.writeFile(
Expand Down
4 changes: 2 additions & 2 deletions helpers/env-variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ export const createBackendEnvFile = async (
| "framework"
| "dataSources"
| "template"
| "externalPort"
| "port"
| "tools"
| "observability"
>,
Expand All @@ -570,7 +570,7 @@ export const createBackendEnvFile = async (
...getModelEnvs(opts.modelConfig),
...getEngineEnvs(),
...getVectorDBEnvs(opts.vectorDb, opts.framework),
...getFrameworkEnvs(opts.framework, opts.externalPort),
...getFrameworkEnvs(opts.framework, opts.port),
...getToolEnvs(opts.tools),
...getTemplateEnvs(opts.template),
...getObservabilityEnvs(opts.observability),
Expand Down
Loading
Loading