Skip to content

Commit 9077cae

Browse files
authored
feat: Add legal document review use case (#467)
1 parent 765d2c4 commit 9077cae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1444
-110
lines changed

.changeset/stale-scissors-turn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-llama": patch
3+
---
4+
5+
Add contract review use case (Python)

e2e/shared/extractor_template.spec.ts

-60
This file was deleted.

e2e/shared/reflex_template.spec.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* eslint-disable turbo/no-undeclared-env-vars */
2+
import { expect, test } from "@playwright/test";
3+
import { ChildProcess } from "child_process";
4+
import fs from "fs";
5+
import path from "path";
6+
import { TemplateAgents, TemplateFramework } from "../../helpers";
7+
import { createTestDir, runCreateLlama } from "../utils";
8+
9+
const templateFramework: TemplateFramework = process.env.FRAMEWORK
10+
? (process.env.FRAMEWORK as TemplateFramework)
11+
: "fastapi";
12+
const dataSource: string = process.env.DATASOURCE
13+
? process.env.DATASOURCE
14+
: "--example-file";
15+
const templateAgents: TemplateAgents[] = ["extractor", "contract_review"];
16+
17+
// The reflex template currently only works with FastAPI and files (and not on Windows)
18+
if (
19+
process.platform !== "win32" &&
20+
templateFramework === "fastapi" &&
21+
dataSource === "--example-file"
22+
) {
23+
for (const agents of templateAgents) {
24+
test.describe(`Test reflex template ${agents} ${templateFramework} ${dataSource}`, async () => {
25+
let appPort: number;
26+
let name: string;
27+
let appProcess: ChildProcess;
28+
let cwd: string;
29+
30+
// Create reflex app
31+
test.beforeAll(async () => {
32+
cwd = await createTestDir();
33+
appPort = Math.floor(Math.random() * 10000) + 10000;
34+
const result = await runCreateLlama({
35+
cwd,
36+
templateType: "reflex",
37+
templateFramework: "fastapi",
38+
dataSource: "--example-file",
39+
vectorDb: "none",
40+
port: appPort,
41+
postInstallAction: "runApp",
42+
agents,
43+
});
44+
name = result.projectName;
45+
appProcess = result.appProcess;
46+
});
47+
48+
test.afterAll(async () => {
49+
appProcess.kill();
50+
});
51+
52+
test("App folder should exist", async () => {
53+
const dirExists = fs.existsSync(path.join(cwd, name));
54+
expect(dirExists).toBeTruthy();
55+
});
56+
test("Frontend should have a title", async ({ page }) => {
57+
await page.goto(`http://localhost:${appPort}`);
58+
await expect(page.getByText("Built by LlamaIndex")).toBeVisible({
59+
timeout: 2000 * 60,
60+
});
61+
});
62+
});
63+
}
64+
}

e2e/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export async function runCreateLlama({
113113
if (observability) {
114114
commandArgs.push("--observability", observability);
115115
}
116-
if (templateType === "multiagent" && agents) {
116+
if ((templateType === "multiagent" || templateType === "reflex") && agents) {
117117
commandArgs.push("--agents", agents);
118118
}
119119

helpers/datasources.ts

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const EXAMPLE_10K_SEC_FILES: TemplateDataSource[] = [
1818
url: new URL(
1919
"https://s2.q4cdn.com/470004039/files/doc_earnings/2023/q4/filing/_10-K-Q4-2023-As-Filed.pdf",
2020
),
21+
filename: "apple_10k_report.pdf",
2122
},
2223
},
2324
{
@@ -26,10 +27,21 @@ export const EXAMPLE_10K_SEC_FILES: TemplateDataSource[] = [
2627
url: new URL(
2728
"https://ir.tesla.com/_flysystem/s3/sec/000162828024002390/tsla-20231231-gen.pdf",
2829
),
30+
filename: "tesla_10k_report.pdf",
2931
},
3032
},
3133
];
3234

35+
export const EXAMPLE_GDPR: TemplateDataSource = {
36+
type: "file",
37+
config: {
38+
url: new URL(
39+
"https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32016R0679",
40+
),
41+
filename: "gdpr.pdf",
42+
},
43+
};
44+
3345
export function getDataSources(
3446
files?: string,
3547
exampleFile?: boolean,

helpers/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ const prepareContextData = async (
118118
const destPath = path.join(
119119
root,
120120
"data",
121-
path.basename(dataSourceConfig.url.toString()),
121+
dataSourceConfig.filename ??
122+
path.basename(dataSourceConfig.url.toString()),
122123
);
123124
await downloadFile(dataSourceConfig.url.toString(), destPath);
124125
} else {
@@ -192,7 +193,7 @@ export const installTemplate = async (
192193
if (
193194
props.template === "streaming" ||
194195
props.template === "multiagent" ||
195-
props.template === "extractor"
196+
props.template === "reflex"
196197
) {
197198
await createBackendEnvFile(props.root, props);
198199
}

helpers/python.ts

+24-20
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,8 @@ export const installPythonTemplate = async ({
405405
>) => {
406406
console.log("\nInitializing Python project with template:", template, "\n");
407407
let templatePath;
408-
if (template === "extractor") {
409-
templatePath = path.join(templatesDir, "types", "extractor", framework);
408+
if (template === "reflex") {
409+
templatePath = path.join(templatesDir, "types", "reflex");
410410
} else {
411411
templatePath = path.join(templatesDir, "types", "streaming", framework);
412412
}
@@ -472,24 +472,6 @@ export const installPythonTemplate = async ({
472472
cwd: path.join(compPath, "engines", "python", engine),
473473
});
474474

475-
// Copy agent code
476-
if (template === "multiagent") {
477-
if (agents) {
478-
await copy("**", path.join(root), {
479-
parents: true,
480-
cwd: path.join(compPath, "agents", "python", agents),
481-
rename: assetRelocator,
482-
});
483-
} else {
484-
console.log(
485-
red(
486-
"There is no agent selected for multi-agent template. Please pick an agent to use via --agents flag.",
487-
),
488-
);
489-
process.exit(1);
490-
}
491-
}
492-
493475
// Copy router code
494476
await copyRouterCode(root, tools ?? []);
495477
}
@@ -503,6 +485,28 @@ export const installPythonTemplate = async ({
503485
});
504486
}
505487

488+
if (template === "multiagent" || template === "reflex") {
489+
if (agents) {
490+
const sourcePath =
491+
template === "multiagent"
492+
? path.join(compPath, "agents", "python", agents)
493+
: path.join(compPath, "reflex", agents);
494+
495+
await copy("**", path.join(root), {
496+
parents: true,
497+
cwd: sourcePath,
498+
rename: assetRelocator,
499+
});
500+
} else {
501+
console.log(
502+
red(
503+
`There is no agent selected for ${template} template. Please pick an agent to use via --agents flag.`,
504+
),
505+
);
506+
process.exit(1);
507+
}
508+
}
509+
506510
console.log("Adding additional dependencies");
507511

508512
const addOnDependencies = getAdditionalDependencies(

helpers/run-app.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SpawnOptions, spawn } from "child_process";
2-
import { TemplateFramework } from "./types";
2+
import { TemplateFramework, TemplateType } from "./types";
33

44
const createProcess = (
55
command: string,
@@ -58,17 +58,17 @@ export function runTSApp(appPath: string, port: number) {
5858

5959
export async function runApp(
6060
appPath: string,
61-
template: string,
61+
template: TemplateType,
6262
framework: TemplateFramework,
6363
port?: number,
6464
): Promise<void> {
6565
try {
6666
// Start the app
6767
const defaultPort =
68-
framework === "nextjs" || template === "extractor" ? 3000 : 8000;
68+
framework === "nextjs" || template === "reflex" ? 3000 : 8000;
6969

7070
const appRunner =
71-
template === "extractor"
71+
template === "reflex"
7272
? runReflexApp
7373
: framework === "fastapi"
7474
? runFastAPIApp

helpers/types.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ export type ModelConfig = {
2020
isConfigured(): boolean;
2121
};
2222
export type TemplateType =
23-
| "extractor"
2423
| "streaming"
2524
| "community"
2625
| "llamapack"
27-
| "multiagent";
26+
| "multiagent"
27+
| "reflex";
2828
export type TemplateFramework = "nextjs" | "express" | "fastapi";
2929
export type TemplateUI = "html" | "shadcn";
3030
export type TemplateVectorDB =
@@ -49,14 +49,21 @@ export type TemplateDataSource = {
4949
};
5050
export type TemplateDataSourceType = "file" | "web" | "db";
5151
export type TemplateObservability = "none" | "traceloop" | "llamatrace";
52-
export type TemplateAgents = "financial_report" | "blog" | "form_filling";
52+
export type TemplateAgents =
53+
| "financial_report"
54+
| "blog"
55+
| "form_filling"
56+
| "extractor"
57+
| "contract_review";
5358
// Config for both file and folder
5459
export type FileSourceConfig =
5560
| {
5661
path: string;
62+
filename?: string;
5763
}
5864
| {
5965
url: URL;
66+
filename?: string;
6067
};
6168
export type WebSourceConfig = {
6269
baseUrl?: string;

helpers/typescript.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export const installTSTemplate = async ({
153153
} else {
154154
console.log(
155155
red(
156-
"There is no agent selected for multi-agent template. Please pick an agent to use via --agents flag.",
156+
`There is no agent selected for ${template} template. Please pick an agent to use via --agents flag.`,
157157
),
158158
);
159159
process.exit(1);

index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const options = program.opts();
215215

216216
if (
217217
process.argv.includes("--no-llama-parse") ||
218-
options.template === "extractor"
218+
options.template === "reflex"
219219
) {
220220
options.useLlamaParse = false;
221221
}

questions/datasources.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const getDataSourceChoices = (
4949
);
5050
}
5151

52-
if (framework === "fastapi" && template !== "extractor") {
52+
if (framework === "fastapi" && template !== "reflex") {
5353
choices.push({
5454
title: "Use website content (requires Chrome)",
5555
value: "web",

questions/questions.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ export const askProQuestions = async (program: QuestionArgs) => {
9595
return; // early return - no further questions needed for llamapack projects
9696
}
9797

98-
if (program.template === "extractor") {
99-
// Extractor template only supports FastAPI, empty data sources, and llamacloud
98+
if (program.template === "reflex") {
99+
// Reflex template only supports FastAPI, empty data sources, and llamacloud
100100
// So we just use example file for extractor template, this allows user to choose vector database later
101101
program.dataSources = [EXAMPLE_FILE];
102102
program.framework = "fastapi";
@@ -354,11 +354,8 @@ export const askProQuestions = async (program: QuestionArgs) => {
354354
// default to use LlamaParse if using LlamaCloud
355355
program.useLlamaParse = true;
356356
} else {
357-
// Extractor template doesn't support LlamaParse and LlamaCloud right now (cannot use asyncio loop in Reflex)
358-
if (
359-
program.useLlamaParse === undefined &&
360-
program.template !== "extractor"
361-
) {
357+
// Reflex template doesn't support LlamaParse and LlamaCloud right now (cannot use asyncio loop in Reflex)
358+
if (program.useLlamaParse === undefined && program.template !== "reflex") {
362359
// if already set useLlamaParse, don't ask again
363360
if (program.dataSources.some((ds) => ds.type === "file")) {
364361
const { useLlamaParse } = await prompts(

0 commit comments

Comments
 (0)