mirror of
https://github.com/run-llama/app-creator.git
synced 2026-06-30 21:08:04 -04:00
allow multi-file projects
This commit is contained in:
@@ -7,12 +7,14 @@ The multi-agents are implemented using [Workflows](https://ts.llamaindex.ai/modu
|
||||
## Getting Started
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```
|
||||
git clone https://github.com/run-llama/app-creator.git
|
||||
cd app-creator
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
@@ -6,13 +6,14 @@ import {
|
||||
WorkflowEvent,
|
||||
} from "@llamaindex/core/workflow";
|
||||
import { OpenAI, Settings } from "llamaindex";
|
||||
import { PackageEvent, packager } from "./packager";
|
||||
|
||||
const MAX_REVIEWS = 3;
|
||||
|
||||
// Create custom event types
|
||||
export class MessageEvent extends WorkflowEvent<{ msg: string }> {}
|
||||
export class CodeEvent extends WorkflowEvent<{ code: string }> {}
|
||||
export class ReviewEvent extends WorkflowEvent<{
|
||||
class CodeEvent extends WorkflowEvent<{ code: string }> {}
|
||||
class ReviewEvent extends WorkflowEvent<{
|
||||
review: string;
|
||||
code: string;
|
||||
}> {}
|
||||
@@ -88,7 +89,7 @@ const reviewer = async (context: Context, ev: CodeEvent) => {
|
||||
msg: `Reviewer says: ${review}`,
|
||||
}),
|
||||
);
|
||||
return new StopEvent({ result: code });
|
||||
return new PackageEvent({ code });
|
||||
}
|
||||
|
||||
return new ReviewEvent({ review, code });
|
||||
@@ -98,7 +99,10 @@ export function createAgent(model: string): Workflow {
|
||||
const codeAgent = new Workflow({ validate: true });
|
||||
codeAgent.addStep(StartEvent, architect, { outputs: CodeEvent });
|
||||
codeAgent.addStep(ReviewEvent, coder, { outputs: CodeEvent });
|
||||
codeAgent.addStep(CodeEvent, reviewer, { outputs: ReviewEvent });
|
||||
codeAgent.addStep(CodeEvent, reviewer, {
|
||||
outputs: [ReviewEvent, PackageEvent],
|
||||
});
|
||||
codeAgent.addStep(PackageEvent, packager, { outputs: StopEvent });
|
||||
|
||||
// Update the llm model with the provided model
|
||||
Settings.llm = new OpenAI({ model, temperature: 1 });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createAgent, MessageEvent } from "./agent";
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import * as fs from "fs/promises";
|
||||
import * as path from "path";
|
||||
import { PackageResult } from "./packager";
|
||||
|
||||
const apps = [
|
||||
{
|
||||
@@ -9,22 +10,45 @@ const apps = [
|
||||
database where they are mapped to answers. If there is a close match, it retrieves
|
||||
the matched answer. If there isn't, it asks the user to provide an answer and
|
||||
stores the question/answer pair in the database.`,
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini", "o1-preview"]
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini", "o1-preview"],
|
||||
},
|
||||
{
|
||||
name: "JavaScript Todo App",
|
||||
spec: `Create a full-stack NextJS todo app with a TailwindCSS frontend, that allows users to add,
|
||||
remove, and mark tasks as complete. Use a Postgres database to persist the tasks.`,
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini"] // didn't complete with o1-preview
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini"], // didn't complete with o1-preview
|
||||
},
|
||||
{
|
||||
name: "Iphone calculator",
|
||||
spec: `Iphone style scientific calculator in one html file, using tailwind css and javascript.`,
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini", "o1-preview"]
|
||||
}
|
||||
models: ["gpt-4o-mini", "gpt-4o", "o1-mini", "o1-preview"],
|
||||
},
|
||||
// Add more specifications as needed
|
||||
];
|
||||
|
||||
async function outputResult(
|
||||
name: string,
|
||||
model: string,
|
||||
packageResult: PackageResult,
|
||||
) {
|
||||
// Create output directory if it doesn't exist
|
||||
const outputDir = path.join("output", name, model);
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
|
||||
// Iterate over all files in the packageResult and store each file with their correct path
|
||||
for (const file of packageResult.files) {
|
||||
const filePath = path.join(outputDir, file.path);
|
||||
const fileDir = path.dirname(filePath);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
await fs.mkdir(fileDir, { recursive: true });
|
||||
|
||||
// Write file content
|
||||
await fs.writeFile(filePath, file.content);
|
||||
console.log(`File written to: ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runGeneration(name: string, spec: string, model: string) {
|
||||
console.log(`Running generation with model: ${model}`);
|
||||
const codeAgent = createAgent(model);
|
||||
@@ -34,15 +58,9 @@ async function runGeneration(name: string, spec: string, model: string) {
|
||||
console.log(`${msg}\n`);
|
||||
}
|
||||
const result = await run;
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
const outputDir = path.join('output', name);
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
|
||||
// Write the generated code to a file
|
||||
const outputFile = path.join(outputDir, `${model}.code`);
|
||||
await fs.writeFile(outputFile, result.data.result);
|
||||
console.log(`Generated code written to: ${outputFile}\n`);
|
||||
const packageResult = result.data.result as unknown as PackageResult;
|
||||
|
||||
await outputResult(name, model, packageResult);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
+4
-2
@@ -13,10 +13,12 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@llamaindex/core": "^0.2.0",
|
||||
"llamaindex": "^0.6.0"
|
||||
"llamaindex": "^0.6.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.23.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.3",
|
||||
"tsx": "^4.19.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
import { Context, StopEvent, WorkflowEvent } from "@llamaindex/core/workflow";
|
||||
import { OpenAI } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
export class PackageEvent extends WorkflowEvent<{
|
||||
code: string;
|
||||
}> {}
|
||||
|
||||
const FileSchema = z.object({
|
||||
path: z.string().describe("Path to the filename, e.g., 'app/main.py'"),
|
||||
content: z.string().describe("Complete content of the file"),
|
||||
});
|
||||
|
||||
const PackageResultSchema = z.object({
|
||||
files: z.array(FileSchema),
|
||||
});
|
||||
|
||||
export type PackageResult = z.infer<typeof PackageResultSchema>;
|
||||
|
||||
export const packager = async (context: Context, ev: PackageEvent) => {
|
||||
const { code } = ev.data;
|
||||
|
||||
// use own llm for extracting the files
|
||||
const llm = new OpenAI({
|
||||
model: "gpt-4o-mini",
|
||||
additionalChatOptions: { response_format: { type: "json_object" } },
|
||||
});
|
||||
|
||||
const schema = JSON.stringify(zodToJsonSchema(PackageResultSchema));
|
||||
|
||||
const response = await llm.chat({
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: `You are an expert in extracting single files (path and content) from one large string.\n\nGenerate a valid JSON following the given schema below:\n\n${schema}`,
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: `Here is the large string: \n------\n${code}\n------`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const json = response.message.content as string;
|
||||
const result = PackageResultSchema.parse(JSON.parse(json));
|
||||
|
||||
// TODO: allow different types of outputs in LlamaIndexTS
|
||||
return new StopEvent({ result: result as unknown as string });
|
||||
};
|
||||
Generated
+18
@@ -13,6 +13,12 @@ importers:
|
||||
llamaindex:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0(@aws-sdk/client-sso-oidc@3.650.0(@aws-sdk/client-sts@3.650.0))(@aws-sdk/credential-providers@3.650.0(@aws-sdk/client-sso-oidc@3.650.0(@aws-sdk/client-sts@3.650.0)))(@notionhq/client@2.2.15(encoding@0.1.13))(encoding@0.1.13)(typescript@5.6.2)
|
||||
zod:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
zod-to-json-schema:
|
||||
specifier: ^3.23.3
|
||||
version: 3.23.3(zod@3.23.8)
|
||||
devDependencies:
|
||||
prettier:
|
||||
specifier: ^3.3.3
|
||||
@@ -3738,6 +3744,14 @@ packages:
|
||||
}
|
||||
engines: { node: ">=12" }
|
||||
|
||||
zod-to-json-schema@3.23.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==,
|
||||
}
|
||||
peerDependencies:
|
||||
zod: ^3.23.3
|
||||
|
||||
zod@3.23.8:
|
||||
resolution:
|
||||
{
|
||||
@@ -6532,4 +6546,8 @@ snapshots:
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
|
||||
zod-to-json-schema@3.23.3(zod@3.23.8):
|
||||
dependencies:
|
||||
zod: 3.23.8
|
||||
|
||||
zod@3.23.8: {}
|
||||
|
||||
Reference in New Issue
Block a user