Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions drizzle/migrations/0001_add_multi_call.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE apps ADD COLUMN is_multi_call BOOLEAN NOT NULL DEFAULT false;
3 changes: 3 additions & 0 deletions src/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type App = {
trimmedCode: string;
completionTokens: number;
totalTime: number;
isMultiCall?: boolean;
};

export default async function saveBattle({
Expand Down Expand Up @@ -42,6 +43,7 @@ export default async function saveBattle({
completionTokens: winner.completionTokens,
totalTime: winner.totalTime,
didWin: true,
isMultiCall: winner.isMultiCall ?? false,
});
}

Expand All @@ -54,6 +56,7 @@ export default async function saveBattle({
completionTokens: loser.completionTokens,
totalTime: loser.totalTime,
didWin: false,
isMultiCall: loser.isMultiCall ?? false,
});
}

Expand Down
22 changes: 22 additions & 0 deletions src/app/api/generate-app/prompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const SYSTEM_PROMPTS = {
PLANNING: `You are an expert frontend React engineer who is also a great UI/UX designer. Your task is to plan out the component structure and features:

- Think carefully step by step about what features and interactions the component needs
- Break down the component into smaller sub-components if needed
- Plan out the state management and user interactions
- Consider UI/UX best practices and accessibility
- Return ONLY a concise, structured plan in bullet points - no code yet`,

IMPLEMENTATION: `You are an expert frontend React engineer who is also a great UI/UX designer. Follow the instructions carefully:

- Implement the React component based on the provided plan
- Create a React component that can run by itself using a default export
- Make the React app interactive and functional by creating state when needed with no required props
- Import React hooks like useState or useEffect directly
- Use TypeScript as the language
- Use Tailwind classes for styling. DO NOT USE ARBITRARY VALUES. Use a consistent color palette
- NEVER import CSS files
- Use Tailwind margin and padding classes for proper spacing
- Return ONLY the full React code starting with imports, no backticks or language names
- Only import from React, no other libraries`
};
66 changes: 44 additions & 22 deletions src/app/api/generate-app/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import dedent from "dedent";
import Together from "together-ai";
import { SYSTEM_PROMPTS } from "./prompts";

