|
1 | 1 | "use server"; |
2 | 2 |
|
3 | | -import client from "@/lib/prisma"; |
4 | | - |
5 | | -export async function shareApp({ |
6 | | - generatedCode, |
7 | | - prompt, |
8 | | - model, |
9 | | -}: { |
10 | | - generatedCode: string; |
11 | | - prompt: string; |
12 | | - model: string; |
13 | | -}) { |
14 | | - let newApp = await client.generatedApp.create({ |
| 3 | +import prisma from "@/lib/prisma"; |
| 4 | +import dedent from "dedent"; |
| 5 | +import { notFound } from "next/navigation"; |
| 6 | +import Together from "together-ai"; |
| 7 | +import { z } from "zod"; |
| 8 | + |
| 9 | +const together = new Together(); |
| 10 | + |
| 11 | +export async function createChat(prompt: string, model: string) { |
| 12 | + const res = await together.chat.completions.create({ |
| 13 | + model: "meta-llama/Llama-3.2-3B-Instruct-Turbo", |
| 14 | + // model: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", |
| 15 | + messages: [ |
| 16 | + { |
| 17 | + role: "system", |
| 18 | + content: |
| 19 | + "You are a chatbot helping the user create a simple app or script, and your current job is to create a succinct title, maximum 3-5 words, for the chat given their initial prompt. Please return only the title.", |
| 20 | + }, |
| 21 | + { |
| 22 | + role: "user", |
| 23 | + content: prompt, |
| 24 | + }, |
| 25 | + ], |
| 26 | + }); |
| 27 | + const title = res.choices[0].message?.content || prompt; |
| 28 | + |
| 29 | + const chat = await prisma.chat.create({ |
15 | 30 | data: { |
16 | | - code: generatedCode, |
17 | | - model: model, |
18 | | - prompt: prompt, |
| 31 | + model, |
| 32 | + title, |
| 33 | + messages: { |
| 34 | + createMany: { |
| 35 | + data: [ |
| 36 | + { role: "system", content: systemPrompt, position: 0 }, |
| 37 | + { role: "user", content: prompt, position: 1 }, |
| 38 | + ], |
| 39 | + }, |
| 40 | + }, |
| 41 | + }, |
| 42 | + include: { |
| 43 | + messages: true, |
19 | 44 | }, |
20 | 45 | }); |
21 | 46 |
|
22 | | - return newApp.id; |
| 47 | + const lastMessage = chat.messages.at(-1); |
| 48 | + if (!lastMessage) throw new Error("No new message"); |
| 49 | + |
| 50 | + return { chatId: chat.id, lastMessageId: lastMessage.id }; |
23 | 51 | } |
| 52 | + |
| 53 | +export async function createMessage( |
| 54 | + chatId: string, |
| 55 | + text: string, |
| 56 | + role: "assistant" | "user", |
| 57 | +) { |
| 58 | + const chat = await prisma.chat.findUnique({ |
| 59 | + where: { id: chatId }, |
| 60 | + include: { messages: true }, |
| 61 | + }); |
| 62 | + if (!chat) notFound(); |
| 63 | + |
| 64 | + const maxPosition = Math.max(...chat.messages.map((m) => m.position)); |
| 65 | + |
| 66 | + const newMessage = await prisma.message.create({ |
| 67 | + data: { |
| 68 | + role, |
| 69 | + content: text, |
| 70 | + position: maxPosition + 1, |
| 71 | + chatId, |
| 72 | + }, |
| 73 | + }); |
| 74 | + |
| 75 | + return newMessage; |
| 76 | +} |
| 77 | + |
| 78 | +export async function streamNextCompletion(messageId: string, model: string) { |
| 79 | + console.log(1); |
| 80 | + const message = await prisma.message.findUnique({ where: { id: messageId } }); |
| 81 | + console.log(2); |
| 82 | + if (!message) notFound(); |
| 83 | + console.log(3); |
| 84 | + |
| 85 | + const messagesRes = await prisma.message.findMany({ |
| 86 | + where: { chatId: message.chatId, position: { lte: message.position } }, |
| 87 | + orderBy: { position: "asc" }, |
| 88 | + }); |
| 89 | + |
| 90 | + const messages = z |
| 91 | + .array( |
| 92 | + z.object({ |
| 93 | + role: z.enum(["system", "user", "assistant"]), |
| 94 | + content: z.string(), |
| 95 | + }), |
| 96 | + ) |
| 97 | + .parse(messagesRes); |
| 98 | + |
| 99 | + console.log(4); |
| 100 | + const res = await together.chat.completions.create({ |
| 101 | + model, |
| 102 | + messages: messages.map((m) => ({ role: m.role, content: m.content })), |
| 103 | + stream: true, |
| 104 | + }); |
| 105 | + |
| 106 | + console.log(5); |
| 107 | + return res.toReadableStream(); |
| 108 | +} |
| 109 | + |
| 110 | +export async function getNextCompletionStreamPromise( |
| 111 | + messageId: string, |
| 112 | + model: string, |
| 113 | +) { |
| 114 | + const message = await prisma.message.findUnique({ where: { id: messageId } }); |
| 115 | + if (!message) notFound(); |
| 116 | + |
| 117 | + const messagesRes = await prisma.message.findMany({ |
| 118 | + where: { chatId: message.chatId, position: { lte: message.position } }, |
| 119 | + orderBy: { position: "asc" }, |
| 120 | + }); |
| 121 | + |
| 122 | + const messages = z |
| 123 | + .array( |
| 124 | + z.object({ |
| 125 | + role: z.enum(["system", "user", "assistant"]), |
| 126 | + content: z.string(), |
| 127 | + }), |
| 128 | + ) |
| 129 | + .parse(messagesRes); |
| 130 | + |
| 131 | + return { |
| 132 | + streamPromise: new Promise<ReadableStream>(async (resolve) => { |
| 133 | + const res = await together.chat.completions.create({ |
| 134 | + model, |
| 135 | + messages: messages.map((m) => ({ role: m.role, content: m.content })), |
| 136 | + stream: true, |
| 137 | + }); |
| 138 | + |
| 139 | + resolve(res.toReadableStream()); |
| 140 | + }), |
| 141 | + }; |
| 142 | +} |
| 143 | + |
| 144 | +const systemPrompt = dedent` |
| 145 | + You are an expert software developer who knows three technologies: React, Python, and Node.js. |
| 146 | +
|
| 147 | + You will be given a prompt for a simple app, and your task is to return a single file with the code for that app. |
| 148 | +
|
| 149 | + You should first decide what the appropriate technology is for the prompt. If the prompt sounds like a web app where a user interface would be appropiate, return a React component. Otherwise, if the prompt could be addressed with a simple script, use Python, unless Node is explicitly specified. |
| 150 | +
|
| 151 | + Explain your work. The first codefence should include the main app. It should also include both the language (either tsx, ts, or python) followed by a sensible filename for the code. Use this format: \`\`\`tsx{filename=calculator.tsx}. |
| 152 | +
|
| 153 | + Here are some more details: |
| 154 | + |
| 155 | + - If you're writing a React component, make sure you don't use any external dependencies, and export a single React component as the default export. Use TypeScript as the language, with "tsx" for any code fences. You can also use Tailwind classes for styling, making sure not to use arbitrary values. |
| 156 | +
|
| 157 | + - If you're writing a Python or Node script, make sure running the script executes the code you wrote and prints some output to the console. |
| 158 | +
|
| 159 | +`; |
0 commit comments