Skip to content

Commit 7726123

Browse files
committed
Breeding makes a url as well
1 parent 0c1fd81 commit 7726123

File tree

4 files changed

+124
-9
lines changed

4 files changed

+124
-9
lines changed

app/api/breed/route.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { createClient } from "@/ai/client";
22
import { modelToOpenRouter } from "@/ai/models";
3-
import { system } from "@/ai/prompt";
43
import PostHogClient from "@/lib/postHogServer";
54
import { shouldUseAuth } from "@/lib/shouldUseAuth";
65
import { Settings } from "@/state/settings";
76
import { currentUser } from "@clerk/nextjs/server";
87
import { NextRequest } from "next/server";
98
import { streamHtml } from "openai-html-stream";
109

11-
import {
12-
ChatCompletionCreateParamsStreaming,
13-
ChatCompletionMessageParam,
14-
} from "openai/resources/index.mjs";
10+
import { ChatCompletionCreateParamsStreaming } from "openai/resources/index.mjs";
1511

1612
const makePrompt = (
1713
p1: string,

app/api/breedUrl/route.ts

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { createClient } from "@/ai/client";
2+
import PostHogClient from "@/lib/postHogServer";
3+
import { shouldUseAuth } from "@/lib/shouldUseAuth";
4+
import { currentUser } from "@clerk/nextjs/server";
5+
import { NextRequest } from "next/server";
6+
7+
import { ChatCompletionCreateParams } from "openai/resources/index.mjs";
8+
9+
const makePrompt = (
10+
p1: string,
11+
p2: string
12+
) => `You will be acting as a website breeder. Your task is to generate a new website name based on two existing websites, as if the new website were the offspring of the two parent sites.
13+
14+
Here are the two URLs you will be working with:
15+
<url1>
16+
${p1}
17+
</url1>
18+
<url2>
19+
${p2}
20+
</url2>
21+
22+
To generate the offspring website name, follow these steps:
23+
24+
1. Analyze each website and identify their key elements, themes, and characteristics. Consider factors such as the website's purpose, target audience, design style, and content focus.
25+
26+
2. Brainstorm potential offspring website names that combine elements from both parent websites. The new name should reflect a blend of the two sites' themes and characteristics.
27+
28+
3. When creating the offspring website name, keep these guidelines in mind:
29+
- The name should be concise and memorable.
30+
- It should maintain a coherent theme that relates to both parent websites.
31+
- The name should hint at the potential purpose or content of the hypothetical offspring website.
32+
- Feel free to use wordplay, puns, or creative combinations of words from the parent website names or their key elements.
33+
34+
4. After brainstorming and refining your ideas, select the best offspring website name.
35+
36+
Please output the final offspring website name inside <offspring_url> tags.
37+
`;
38+
39+
export async function POST(req: NextRequest) {
40+
const { urls } = await req.json();
41+
42+
if (shouldUseAuth) {
43+
const user = await currentUser();
44+
const posthog = PostHogClient();
45+
46+
if (!user) {
47+
return new Response(`<h1>Unauthorized</h1><p>Log in to continue</p>`, {
48+
status: 401,
49+
headers: { "Content-Type": "text/html" },
50+
});
51+
}
52+
53+
posthog.capture({
54+
distinctId: user.id,
55+
event: "breed url",
56+
});
57+
}
58+
59+
const offspringUrl = await genResponse({ urls });
60+
61+
return new Response(JSON.stringify(offspringUrl), {
62+
headers: {
63+
"Content-Type": "application/json",
64+
},
65+
status: 200,
66+
});
67+
}
68+
69+
async function genResponse({ urls }: { urls: string[] }): Promise<string> {
70+
const params: ChatCompletionCreateParams = {
71+
messages: [
72+
{
73+
role: "user",
74+
content: makePrompt(urls[0], urls[1]),
75+
},
76+
],
77+
78+
model: "claude-3-haiku-20240307",
79+
max_tokens: 4000,
80+
};
81+
82+
const client = createClient(process.env.ANTHROPIC_API_KEY!);
83+
84+
const content = (await client.chat.completions.create(params)).choices[0]
85+
.message.content!;
86+
const offspringUrlMatch = content.match(
87+
/<offspring_url>(.*?)<\/offspring_url>/
88+
);
89+
return offspringUrlMatch ? offspringUrlMatch[1] : "";
90+
}

components/Canvas.tsx

+21-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import dynamic from "next/dynamic";
44
import { BrowserShapeUtil } from "@/components/BrowserShape";
55
import { useEditor } from "tldraw";
6-
import { useEffect } from "react";
6+
import { useEffect, useState } from "react";
77
import { BottomBar } from "@/components/BottomBar";
88
import { BrowserTool } from "@/tools/BrowserTool";
99
import { SignOutButton } from "@clerk/nextjs";
@@ -13,6 +13,7 @@ import { shouldUseAuth } from "@/lib/shouldUseAuth";
1313
import { Settings } from "@/components/Settings";
1414
import { PromptShapeTool } from "@/tools/PromptShapeTool";
1515
import { breed } from "@/lib/breed";
16+
import { ReloadIcon } from "@radix-ui/react-icons";
1617

1718
const Tldraw = dynamic(async () => (await import("tldraw")).Tldraw, {
1819
ssr: false,
@@ -57,9 +58,7 @@ function UI() {
5758
style={{ zIndex: 1000 }}
5859
>
5960
<Settings />
60-
<Button size="sm" onClick={() => breed(editor)}>
61-
Breed
62-
</Button>
61+
<BreedButton />
6362
{shouldUseAuth && (
6463
<SignOutButton>
6564
<Button size="sm">Sign Out</Button>
@@ -75,3 +74,21 @@ function UI() {
7574
</>
7675
);
7776
}
77+
78+
function BreedButton() {
79+
const editor = useEditor();
80+
const [isBreeding, setIsBreeding] = useState(false);
81+
return (
82+
<Button
83+
onClick={async () => {
84+
setIsBreeding(true);
85+
await breed(editor);
86+
setIsBreeding(false);
87+
}}
88+
disabled={isBreeding}
89+
size="sm"
90+
>
91+
{isBreeding ? <ReloadIcon className="h-4 w-4 animate-spin" /> : "Breed"}
92+
</Button>
93+
);
94+
}

lib/breed.ts

+12
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,25 @@ export async function breed(editor: Editor) {
1919
return;
2020
}
2121

22+
const urls = selectedShapes.map((s) => s.props.url);
23+
const response = await fetch(`/api/breedUrl`, {
24+
method: "POST",
25+
body: JSON.stringify({ urls }),
26+
headers: {
27+
"Content-Type": "application/json",
28+
},
29+
});
30+
31+
const offspringUrl = await response.json();
32+
2233
const id = makeShapeID();
2334
editor.createShape<BrowserShape>({
2435
...getPointUnder(boundingBox),
2536
type: "browser",
2637
id,
2738
props: {
2839
isBred: true,
40+
url: offspringUrl,
2941
},
3042
});
3143

0 commit comments

Comments
 (0)