finish generate logic
This commit is contained in:
parent
e6cf993b6a
commit
2bfaf428d9
35
backend/server/dist/index.js
vendored
35
backend/server/dist/index.js
vendored
@ -100,7 +100,6 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
}));
|
||||
socket.on("createFile", (name) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
const id = `projects/${data.id}/${name}`;
|
||||
console.log("create file", id, name);
|
||||
fs_1.default.writeFile(path_1.default.join(dirName, id), "", function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
@ -143,14 +142,12 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
callback(newFiles.files);
|
||||
}));
|
||||
socket.on("createTerminal", ({ id }) => {
|
||||
console.log("creating terminal, id=" + id);
|
||||
const pty = (0, node_pty_1.spawn)(os_1.default.platform() === "win32" ? "cmd.exe" : "bash", [], {
|
||||
name: "xterm",
|
||||
cols: 100,
|
||||
cwd: path_1.default.join(dirName, "projects", data.id),
|
||||
});
|
||||
const onData = pty.onData((data) => {
|
||||
console.log(data);
|
||||
socket.emit("terminalResponse", {
|
||||
// data: Buffer.from(data, "utf-8").toString("base64"),
|
||||
data,
|
||||
@ -165,11 +162,7 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
};
|
||||
});
|
||||
socket.on("terminalData", (id, data) => {
|
||||
// socket.on("terminalData", (data: string) => {
|
||||
console.log(`Received data for terminal ${id}: ${data}`);
|
||||
// pty.write(data)
|
||||
if (!terminals[id]) {
|
||||
console.log("terminal not found");
|
||||
console.log("terminals", terminals);
|
||||
return;
|
||||
}
|
||||
@ -180,6 +173,34 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
console.log("Error writing to terminal", e);
|
||||
}
|
||||
});
|
||||
socket.on("generateCode", (fileName, code, line, instructions, callback) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
console.log("Generating code...");
|
||||
const res = yield fetch(`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_USER_ID}/ai/run/@cf/meta/llama-3-8b-instruct`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.CF_API_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: "You are an expert coding assistant. You read code from a file, and you suggest new code to add to the file. You may be given instructions on what to generate, which you should follow. You should generate code that is correct, efficient, and follows best practices. You should also generate code that is clear and easy to read.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: `The file is called ${fileName}. Here are my instructions on what to generate: ${instructions}. Suggest me code to insert at line ${line} in my file.
|
||||
|
||||
My code file content: ${code}
|
||||
|
||||
Return only the code, and nothing else. Do not include backticks.`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
const json = yield res.json();
|
||||
callback(json);
|
||||
}));
|
||||
socket.on("disconnect", () => {
|
||||
Object.entries(terminals).forEach((t) => {
|
||||
const { terminal, onData, onExit } = t[1];
|
||||
|
@ -116,7 +116,6 @@ io.on("connection", async (socket) => {
|
||||
|
||||
socket.on("createFile", async (name: string) => {
|
||||
const id = `projects/${data.id}/${name}`
|
||||
console.log("create file", id, name)
|
||||
|
||||
fs.writeFile(path.join(dirName, id), "", function (err) {
|
||||
if (err) throw err
|
||||
@ -170,7 +169,6 @@ io.on("connection", async (socket) => {
|
||||
})
|
||||
|
||||
socket.on("createTerminal", ({ id }: { id: string }) => {
|
||||
console.log("creating terminal, id=" + id)
|
||||
const pty = spawn(os.platform() === "win32" ? "cmd.exe" : "bash", [], {
|
||||
name: "xterm",
|
||||
cols: 100,
|
||||
@ -178,7 +176,6 @@ io.on("connection", async (socket) => {
|
||||
})
|
||||
|
||||
const onData = pty.onData((data) => {
|
||||
console.log(data)
|
||||
socket.emit("terminalResponse", {
|
||||
// data: Buffer.from(data, "utf-8").toString("base64"),
|
||||
data,
|
||||
@ -197,12 +194,7 @@ io.on("connection", async (socket) => {
|
||||
})
|
||||
|
||||
socket.on("terminalData", (id: string, data: string) => {
|
||||
// socket.on("terminalData", (data: string) => {
|
||||
console.log(`Received data for terminal ${id}: ${data}`)
|
||||
// pty.write(data)
|
||||
|
||||
if (!terminals[id]) {
|
||||
console.log("terminal not found")
|
||||
console.log("terminals", terminals)
|
||||
return
|
||||
}
|
||||
@ -214,6 +206,49 @@ io.on("connection", async (socket) => {
|
||||
}
|
||||
})
|
||||
|
||||
socket.on(
|
||||
"generateCode",
|
||||
async (
|
||||
fileName: string,
|
||||
code: string,
|
||||
line: number,
|
||||
instructions: string,
|
||||
callback
|
||||
) => {
|
||||
console.log("Generating code...")
|
||||
const res = await fetch(
|
||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_USER_ID}/ai/run/@cf/meta/llama-3-8b-instruct`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.CF_API_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are an expert coding assistant. You read code from a file, and you suggest new code to add to the file. You may be given instructions on what to generate, which you should follow. You should generate code that is correct, efficient, and follows best practices. You should also generate code that is clear and easy to read.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: `The file is called ${fileName}. Here are my instructions on what to generate: ${instructions}. Suggest me code to insert at line ${line} in my file.
|
||||
|
||||
My code file content: ${code}
|
||||
|
||||
Return only the code, and nothing else. Do not include backticks.`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
const json = await res.json()
|
||||
callback(json)
|
||||
}
|
||||
)
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
Object.entries(terminals).forEach((t) => {
|
||||
const { terminal, onData, onExit } = t[1]
|
||||
|
@ -1,33 +1,41 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { Input } from "../ui/input"
|
||||
import { Button } from "../ui/button"
|
||||
import { Check, Loader2, RotateCw, Sparkles, X } from "lucide-react"
|
||||
import { Socket } from "socket.io-client"
|
||||
import { Editor } from "@monaco-editor/react"
|
||||
// import monaco from "monaco-editor"
|
||||
|
||||
export default function GenerateInput({
|
||||
cancel,
|
||||
submit,
|
||||
socket,
|
||||
width,
|
||||
data,
|
||||
editor,
|
||||
onExpand,
|
||||
onAccept,
|
||||
}: {
|
||||
cancel: () => void
|
||||
submit: (input: string) => void
|
||||
socket: Socket
|
||||
width: number
|
||||
data: {
|
||||
fileName: string
|
||||
code: string
|
||||
line: number
|
||||
}
|
||||
editor: {
|
||||
language: string
|
||||
}
|
||||
onExpand: () => void
|
||||
onAccept: (code: string) => void
|
||||
}) {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const [code, setCode] = useState(`function add(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
const result = add(2, 3);
|
||||
console.log(result);`)
|
||||
const [code, setCode] = useState("")
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [loading, setLoading] = useState({
|
||||
generate: false,
|
||||
regenerate: false,
|
||||
})
|
||||
const [input, setInput] = useState("")
|
||||
const [currentPrompt, setCurrentPrompt] = useState("")
|
||||
|
||||
@ -37,16 +45,44 @@ export default function GenerateInput({
|
||||
}, 0)
|
||||
}, [])
|
||||
|
||||
const handleGenerate = async () => {
|
||||
setLoading(true)
|
||||
const handleGenerate = async ({
|
||||
regenerate = false,
|
||||
}: {
|
||||
regenerate?: boolean
|
||||
}) => {
|
||||
setLoading({ generate: !regenerate, regenerate })
|
||||
setCurrentPrompt(input)
|
||||
// const res = await generateCode()
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
socket.emit(
|
||||
"generateCode",
|
||||
data.fileName,
|
||||
data.code,
|
||||
data.line,
|
||||
regenerate ? currentPrompt : input,
|
||||
(res: {
|
||||
result: {
|
||||
response: string
|
||||
}
|
||||
success: boolean
|
||||
errors: any[]
|
||||
messages: any[]
|
||||
}) => {
|
||||
if (!res.success) {
|
||||
console.error(res.errors)
|
||||
return
|
||||
}
|
||||
|
||||
setCode(res.result.response)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (code) {
|
||||
setExpanded(true)
|
||||
onExpand()
|
||||
setLoading(false)
|
||||
setLoading({ generate: false, regenerate: false })
|
||||
}
|
||||
}, [code])
|
||||
|
||||
return (
|
||||
<div className="w-full pr-4 space-y-2">
|
||||
@ -64,10 +100,10 @@ export default function GenerateInput({
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={loading || input === ""}
|
||||
onClick={handleGenerate}
|
||||
disabled={loading.generate || loading.regenerate || input === ""}
|
||||
onClick={() => handleGenerate({})}
|
||||
>
|
||||
{loading ? (
|
||||
{loading.generate ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin h-3 w-3 mr-2" />
|
||||
Generating...
|
||||
@ -83,20 +119,55 @@ export default function GenerateInput({
|
||||
{expanded ? (
|
||||
<>
|
||||
<div className="rounded-md border border-muted-foreground w-full h-28 overflow-y-scroll p-2">
|
||||
<pre>{code}</pre>
|
||||
<Editor
|
||||
height="100%"
|
||||
defaultLanguage={editor.language}
|
||||
value={code}
|
||||
options={{
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
scrollBeyondLastLine: false,
|
||||
fontFamily: "var(--font-geist-mono)",
|
||||
domReadOnly: true,
|
||||
readOnly: true,
|
||||
lineNumbers: "off",
|
||||
glyphMargin: false,
|
||||
folding: false,
|
||||
// Undocumented see https://github.com/Microsoft/vscode/issues/30795#issuecomment-410998882
|
||||
lineDecorationsWidth: 0,
|
||||
lineNumbersMinChars: 0,
|
||||
}}
|
||||
theme="vs-dark"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<Button onClick={() => onAccept(code)} size="sm">
|
||||
<div className="flex space-x-2 font-sans">
|
||||
<Button
|
||||
disabled={loading.generate || loading.regenerate}
|
||||
onClick={() => onAccept(code)}
|
||||
size="sm"
|
||||
>
|
||||
<Check className="h-3 w-3 mr-2" />
|
||||
Accept
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleGenerate({ regenerate: true })}
|
||||
disabled={loading.generate || loading.regenerate}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="bg-transparent border-muted-foreground"
|
||||
>
|
||||
{loading.regenerate ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin h-3 w-3 mr-2" />
|
||||
Generating...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RotateCw className="h-3 w-3 mr-2" />
|
||||
Re-Generate
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import Editor, { BeforeMount, OnMount } from "@monaco-editor/react"
|
||||
import monaco from "monaco-editor"
|
||||
import { use, useEffect, useRef, useState } from "react"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
// import theme from "./theme.json"
|
||||
|
||||
import {
|
||||
@ -372,9 +372,16 @@ export default function CodeEditor({
|
||||
<div className="z-50 p-1" ref={generateWidgetRef}>
|
||||
{generate.show ? (
|
||||
<GenerateInput
|
||||
cancel={() => {}}
|
||||
submit={(str: string) => {}}
|
||||
socket={socket}
|
||||
width={generate.width - 90}
|
||||
data={{
|
||||
fileName: tabs.find((t) => t.id === activeId)?.name ?? "",
|
||||
code: editorRef.current?.getValue() ?? "",
|
||||
line: generate.line,
|
||||
}}
|
||||
editor={{
|
||||
language: editorLanguage,
|
||||
}}
|
||||
onExpand={() => {
|
||||
editorRef.current?.changeViewZones(function (changeAccessor) {
|
||||
changeAccessor.removeZone(generate.id)
|
||||
@ -391,13 +398,19 @@ export default function CodeEditor({
|
||||
})
|
||||
}}
|
||||
onAccept={(code: string) => {
|
||||
const line = generate.line
|
||||
setGenerate((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
show: !prev.show,
|
||||
}
|
||||
})
|
||||
console.log("accepted:", code)
|
||||
const file = editorRef.current?.getValue()
|
||||
|
||||
const lines = file?.split("\n") || []
|
||||
lines.splice(line - 1, 0, code)
|
||||
const updatedFile = lines.join("\n")
|
||||
editorRef.current?.setValue(updatedFile)
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -24,7 +24,7 @@ export async function updateSandbox(body: {
|
||||
name?: string
|
||||
visibility?: "public" | "private"
|
||||
}) {
|
||||
const res = await fetch("http://localhost:8787/api/sandbox", {
|
||||
await fetch("http://localhost:8787/api/sandbox", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -36,7 +36,7 @@ export async function updateSandbox(body: {
|
||||
}
|
||||
|
||||
export async function deleteSandbox(id: string) {
|
||||
const res = await fetch(`http://localhost:8787/api/sandbox?id=${id}`, {
|
||||
await fetch(`http://localhost:8787/api/sandbox?id=${id}`, {
|
||||
method: "DELETE",
|
||||
})
|
||||
|
||||
@ -62,7 +62,7 @@ export async function shareSandbox(sandboxId: string, email: string) {
|
||||
}
|
||||
|
||||
export async function unshareSandbox(sandboxId: string, userId: string) {
|
||||
const res = await fetch("http://localhost:8787/api/sandbox/share", {
|
||||
await fetch("http://localhost:8787/api/sandbox/share", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -72,29 +72,3 @@ export async function unshareSandbox(sandboxId: string, userId: string) {
|
||||
|
||||
revalidatePath(`/code/${sandboxId}`)
|
||||
}
|
||||
|
||||
export async function generateCode(code: string, line: number) {
|
||||
const res = await fetch(
|
||||
"https://api.cloudflare.com/client/v4/accounts/d18f2f848da38e37adc9a34eab3d5ae2/ai/run/@cf/meta/llama-3-8b-instruct",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.CF_API_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are an expert coding assistant who reads from an existing code file, and suggests code to add to the file.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: "", //todo
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user