1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import valleGetValsContextWindow from "https://esm.town/v/janpaul123/valleGetValsContextWindow?v=7";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo?v=29";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=84";
import { verifyToken } from "https://esm.town/v/pomdtr/verifyToken?v=1";
import { openai } from "npm:@ai-sdk/openai";
import ValTown from "npm:@valtown/sdk";
import { streamText } from "npm:ai";
import _ from "npm:lodash@4";
async function main(req: Request): Promise<Response> {
const { readable, writable } = new TransformStream();
const writer = writable.getWriter();
const write = (text) => writer.write(new TextEncoder().encode(text));
(async () => {
write(`<!DOCTYPE html>
<html>
<head><link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" /></head>
<body style="padding: 8px; padding-top: 12px; height: 100%; overflow: auto">
<script>
// Scroll to the bottom of the page when the page changes.
(new MutationObserver(function (mutationsList, observer) {
window.scrollTo({ left: 0, top: document.body.scrollHeight, behavior: "instant" });
})).observe(document, { childList: true, characterData: true, subtree: true });
</script>
<div class="mb-4">Hi, I'm <strong>VALL-E</strong>. What would you like to make?</div>`);
const userprompt = req.method === "POST" ? (await req.formData()).get("userprompt") as string : "";
write(`<form method="POST" action="/">
<textarea "autofocus" name="userprompt" class="bg-gray-100 w-full p-2 rounded">${userprompt}</textarea>
<button type="submit" class="bg-gray-100 hover:bg-gray-200 px-2 block rounded">Go</button>
</form>`);
if (userprompt) {
write(`<div class="my-4">I wrote some new code for your Val:
<div class="font-mono whitespace-pre-wrap text-xs p-2 mt-2 rounded bg-gray-100">`);
const stream = await streamText({
model: openai("gpt-4o", {
baseURL: "https://std-openaiproxy.web.val.run/v1",
apiKey: Deno.env.get("valtown"),
} as any),
messages: [
...(await valleGetValsContextWindow("gpt-4o")),
{
role: "system",
content: ` Your entire response should only be TypeScript.
Your response should start with \`\`\`ts and end with \`\`\`, so full code fences.
There should be no comments like "more content here", it should be complete and directly runnable.
The val should have an "export default async function main". The val should return a valid HTML website.
Prefer using Tailwind. Put frontend functions in a <script> tag, using dangerouslySetInnerHTML. Don't use Hono. Don't use Response.redirect.
`.replace("\n", " "),
},
{ role: "user", content: userprompt },
],
});
const tokens = [];
for await (const text of stream.textStream) {
write(_.escape(text));
tokens.push(text);
}
write(`</div></div>`);
const tempValName = `valle_tmp_${Math.random()}`.replaceAll(".", "");
await new ValTown({ bearerToken: Deno.env.get("valtown") }).vals.create({
name: tempValName,
code: tokens.join("").replaceAll("```ts", "").replaceAll("```", ""),
type: "http" as any,
privacy: "unlisted",
});
const username = extractValInfo(import.meta.url).author;
write(`<div class="mt-4">
Open your val here:
<a class="underline hover:no-underline" href="https://${username}-${tempValName}.web.val.run">${username}/${tempValName}</a>.
</div>`);
}
writer.close();
})();
return new Response(readable, { headers: { "Content-Type": "text/html" } });
}
export default passwordAuth(main, { verifyPassword: verifyToken });