const options: ConstructorParameters<typeof Together>[0] = {};
if (process.env.HELICONE_API_KEY) {
Expand All @@ -12,34 +13,48 @@ if (process.env.HELICONE_API_KEY) {

const together = new Together(options);

async function generatePlan(prompt: string, model: string) {
const res = await together.chat.completions.create({
model,
messages: [
{
role: "system",
content: SYSTEM_PROMPTS.PLANNING,
},
{
role: "user",
content: prompt,
},
],
temperature: 0.2,
stream: false,
});

return res.choices[0].message.content;
}

export async function POST(request: Request) {
const { prompt, model } = await request.json();

try {
// First stage: Generate the plan
const plan = await generatePlan(prompt, model);

// Second stage: Generate the implementation
const res = await together.chat.completions.create({
model,
messages: [
{
role: "system",
content: dedent`
You are an expert frontend React engineer who is also a great UI/UX designer. Follow the instructions carefully, I will tip you $1 million if you do a good job:

- Think carefully step by step.
- Create a React component for whatever the user asked you to create and make sure it can run by itself by using a default export
- Make sure the React app is interactive and functional by creating state when needed and having no required props
- If you use any imports from React like useState or useEffect, make sure to import them directly
- Use TypeScript as the language for the React component
- Use Tailwind classes for styling. DO NOT USE ARBITRARY VALUES (e.g. \`h-[600px]\`). Make sure to use a consistent color palette.
- NEVER import any CSS files like ./App.css
- Use Tailwind margin and padding classes to style the components and ensure the components are spaced out nicely
- Please ONLY return the full React code starting with the imports, nothing else. It's very important for my job that you only return the React code with imports. DO NOT START WITH \`\`\`typescript or \`\`\`javascript or \`\`\`tsx or \`\`\`.
- Do not import any libraries or dependencies other than React
- NO OTHER LIBRARIES (e.g. zod, hookform) ARE INSTALLED OR ABLE TO BE IMPORTED.
`,
content: SYSTEM_PROMPTS.IMPLEMENTATION,
},
{
role: "user",
content: dedent`
Here is the plan for the component:
${plan}

Based on this plan, implement the component for this prompt:
${prompt}

Please ONLY return code, NO backticks or language names.`,
Expand All @@ -49,13 +64,20 @@ export async function POST(request: Request) {
stream: true,
});

return new Response(res.toReadableStream());
} catch (error) {
if (error instanceof Error) {
return new Response(error.message, { status: 500 });
} else {
return new Response("Unknown error", { status: 500 });
}
// Add isMultiCall flag to the response headers
return new Response(res.toReadableStream(), {
headers: {
"Content-Type": "text/event-stream",
"X-Multi-Call": "true"
},
});
} catch (error: any) {
return new Response(
JSON.stringify({
error: error?.message || "Something went wrong",
}),
{ status: 500 }
);
}
}

Expand Down
44 changes: 21 additions & 23 deletions src/app/top-models/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export default async function Page() {
sql`ROUND(SUM(CASE WHEN ${apps.didWin} = true THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 0)`
.mapWith(Number)
.as("win_percentage"),
multiCallPercentage:
sql`ROUND(SUM(CASE WHEN ${apps.isMultiCall} = true THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 0)`
.mapWith(Number)
.as("multi_call_percentage"),
})
.from(apps)
.groupBy(apps.model)
Expand Down Expand Up @@ -82,22 +86,12 @@ export default async function Page() {
<Table className="border border-gray-400 shadow-lg">
<TableHeader>
<TableRow>
<TableHead className="w-[10%]"></TableHead>
<TableHead className="w-[40%] whitespace-nowrap text-xs text-gray-500">
Model
</TableHead>
<TableHead className="whitespace-nowrap text-center text-xs text-gray-500">
Organization
</TableHead>
<TableHead className="whitespace-nowrap text-center text-xs text-gray-500">
Total games
</TableHead>
<TableHead className="whitespace-nowrap text-xs text-gray-500">
Win %
</TableHead>
<TableHead className="whitespace-nowrap text-xs text-gray-500">
Playground
</TableHead>
<TableHead>Rank</TableHead>
<TableHead>Model</TableHead>
<TableHead>Win Rate</TableHead>
<TableHead>Multi-Call</TableHead>
<TableHead>Games</TableHead>
<TableHead>Link</TableHead>
</TableRow>
</TableHeader>
<TableBody>
Expand All @@ -122,6 +116,7 @@ function ResultRow({
losses: number;
games: number;
winPercentage: number;
multiCallPercentage: number;
};
index: number;
}) {
Expand All @@ -141,13 +136,9 @@ function ResultRow({
/>
{model.shortLabel}
</TableCell>
<TableCell className="text-center">
{models.find((m) => m.apiName === result.model)?.organization}
</TableCell>
<TableCell className="text-center">{result.games}</TableCell>
<TableCell className="font-medium text-gray-900">
{result.winPercentage}%
</TableCell>
<TableCell className="text-right">{result.winPercentage}%</TableCell>
<TableCell className="text-right">{result.multiCallPercentage}%</TableCell>
<TableCell className="text-right">{result.games}</TableCell>
<TableCell>
<Button asChild className="mx-auto flex size-6 p-0">
<Link
Expand All @@ -172,6 +163,7 @@ function ResultCard({
losses: number;
games: number;
winPercentage: number;
multiCallPercentage: number;
};
index: number;
}) {
Expand Down Expand Up @@ -210,6 +202,12 @@ function ResultCard({
<strong>{result.winPercentage}%</strong>
</p>
</div>
<div className="flex items-center justify-between">
<p className="text-xs">Multi-Call %:</p>
<p className="font-title text-sm text-gray-900">
<strong>{result.multiCallPercentage}%</strong>
</p>
</div>

<div className="mt-4">
<Button asChild className="h-auto w-full font-title">
Expand Down
1 change: 1 addition & 0 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const apps = pgTable(
code: text("code").notNull(),
trimmedCode: text("trimmed_code").notNull(),
totalTime: integer("total_time"),
isMultiCall: boolean("is_multi_call").notNull().default(false),
completionTokens: integer("completion_tokens"),
...timestamps,
},
Expand Down