From 13040b61929c6f13dc266f82760b57f11abb86f3 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:59:21 +1000 Subject: [PATCH 01/43] Configure CORS in planning server --- .../packages/planning-server/src/actions.ts | 143 +++++++++++++ .../packages/planning-server/src/deps.ts | 2 + .../packages/planning-server/src/index.ts | 193 +----------------- .../packages/planning-server/src/server.ts | 90 ++++++++ 4 files changed, 237 insertions(+), 191 deletions(-) create mode 100644 typescript/packages/planning-server/src/actions.ts create mode 100644 typescript/packages/planning-server/src/server.ts diff --git a/typescript/packages/planning-server/src/actions.ts b/typescript/packages/planning-server/src/actions.ts new file mode 100644 index 000000000..5b1e770d6 --- /dev/null +++ b/typescript/packages/planning-server/src/actions.ts @@ -0,0 +1,143 @@ +import { CoreAssistantMessage, CoreMessage, CoreTool } from "npm:ai"; +import { + ConversationThread, + InMemoryConversationThreadManager, +} from "./conversation.ts"; +import { ask } from "./anthropic.ts"; + +const cache: Record = {}; +const threadManager = new InMemoryConversationThreadManager(); + +type CreateConversationThreadResponse = { + type: "success"; + threadId: string; + output: string; + assistantResponse: CoreAssistantMessage; + conversation: CoreMessage[]; +}; + +type AppendToConversationThreadResponse = { + type: "success"; + threadId: string; + output: string; + assistantResponse: CoreAssistantMessage; + conversation: CoreMessage[]; +}; + +type ConversationThreadResponse = + | CreateConversationThreadResponse + | AppendToConversationThreadResponse; + +type ErrorResponse = { + type: "error"; + error: string; +}; + +export async function handleCreateConversationThread( + system: string, + message: string, + activeTools: CoreTool[] +): Promise { + const cacheKey = `${system}:${message}`; + + if (cache[cacheKey]) { + console.log( + "Cache hit!", + (cacheKey.slice(0, 20) + "..." + cacheKey.slice(-20)).replaceAll("\n", "") + ); + return cache[cacheKey]; + } + + const thread = threadManager.create(system, message, activeTools); + const result = await processConversationThread(thread); + if (result.type === "error") { + throw new Error(result.error); + } + + if (result.assistantResponse) { + threadManager.update(thread.id, [result.assistantResponse]); + } + + // cache[cacheKey] = result; + + return result; +} + +export async function handleAppendToConversationThread( + threadId: string, + message?: string +): Promise { + const thread = threadManager.get(threadId); + if (!thread) { + throw new Error("Thread not found"); + } + + if (message) { + threadManager.update(threadId, [ + { + role: "user", + content: message, + }, + ]); + } + + const result = await processConversationThread(thread); + if (result.type === "error") { + return result; + } + + // Update the thread with the assistant's response + if (result.assistantResponse) { + threadManager.update(threadId, [result.assistantResponse]); + } + + return result; +} + +type ProcessConversationThreadResult = + | { + type: "success"; + threadId: string; + output: string; + assistantResponse: CoreAssistantMessage; + conversation: CoreMessage[]; + } + | { type: "error"; error: string }; + +async function processConversationThread( + thread: ConversationThread +): Promise { + console.log("Thread", thread); + + const result = await ask( + thread.conversation, + thread.system, + thread.activeTools + ); + if (!result) { + return { type: "error", error: "No response from Anthropic" }; + } + + // Find the new assistant's response (it should be the last message) + const assistantResponse = result[result.length - 1]; + if (assistantResponse.role !== "assistant") { + return { type: "error", error: "No assistant response found" }; + } + + if (Array.isArray(assistantResponse.content)) { + assistantResponse.content = assistantResponse.content + .filter((msg) => msg.type == "text") + .map((msg) => msg.text) + .join(" "); + } + + const output = assistantResponse.content; + console.log("Output=", output); + return { + type: "success", + threadId: thread.id, + output, + assistantResponse, + conversation: result, + }; +} diff --git a/typescript/packages/planning-server/src/deps.ts b/typescript/packages/planning-server/src/deps.ts index 7d28ce8d0..2cf247807 100644 --- a/typescript/packages/planning-server/src/deps.ts +++ b/typescript/packages/planning-server/src/deps.ts @@ -2,6 +2,8 @@ export { default as datascript } from "npm:datascript"; import { config } from "https://deno.land/x/dotenv/mod.ts"; export { serve } from "https://deno.land/std@0.140.0/http/server.ts"; +export { Application, Router } from "https://deno.land/x/oak/mod.ts"; +export { oakCors } from "https://deno.land/x/cors/mod.ts"; export * as ai from "npm:ai"; export { anthropic } from "npm:@ai-sdk/anthropic"; diff --git a/typescript/packages/planning-server/src/index.ts b/typescript/packages/planning-server/src/index.ts index 11a9d79fc..c415f6560 100644 --- a/typescript/packages/planning-server/src/index.ts +++ b/typescript/packages/planning-server/src/index.ts @@ -1,192 +1,3 @@ -import { ask } from "./anthropic.ts"; -import { serve } from "./deps.ts"; -import { - InMemoryConversationThreadManager, - ConversationThread, -} from "./conversation.ts"; -import { CoreMessage, CoreTool } from "npm:ai"; -import { CoreAssistantMessage } from "npm:ai"; +import { start } from "./server.ts"; -const threadManager = new InMemoryConversationThreadManager(); - -type CreateConversationThreadRequest = { - action: "create"; - message: string; - system: string; - activeTools: CoreTool[]; -}; - -type AppendToConversationThreadRequest = { - action: "append"; - threadId: string; - message?: string; -}; - -type ConversationThreadRequest = - | CreateConversationThreadRequest - | AppendToConversationThreadRequest; - -const handler = async (request: Request): Promise => { - if (request.method === "POST") { - try { - const body: ConversationThreadRequest = await request.json(); - const { action } = body; - - switch (action) { - case "create": { - const { message, system, activeTools } = body; - return handleCreateConversationThread(system, message, activeTools); - } - case "append": { - const { threadId, message } = body; - return handleAppendToConversationThread(threadId, message); - } - default: - return new Response(JSON.stringify({ error: "Invalid action" }), { - status: 400, - headers: { "Content-Type": "application/json" }, - }); - } - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - status: 400, - headers: { "Content-Type": "application/json" }, - }); - } - } else { - return new Response("Please send a POST request", { status: 405 }); - } -}; - -const cache: Record = {}; - -async function handleCreateConversationThread( - system: string, - message: string, - activeTools: CoreTool[] -): Promise { - const cacheKey = `${system}:${message}`; - - if (cache[cacheKey]) { - console.log( - "Cache hit!", - (cacheKey.slice(0, 20) + "..." + cacheKey.slice(-20)).replaceAll("\n", "") - ); - return new Response(JSON.stringify(cache[cacheKey]), { - headers: { "Content-Type": "application/json" }, - }); - } - - const thread = threadManager.create(system, message, activeTools); - const result = await processConversationThread(thread); - if (result.type === "error") { - return new Response(JSON.stringify(result), { - status: 400, - headers: { "Content-Type": "application/json" }, - }); - } - - if (result.assistantResponse) { - threadManager.update(thread.id, [result.assistantResponse]); - } - - // cache[cacheKey] = result; - - return new Response(JSON.stringify(result), { - headers: { "Content-Type": "application/json" }, - }); -} - -async function handleAppendToConversationThread( - threadId: string, - message?: string -): Promise { - const thread = threadManager.get(threadId); - if (!thread) { - return new Response(JSON.stringify({ error: "Thread not found" }), { - status: 404, - headers: { "Content-Type": "application/json" }, - }); - } - - if (message) { - threadManager.update(threadId, [ - { - role: "user", - content: message, - }, - ]); - } - - const result = await processConversationThread(thread); - if (result.type === "error") { - return new Response(JSON.stringify(result), { - status: 400, - headers: { "Content-Type": "application/json" }, - }); - } - - // Update the thread with the assistant's response - if (result.assistantResponse) { - threadManager.update(threadId, [result.assistantResponse]); - } - - // Remove the assistantResponse from the result before sending it to the client - const { assistantResponse, ...responseToClient } = result; - - return new Response(JSON.stringify(responseToClient), { - headers: { "Content-Type": "application/json" }, - }); -} - -type ProcessConversationThreadResult = - | { - type: "success"; - threadId: string; - output: string; - assistantResponse: CoreAssistantMessage; - conversation: CoreMessage[]; - } - | { type: "error"; error: string }; - -async function processConversationThread( - thread: ConversationThread -): Promise { - console.log("Thread", thread); - - const result = await ask( - thread.conversation, - thread.system, - thread.activeTools - ); - if (!result) { - return { type: "error", error: "No response from Anthropic" }; - } - - // Find the new assistant's response (it should be the last message) - const assistantResponse = result[result.length - 1]; - if (assistantResponse.role !== "assistant") { - return { type: "error", error: "No assistant response found" }; - } - - if (Array.isArray(assistantResponse.content)) { - assistantResponse.content = assistantResponse.content - .filter((msg) => msg.type == "text") - .map((msg) => msg.text) - .join(" "); - } - - const output = assistantResponse.content; - console.log("Output=", output); - return { - type: "success", - threadId: thread.id, - output, - assistantResponse, - conversation: result, - }; -} - -const port = Deno.env.get("PORT") || "8000"; -console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`); -await serve(handler, { port: parseInt(port) }); +start(); diff --git a/typescript/packages/planning-server/src/server.ts b/typescript/packages/planning-server/src/server.ts new file mode 100644 index 000000000..29712b544 --- /dev/null +++ b/typescript/packages/planning-server/src/server.ts @@ -0,0 +1,90 @@ +import { CoreTool } from "npm:ai"; +import { Application, Router } from "./deps.ts"; +import { oakCors } from "./deps.ts"; +import { + handleAppendToConversationThread, + handleCreateConversationThread, +} from "./actions.ts"; + +type CreateConversationThreadRequest = { + action: "create"; + message: string; + system: string; + activeTools: CoreTool[]; +}; + +type AppendToConversationThreadRequest = { + action: "append"; + threadId: string; + message?: string; +}; + +type ConversationThreadRequest = + | CreateConversationThreadRequest + | AppendToConversationThreadRequest; + +export async function start() { + const app = new Application(); + + // Enabling CORS for port 5173 on localhost using oakCors + // make sure to initialize oakCors before the routers + app.use( + oakCors({ + origin: "http://localhost:8080", + optionsSuccessStatus: 200, + methods: "POST, OPTIONS", + }) + ); + + const router = new Router(); + + router.post("/", async (context) => { + const request = context.request; + if (request.method === "POST") { + try { + const body: ConversationThreadRequest = await request.body.json(); + const { action } = body; + + switch (action) { + case "create": { + const { message, system, activeTools } = body; + const result = await handleCreateConversationThread( + system, + message, + activeTools + ); + context.response.status = 200; + context.response.body = result; + break; + } + case "append": { + const { threadId, message } = body; + const result = await handleAppendToConversationThread( + threadId, + message + ); + context.response.status = 200; + context.response.body = result; + break; + } + default: + context.response.status = 400; + context.response.body = { error: "Invalid action" }; + } + } catch (error) { + context.response.status = 400; + context.response.body = { error: error.message }; + } + } else { + context.response.status = 405; + context.response.body = { error: "Method not allowed" }; + } + }); + + app.use(router.routes()); + app.use(router.allowedMethods()); + + const port = Number(Deno.env.get("PORT") || 8000); + console.log(`Listening on port ${port}`); + await app.listen({ port }); +} From 8316bc0b17f825d9fe3f5789af8010cd93602e49 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:59:37 +1000 Subject: [PATCH 02/43] Create gemcraft leptos project --- Cargo.lock | 710 ++++++++++++++++++++++++++++++- Cargo.toml | 2 +- rust/gemcraft-leptos/Cargo.toml | 11 + rust/gemcraft-leptos/Trunk.toml | 5 + rust/gemcraft-leptos/index.html | 5 + rust/gemcraft-leptos/src/main.rs | 131 ++++++ 6 files changed, 852 insertions(+), 12 deletions(-) create mode 100644 rust/gemcraft-leptos/Cargo.toml create mode 100644 rust/gemcraft-leptos/Trunk.toml create mode 100644 rust/gemcraft-leptos/index.html create mode 100644 rust/gemcraft-leptos/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 7cd6b7a7a..fdb51bfee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,6 +164,17 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "async-trait" version = "0.1.80" @@ -181,6 +192,36 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attribute-derive" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1ee502851995027b06f99f5ffbeffa1406b38d0b318a1ebfa469332c6cbafd" +dependencies = [ + "attribute-derive-macro", + "derive-where", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3601467f634cfe36c4780ca9c75dea9a5b34529c1f2810676a337e7e0997f954" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn 2.0.61", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -209,7 +250,7 @@ dependencies = [ "axum-macros", "bytes", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -243,7 +284,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "mime", @@ -385,6 +426,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" + [[package]] name = "cap-fs-ext" version = "3.1.0" @@ -479,6 +526,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.7" @@ -525,18 +599,77 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "collection_literals" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" + [[package]] name = "colorchoice" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "convert_case", + "lazy_static", + "nom", + "pathdiff", + "serde", + "toml", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -740,6 +873,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -918,6 +1057,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -1006,6 +1156,12 @@ dependencies = [ "text_lines", ] +[[package]] +name = "drain_filter_polyfill" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" + [[package]] name = "either" version = "1.12.0" @@ -1242,6 +1398,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "gemcraft-leptos" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "leptos", + "wasm-bindgen-futures", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1259,8 +1424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1274,6 +1441,40 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 0.2.12", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "h2" version = "0.4.5" @@ -1285,7 +1486,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -1293,6 +1494,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -1353,6 +1564,26 @@ dependencies = [ "triomphe", ] +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.1.0" @@ -1371,7 +1602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http", + "http 1.1.0", ] [[package]] @@ -1382,7 +1613,7 @@ checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", "futures-core", - "http", + "http 1.1.0", "http-body", "pin-project-lite", ] @@ -1409,7 +1640,7 @@ dependencies = [ "futures-channel", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "httparse", "httpdate", @@ -1427,7 +1658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", - "http", + "http 1.1.0", "hyper", "hyper-util", "rustls", @@ -1446,7 +1677,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", + "http 1.1.0", "http-body", "hyper", "pin-project-lite", @@ -1536,6 +1767,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + +[[package]] +name = "inventory" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" + [[package]] name = "io-extras" version = "0.18.2" @@ -1658,6 +1901,153 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "leptos" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5fae88b21265cbb847c891d7cf660e284a1282da15459691992be9358e906fb" +dependencies = [ + "cfg-if", + "leptos_config", + "leptos_dom", + "leptos_macro", + "leptos_reactive", + "leptos_server", + "server_fn", + "tracing", + "typed-builder", + "typed-builder-macro", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_config" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec33b6f994829469ba7c62bfd5fb572a639071d0de715a41c2aa0df86301a4fa" +dependencies = [ + "config", + "regex", + "serde", + "thiserror", + "typed-builder", +] + +[[package]] +name = "leptos_dom" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867d2afc153cc0f1d6f775872d5dfc409385f4d8544831ee45f720d88f363e6b" +dependencies = [ + "async-recursion", + "cfg-if", + "drain_filter_polyfill", + "futures", + "getrandom", + "html-escape", + "indexmap", + "itertools", + "js-sys", + "leptos_reactive", + "once_cell", + "pad-adapter", + "paste", + "rustc-hash", + "serde", + "serde_json", + "server_fn", + "smallvec", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_hot_reload" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5ce56051f2eff2c4736b7a2056177e67be19597b767ff72fbab20917a7422d" +dependencies = [ + "anyhow", + "camino", + "indexmap", + "parking_lot 0.12.3", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.61", + "walkdir", +] + +[[package]] +name = "leptos_macro" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "019016cc0193831660a7794aa046e4c01617d97ccb2f403a5c10b21744391a71" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case", + "html-escape", + "itertools", + "leptos_hot_reload", + "prettyplease", + "proc-macro-error", + "proc-macro2", + "quote", + "rstml", + "server_fn_macro", + "syn 2.0.61", + "tracing", + "uuid", +] + +[[package]] +name = "leptos_reactive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076064e3c84e3aa12d4bad283e82ba5968675f5f9714d04a5c38f169cd4f26b5" +dependencies = [ + "base64 0.22.1", + "cfg-if", + "futures", + "indexmap", + "js-sys", + "oco_ref", + "paste", + "pin-project", + "rustc-hash", + "self_cell", + "serde", + "serde-wasm-bindgen", + "serde_json", + "slotmap", + "thiserror", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_server" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603064a2d7ac46dba4b3ed5397a475076f9738918dd605670869dfe877d5966c" +dependencies = [ + "inventory", + "lazy_static", + "leptos_macro", + "leptos_reactive", + "serde", + "server_fn", + "thiserror", + "tracing", +] + [[package]] name = "libc" version = "0.2.155" @@ -1711,6 +2101,29 @@ dependencies = [ "libc", ] +[[package]] +name = "manyhow" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91ea592d76c0b6471965708ccff7e6a5d277f676b90ab31f4d3f3fc77fade64" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "manyhow-macros" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64621e2c08f2576e4194ea8be11daf24ac01249a4f53cd8befcbb7077120ead" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1772,6 +2185,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.3" @@ -1807,7 +2226,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 1.1.0", "httparse", "memchr", "mime", @@ -1821,6 +2240,16 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1891,6 +2320,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "oco_ref" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51ebcefb2f0b9a5e0bea115532c8ae4215d1b01eff176d0f4ba4192895c2708" +dependencies = [ + "serde", + "thiserror", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1909,6 +2348,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "pad-adapter" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63" + [[package]] name = "parking_lot" version = "0.11.2" @@ -2082,6 +2527,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.61", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2106,6 +2561,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + [[package]] name = "proc-macro2" version = "1.0.82" @@ -2115,6 +2581,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", + "version_check", + "yansi", +] + [[package]] name = "psm" version = "0.1.21" @@ -2133,6 +2612,29 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quote-use" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e96ac59974192a2fa6ee55a41211cf1385c5b2a8636a4c3068b3b3dd599ece" +dependencies = [ + "quote", + "quote-use-macros", +] + +[[package]] +name = "quote-use-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c57308e9dde4d7be9af804f6deeaa9951e1de1d5ffce6142eb964750109f7e" +dependencies = [ + "derive-where", + "proc-macro-utils", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "radium" version = "0.7.0" @@ -2309,7 +2811,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -2356,6 +2858,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rstml" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe542870b8f59dd45ad11d382e5339c9a1047cde059be136a7016095bbdefa77" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.61", + "syn_derive", + "thiserror", +] + [[package]] name = "rust-embed" version = "8.4.0" @@ -2506,6 +3022,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "semver" version = "0.9.0" @@ -2527,6 +3049,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + [[package]] name = "serde" version = "1.0.201" @@ -2536,6 +3067,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.201" @@ -2569,6 +3111,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_spanned" version = "0.6.6" @@ -2590,6 +3143,59 @@ dependencies = [ "serde", ] +[[package]] +name = "server_fn" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06e6e5467a2cd93ce1accfdfd8b859404f0b3b2041131ffd774fabf666b8219" +dependencies = [ + "bytes", + "ciborium", + "const_format", + "dashmap", + "futures", + "gloo-net", + "http 1.1.0", + "js-sys", + "once_cell", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "thiserror", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c216bb1c1ac890151397643c663c875a1836adf0b269be4e389cb1b48c173c" +dependencies = [ + "const_format", + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.61", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00783df297ec85ea605779f2fef9cbec98981dffe2e01e1a9845c102ee1f1ae6" +dependencies = [ + "server_fn_macro", + "syn 2.0.61", +] + [[package]] name = "sha-1" version = "0.10.0" @@ -2669,6 +3275,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "serde", + "version_check", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -3238,6 +3854,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -3485,7 +4113,7 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags 2.5.0", "bytes", - "http", + "http 1.1.0", "http-body", "http-body-util", "pin-project-lite", @@ -3614,6 +4242,26 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typed-builder" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "typenum" version = "1.17.0" @@ -3662,6 +4310,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.12" @@ -3746,6 +4400,12 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "utf8parse" version = "0.2.2" @@ -3799,6 +4459,9 @@ name = "uuid" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] [[package]] name = "valuable" @@ -3982,6 +4645,19 @@ dependencies = [ "wasmparser 0.208.1", ] +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" version = "0.202.0" @@ -4865,6 +5541,12 @@ dependencies = [ "tap", ] +[[package]] +name = "xxhash-rust" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63658493314859b4dfdf3fb8c1defd61587839def09582db50b8a4e93afca6bb" + [[package]] name = "yaml-rust2" version = "0.8.1" @@ -4876,6 +5558,12 @@ dependencies = [ "hashlink", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.34" diff --git a/Cargo.toml b/Cargo.toml index f7a0160b6..abbfe5318 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "rust/usuba-compat", "rust/usuba-bundle", "rust/verification-svc" -] +, "rust/gemcraft-leptos"] # See: https://github.com/rust-lang/rust/issues/90148#issuecomment-949194352 resolver = "2" diff --git a/rust/gemcraft-leptos/Cargo.toml b/rust/gemcraft-leptos/Cargo.toml new file mode 100644 index 000000000..6b596d4c1 --- /dev/null +++ b/rust/gemcraft-leptos/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "gemcraft-leptos" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +console_error_panic_hook = "0.1.7" +leptos = { version = "0.6.12", features = ["csr", "nightly"] } +wasm-bindgen-futures = "0.4.42" diff --git a/rust/gemcraft-leptos/Trunk.toml b/rust/gemcraft-leptos/Trunk.toml new file mode 100644 index 000000000..65bbd0e2f --- /dev/null +++ b/rust/gemcraft-leptos/Trunk.toml @@ -0,0 +1,5 @@ +[serve] +# The address to serve on +address = "127.0.0.1" +# The port to serve on +port = 8080 diff --git a/rust/gemcraft-leptos/index.html b/rust/gemcraft-leptos/index.html new file mode 100644 index 000000000..a4acdc47a --- /dev/null +++ b/rust/gemcraft-leptos/index.html @@ -0,0 +1,5 @@ + + + + + diff --git a/rust/gemcraft-leptos/src/main.rs b/rust/gemcraft-leptos/src/main.rs new file mode 100644 index 000000000..72ebc5adc --- /dev/null +++ b/rust/gemcraft-leptos/src/main.rs @@ -0,0 +1,131 @@ +use leptos::*; +use logging::log; +use wasm_bindgen::{JsCast, JsValue}; +use wasm_bindgen_futures::JsFuture; +use web_sys::{Request, RequestInit, Response}; + +fn main() { + console_error_panic_hook::set_once(); + + mount_to_body(|| view! { }) +} + +#[component] +fn App() -> impl IntoView { + let (count, set_count) = create_signal(0); + + view! { + + + } +} + +#[component] +pub fn FormWithPreview() -> impl IntoView { + let (image_url, set_image_url) = create_signal(String::new()); + let (description, set_description) = create_signal(String::new()); + let (json_data, set_json_data) = create_signal(String::from("{}")); + + let generate_preview = create_action(move |_| { + async move { + // LLM URL: + // window.location.protocol + "//" + window.location.host + "/api/v0/llm"; + let win = window(); + + let mut opts = RequestInit::new(); + opts.method("POST"); + // set body as JSON string + opts.body(Some(&JsValue::from_str( + r#"{"action": "create", "message": "hello"}"#, + ))); + opts.co + + let request = Request::new_with_str_and_init("http://localhost:8000", &opts).unwrap(); + + let resp_value = JsFuture::from(win.fetch_with_request(&request)) + .await + .expect("failed to fetch"); + let resp: Response = resp_value.dyn_into().unwrap(); + + let json = JsFuture::from(resp.json().unwrap()) + .await + .expect("failed to get response text"); + } + }); + + let on_submit = move |ev: web_sys::SubmitEvent| { + ev.prevent_default(); + // Handle form submission here + log!("Form submitted"); + log!("Description: {}", description.get()); + log!("JSON Data: {}", json_data.get()); + }; + + view! { +
+
+ + Preview + +
+ +
+ + +
+ +
+ + +
+ + +
+ } +} + +fn event_target_value(ev: &web_sys::Event) -> String { + let target: web_sys::EventTarget = ev.target().unwrap(); + let target: web_sys::HtmlTextAreaElement = target.dyn_into().unwrap(); + target.value() +} From 77c8468a7bc53520be444d140886992f8f94496d Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:10:02 +1000 Subject: [PATCH 03/43] Deserialize response to struct --- Cargo.lock | 4 ++++ rust/gemcraft-leptos/Cargo.toml | 4 ++++ rust/gemcraft-leptos/src/main.rs | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fdb51bfee..768c0b293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1404,6 +1404,10 @@ version = "0.1.0" dependencies = [ "console_error_panic_hook", "leptos", + "serde", + "serde-wasm-bindgen", + "serde_json", + "wasm-bindgen", "wasm-bindgen-futures", ] diff --git a/rust/gemcraft-leptos/Cargo.toml b/rust/gemcraft-leptos/Cargo.toml index 6b596d4c1..02ff86fb9 100644 --- a/rust/gemcraft-leptos/Cargo.toml +++ b/rust/gemcraft-leptos/Cargo.toml @@ -8,4 +8,8 @@ edition = "2021" [dependencies] console_error_panic_hook = "0.1.7" leptos = { version = "0.6.12", features = ["csr", "nightly"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde-wasm-bindgen = "0.6" +wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4.42" diff --git a/rust/gemcraft-leptos/src/main.rs b/rust/gemcraft-leptos/src/main.rs index 72ebc5adc..cb7e2db3d 100644 --- a/rust/gemcraft-leptos/src/main.rs +++ b/rust/gemcraft-leptos/src/main.rs @@ -1,5 +1,7 @@ use leptos::*; use logging::log; +use serde::{Deserialize, Serialize}; +use serde_wasm_bindgen; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::JsFuture; use web_sys::{Request, RequestInit, Response}; @@ -29,6 +31,15 @@ fn App() -> impl IntoView { } } +#[derive(Deserialize, Serialize, Debug)] +struct LlmResponse { + #[serde(rename = "type")] + r#type: String, + #[serde(rename = "threadId")] + thread_id: String, + output: String, +} + #[component] pub fn FormWithPreview() -> impl IntoView { let (image_url, set_image_url) = create_signal(String::new()); @@ -47,7 +58,6 @@ pub fn FormWithPreview() -> impl IntoView { opts.body(Some(&JsValue::from_str( r#"{"action": "create", "message": "hello"}"#, ))); - opts.co let request = Request::new_with_str_and_init("http://localhost:8000", &opts).unwrap(); @@ -59,6 +69,13 @@ pub fn FormWithPreview() -> impl IntoView { let json = JsFuture::from(resp.json().unwrap()) .await .expect("failed to get response text"); + + let llm_response: LlmResponse = + serde_wasm_bindgen::from_value(json).map_err(|_| "Failed to deserialize JSON")?; + + log!("Response: {:?}", llm_response); + + Ok::(llm_response) } }); From 1ef91642ccf4cbda4033be7a692466df6ba4f2ab Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:37:36 +1000 Subject: [PATCH 04/43] Checkpoint: CRUD for the gem data + classification with central state --- Cargo.lock | 2 + rust/gemcraft-leptos/Cargo.toml | 2 + rust/gemcraft-leptos/index.html | 54 ++++- rust/gemcraft-leptos/src/extract.rs | 9 + rust/gemcraft-leptos/src/main.rs | 304 ++++++++++++++++++++-------- 5 files changed, 291 insertions(+), 80 deletions(-) create mode 100644 rust/gemcraft-leptos/src/extract.rs diff --git a/Cargo.lock b/Cargo.lock index 768c0b293..e3274e3c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1404,9 +1404,11 @@ version = "0.1.0" dependencies = [ "console_error_panic_hook", "leptos", + "regex", "serde", "serde-wasm-bindgen", "serde_json", + "uuid", "wasm-bindgen", "wasm-bindgen-futures", ] diff --git a/rust/gemcraft-leptos/Cargo.toml b/rust/gemcraft-leptos/Cargo.toml index 02ff86fb9..5f18b1636 100644 --- a/rust/gemcraft-leptos/Cargo.toml +++ b/rust/gemcraft-leptos/Cargo.toml @@ -13,3 +13,5 @@ serde_json = "1.0" serde-wasm-bindgen = "0.6" wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4.42" +regex = "1.5.4" +uuid = { version = "1.3", features = ["v4"] } diff --git a/rust/gemcraft-leptos/index.html b/rust/gemcraft-leptos/index.html index a4acdc47a..98de606d2 100644 --- a/rust/gemcraft-leptos/index.html +++ b/rust/gemcraft-leptos/index.html @@ -1,5 +1,57 @@ - + + + diff --git a/rust/gemcraft-leptos/src/extract.rs b/rust/gemcraft-leptos/src/extract.rs new file mode 100644 index 000000000..6e7498468 --- /dev/null +++ b/rust/gemcraft-leptos/src/extract.rs @@ -0,0 +1,9 @@ +use regex::Regex; + +pub fn extract_code_blocks_from_markdown(markdown: &str, block_type: &str) -> Vec { + let pattern = format!(r"```{}\s*([\s\S]*?)\s*```", regex::escape(block_type)); + let re = Regex::new(&pattern).unwrap(); + re.captures_iter(markdown) + .map(|cap| cap[1].to_string()) + .collect() +} \ No newline at end of file diff --git a/rust/gemcraft-leptos/src/main.rs b/rust/gemcraft-leptos/src/main.rs index cb7e2db3d..946eaaa4d 100644 --- a/rust/gemcraft-leptos/src/main.rs +++ b/rust/gemcraft-leptos/src/main.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; +use uuid::Uuid; use leptos::*; use logging::log; use serde::{Deserialize, Serialize}; @@ -6,31 +8,71 @@ use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::JsFuture; use web_sys::{Request, RequestInit, Response}; +mod extract; +use extract::extract_code_blocks_from_markdown; + +const LLM_URL: &str = "http://localhost:8000"; + fn main() { console_error_panic_hook::set_once(); - mount_to_body(|| view! { }) + mount_to_body(|| view! { }) } +// create signal to store hashmap of data gems + #[component] fn App() -> impl IntoView { - let (count, set_count) = create_signal(0); + let gems = create_rw_signal(HashMap::::new()); + let (selection, set_selection) = create_signal(Vec::::new()); + + let on_toggle_selection = move |id| { + set_selection.update(|current| + if current.contains(&id) { + current.retain(|x| x != &id); + } else { + current.push(id.clone()); + }) + }; + + let on_classify = move |(id, classification, description, json_data)| { + gems.update(|gems| { + gems.insert(id, DataGem { + classification: Some(classification), + description: description, + json_data: json_data, + }); + }); + }; view! { - - +
+ {move || selection.get().join(", ")} + {move || gems() + .into_iter() + .map(|(id, gem)| view! { }) + .collect_view()} + + +
} } - #[derive(Deserialize, Serialize, Debug)] struct LlmResponse { #[serde(rename = "type")] @@ -40,73 +82,172 @@ struct LlmResponse { output: String, } +#[derive(Deserialize, Serialize, Debug)] +struct CreateThreadRequest { + action: String, + system: String, + message: String, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct ClassificationData { + title: String, + #[serde(rename = "contentType")] + content_type: String, + emoji: String, + sensitivity: String, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct DataGem { + classification: Option, + description: String, + json_data: String, +} + #[component] -pub fn FormWithPreview() -> impl IntoView { - let (image_url, set_image_url) = create_signal(String::new()); - let (description, set_description) = create_signal(String::new()); - let (json_data, set_json_data) = create_signal(String::from("{}")); +pub fn DataGemPreview(classification: ClassificationData) -> impl IntoView { + view! { +
+
{classification.emoji.clone()}
+
+

{classification.title.clone()}

+ {classification.content_type.clone()} "("{classification.sensitivity.clone()}")" +
+
+ } +} - let generate_preview = create_action(move |_| { - async move { - // LLM URL: - // window.location.protocol + "//" + window.location.host + "/api/v0/llm"; - let win = window(); +pub async fn classify_data(json: String, description: String) -> Result { + let win = window(); + let mut opts = RequestInit::new(); + opts.method("POST"); + + let msg = format!( + "Classify the following data:\n\n{}\n\nContext:\n\n{}", + json, + description + ); + + // set body as JSON string + let body = CreateThreadRequest { + action: String::from("create"), + system: String::from("Examine the provided raw data and context and return a brief title, it's confidentiality/sensitivity (public, shared, personal, secret), the data type and emoji to describe the data. Respond with a JSON object containing the title and emoji, e.g. {\"title\": \"Personal Budget\", \"contentType\": \"Spreadsheet\", \"emoji\": \"💸\", \"sensitivity\": \"personal/financial\"} wrapped in a code block."), + message: msg, + }; + let body = serde_json::to_string(&body).unwrap(); + opts.body(Some(&JsValue::from_str(&body))); + + let request = Request::new_with_str_and_init(LLM_URL, &opts).unwrap(); + + let resp_value = JsFuture::from(win.fetch_with_request(&request)) + .await + .expect("failed to fetch"); + let resp: Response = resp_value.dyn_into().unwrap(); - let mut opts = RequestInit::new(); + let json = JsFuture::from(resp.json().unwrap()) + .await + .expect("failed to get response text"); + + let llm_response: LlmResponse = + serde_wasm_bindgen::from_value(json).map_err(|_| "Failed to deserialize JSON")?; + + log!("Response: {:?}", llm_response); + + let classification_data = + extract_code_blocks_from_markdown(&llm_response.output, "json"); + let classification_data: ClassificationData = + serde_json::from_str(&classification_data[0]).unwrap(); + + Ok(classification_data) +} + +pub async fn combine_data(json: String, description: String) -> Result { + let win = window(); + let mut opts = RequestInit::new(); opts.method("POST"); - // set body as JSON string - opts.body(Some(&JsValue::from_str( - r#"{"action": "create", "message": "hello"}"#, - ))); + + let msg = format!( + "Classify the following data:\n\n{}\n\nContext:\n\n{}", + json, + description + ); - let request = Request::new_with_str_and_init("http://localhost:8000", &opts).unwrap(); + // set body as JSON string + let body = CreateThreadRequest { + action: String::from("create"), + system: String::from("Examine the provided raw data and context and return a brief title, it's confidentiality/sensitivity (public, shared, personal, secret), the data type and emoji to describe the data. Respond with a JSON object containing the title and emoji, e.g. {\"title\": \"Personal Budget\", \"contentType\": \"Spreadsheet\", \"emoji\": \"💸\", \"sensitivity\": \"personal/financial\"} wrapped in a code block."), + message: msg, + }; + let body = serde_json::to_string(&body).unwrap(); + opts.body(Some(&JsValue::from_str(&body))); - let resp_value = JsFuture::from(win.fetch_with_request(&request)) - .await - .expect("failed to fetch"); - let resp: Response = resp_value.dyn_into().unwrap(); + let request = Request::new_with_str_and_init(LLM_URL, &opts).unwrap(); - let json = JsFuture::from(resp.json().unwrap()) - .await - .expect("failed to get response text"); + let resp_value = JsFuture::from(win.fetch_with_request(&request)) + .await + .expect("failed to fetch"); + let resp: Response = resp_value.dyn_into().unwrap(); + + let json = JsFuture::from(resp.json().unwrap()) + .await + .expect("failed to get response text"); + + let llm_response: LlmResponse = + serde_wasm_bindgen::from_value(json).map_err(|_| "Failed to deserialize JSON")?; + + log!("Response: {:?}", llm_response); + + let classification_data = + extract_code_blocks_from_markdown(&llm_response.output, "json"); + let classification_data: ClassificationData = + serde_json::from_str(&classification_data[0]).unwrap(); + + Ok(classification_data) +} - let llm_response: LlmResponse = - serde_wasm_bindgen::from_value(json).map_err(|_| "Failed to deserialize JSON")?; +#[component] +pub fn DataGemEditor( + id: String, + gem: DataGem, + selected: bool, + #[prop(into)] on_toggle: Callback, + #[prop(into)] on_classify: Callback<(String, ClassificationData, String, String)>, +) -> impl IntoView { + let id = store_value(id); + let (description, set_description) = create_signal(gem.description.clone()); + let (json_data, set_json_data) = create_signal(gem.json_data.clone()); - log!("Response: {:?}", llm_response); + let classify_data = create_action(move |_| { + async move { + let json = move || json_data.get(); + let description = move || description.get(); - Ok::(llm_response) + let data = classify_data(json(), description()).await; + match data { + Ok(data) => { + on_classify((id.get_value().clone(), data.clone(), description(), json_data())); + }, + Err(e) => { + log!("Error: {:?}", e); + } + } } }); - let on_submit = move |ev: web_sys::SubmitEvent| { - ev.prevent_default(); - // Handle form submission here - log!("Form submitted"); - log!("Description: {}", description.get()); - log!("JSON Data: {}", json_data.get()); - }; - view! { -
-
- - Preview - + +
+ + {gem.classification.map(|c| view! { })}
- -
+ + + + + + + + + +
+ - - -
- - -
- - + >
+ +
} } From 5d8edd54b22c05464f7388c5bd81e30e0fb65106 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Thu, 25 Jul 2024 12:23:03 +1000 Subject: [PATCH 05/43] Refactor into modules --- rust/gemcraft-leptos/index.html | 36 +++- rust/gemcraft-leptos/src/data.rs | 17 ++ rust/gemcraft-leptos/src/gem.rs | 138 ++++++++++++++ rust/gemcraft-leptos/src/llm.rs | 155 ++++++++++++++++ rust/gemcraft-leptos/src/main.rs | 300 ++++++------------------------- 5 files changed, 401 insertions(+), 245 deletions(-) create mode 100644 rust/gemcraft-leptos/src/data.rs create mode 100644 rust/gemcraft-leptos/src/gem.rs create mode 100644 rust/gemcraft-leptos/src/llm.rs diff --git a/rust/gemcraft-leptos/index.html b/rust/gemcraft-leptos/index.html index 98de606d2..ad12a42fc 100644 --- a/rust/gemcraft-leptos/index.html +++ b/rust/gemcraft-leptos/index.html @@ -2,6 +2,20 @@ diff --git a/rust/gemcraft-leptos/src/llm.rs b/rust/gemcraft-leptos/src/llm.rs index 950205b03..2e08aa1b1 100644 --- a/rust/gemcraft-leptos/src/llm.rs +++ b/rust/gemcraft-leptos/src/llm.rs @@ -124,12 +124,12 @@ pub async fn combine_data(gems: Vec, description: String) -> Result>().join("\n\n"), description); + let msg = format!("Imagine 4 different micro-apps that could operate on the following data gems: \n\n{}\n\nRemember, we are creating micro-apps that literally operate ON the provided data as their input. {}", gems.iter().map(|g| format_gem_with_classification(g.clone())).collect::>().join("\n\n"), description); // set body as JSON string let body = CreateThreadRequest { action: String::from("create"), - system: String::from("Examine the provided data gems and imagine what kind of user interface / mini-app a user would like to use to explore, manipulate and interact with the data contained within. Describe each micro-app with a small spec listing what a user can do with a loose idea of the visual components and layout. Include an emoji as the icon."), + system: String::from("Examine the provided data gems and imagine what kind of user interface / mini-app a user would like to use to explore, manipulate and interact with the data contained within. You must utilize all provided data gems and consider how to use them TOGETHER in an app. The user selected each one for a reason. Describe each micro-app with a small spec listing what a user can do with a loose idea of the visual components and layout. Include an emoji as the icon."), message: msg, }; let body = serde_json::to_string(&body).unwrap(); diff --git a/rust/gemcraft-leptos/src/main.rs b/rust/gemcraft-leptos/src/main.rs index 0b341bbdc..c2a4cb354 100644 --- a/rust/gemcraft-leptos/src/main.rs +++ b/rust/gemcraft-leptos/src/main.rs @@ -20,6 +20,7 @@ fn main() { #[component] fn App() -> impl IntoView { let gems = create_rw_signal(HashMap::::new()); + let search = create_rw_signal(String::new()); let (selection, set_selection) = create_signal(Vec::::new()); let (imagined_apps, set_imagined_apps) = create_signal(String::new()); @@ -55,7 +56,7 @@ fn App() -> impl IntoView { .filter(|(id, _)| selection.get().contains(id)) .map(|(_, gem)| gem.clone()) .collect(); - let data = llm::combine_data(selectedData, "".to_string()).await; + let data = llm::combine_data(selectedData, search.get()).await; match data { Ok(data) => { log!("Response: {:?}", data); @@ -98,8 +99,9 @@ fn App() -> impl IntoView {
{move || selection.get().iter().map(|id| view! { }).collect_view()}
+ -
{move || imagined_apps.get()}
+
{move || imagined_apps.get()}
} diff --git a/typescript/packages/planning-server/.env.local b/typescript/packages/planning-server/.env.local index 8d305b986..9c7a690ee 100644 --- a/typescript/packages/planning-server/.env.local +++ b/typescript/packages/planning-server/.env.local @@ -1,3 +1,8 @@ ANTHROPIC_API_KEY=sk-fake +GOOGLE_GENERATIVE_AI_API_KEY=g-fake +GOOGLE_VERTEX_PROJECT=g-fake +GOOGLE_VERTEX_LOCATION=us-central1 +GOOGLE_VERTEX_CLIENT_EMAIL=fake@fake.iam.gserviceaccount.com +GOOGLE_VERTEX_PRIVATE_KEY=fake ANTHROPIC_BASE_URL=https://api.anthropic.com PORT=8000 diff --git a/typescript/packages/planning-server/src/actions.ts b/typescript/packages/planning-server/src/actions.ts index 5b1e770d6..2afd4a0fd 100644 --- a/typescript/packages/planning-server/src/actions.ts +++ b/typescript/packages/planning-server/src/actions.ts @@ -3,7 +3,7 @@ import { ConversationThread, InMemoryConversationThreadManager, } from "./conversation.ts"; -import { ask } from "./anthropic.ts"; +import { ask } from "./llm.ts"; const cache: Record = {}; const threadManager = new InMemoryConversationThreadManager(); diff --git a/typescript/packages/planning-server/src/deps.ts b/typescript/packages/planning-server/src/deps.ts index 2cf247807..0cd65a7a2 100644 --- a/typescript/packages/planning-server/src/deps.ts +++ b/typescript/packages/planning-server/src/deps.ts @@ -7,5 +7,22 @@ export { oakCors } from "https://deno.land/x/cors/mod.ts"; export * as ai from "npm:ai"; export { anthropic } from "npm:@ai-sdk/anthropic"; +export { google } from "npm:@ai-sdk/google"; +import { createVertex } from "npm:@ai-sdk/google-vertex"; await config({ export: true }); + +const authOptions = { + credentials: { + client_email: Deno.env.get("GOOGLE_VERTEX_CLIENT_EMAIL")!, + private_key: Deno.env + .get("GOOGLE_VERTEX_PRIVATE_KEY")! + .replace(/\\n/g, "\n"), + }, +}; + +export const vertex = createVertex({ + project: Deno.env.get("GOOGLE_VERTEX_PROJECT")!, + location: Deno.env.get("GOOGLE_VERTEX_LOCATION")!, + googleAuthOptions: authOptions, +}); diff --git a/typescript/packages/planning-server/src/anthropic.ts b/typescript/packages/planning-server/src/llm.ts similarity index 91% rename from typescript/packages/planning-server/src/anthropic.ts rename to typescript/packages/planning-server/src/llm.ts index 61cbc7cb0..626e22bb6 100644 --- a/typescript/packages/planning-server/src/anthropic.ts +++ b/typescript/packages/planning-server/src/llm.ts @@ -1,4 +1,4 @@ -import { anthropic, ai } from "./deps.ts"; +import { anthropic, google, ai, vertex } from "./deps.ts"; import { CoreMessage } from "npm:ai"; import { CoreTool } from "npm:ai"; const { generateText, streamText } = ai; @@ -6,6 +6,7 @@ const { generateText, streamText } = ai; export const OPUS = "claude-3-5-opus-20240307"; export const HAIKU = "claude-3-haiku-20240307"; export const SONNET = "claude-3-5-sonnet-20240620"; +export const LLAMA_3_1_405B = "meta/llama3-405b-instruct-maas"; const model = anthropic(SONNET); type Model = typeof model; @@ -30,7 +31,7 @@ export async function single(text: string, model: Model) { export async function ask( initialConversation: CoreMessage[] = [], systemPrompt: string = "", - activeTools: CoreTool[], + activeTools: CoreTool[] ) { const conversation: CoreMessage[] = [...initialConversation]; From 8d72f11f064c6983b32add2367ba5dd9e1a74e93 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:39:13 -0700 Subject: [PATCH 07/43] svg wireframes --- rust/gemcraft-leptos/src/llm.rs | 4 +- rust/gemcraft-leptos/src/main.rs | 4 +- rust/gemcraft-leptos/src/micro_app.rs | 109 +++ typescript/packages/planning-server/deno.lock | 718 +++++++++++++++++- 4 files changed, 829 insertions(+), 6 deletions(-) create mode 100644 rust/gemcraft-leptos/src/micro_app.rs diff --git a/rust/gemcraft-leptos/src/llm.rs b/rust/gemcraft-leptos/src/llm.rs index 2e08aa1b1..921a185a1 100644 --- a/rust/gemcraft-leptos/src/llm.rs +++ b/rust/gemcraft-leptos/src/llm.rs @@ -124,12 +124,12 @@ pub async fn combine_data(gems: Vec, description: String) -> Result{}", gems.iter().map(|g| format_gem_with_classification(g.clone())).collect::>().join("\n\n"), description); + let msg = format!("Imagine 4 different micro-apps that could operate on the following data gems: \n\n{}\n\nRemember, we are creating micro-apps that literally operate ON the provided data as their input. Inspired by: {}", gems.iter().map(|g| format_gem_with_classification(g.clone())).collect::>().join("\n\n"), description); // set body as JSON string let body = CreateThreadRequest { action: String::from("create"), - system: String::from("Examine the provided data gems and imagine what kind of user interface / mini-app a user would like to use to explore, manipulate and interact with the data contained within. You must utilize all provided data gems and consider how to use them TOGETHER in an app. The user selected each one for a reason. Describe each micro-app with a small spec listing what a user can do with a loose idea of the visual components and layout. Include an emoji as the icon."), + system: String::from("Examine the provided data gems and imagine what kind of user interface / mini-app a user would like to use to explore, manipulate and interact with the data contained within. You must utilize all provided data gems and consider how to use them TOGETHER in an app. The user selected each one for a reason. Describe each micro-app within a tag with a small spec listing what a user can do with a loose idea of the visual components and layout. Include an emoji as the icon and the code for an showing a rough wireframe sketch of how the interface could look. Be creative in how you combine the input data and request, try to delight the user."), message: msg, }; let body = serde_json::to_string(&body).unwrap(); diff --git a/rust/gemcraft-leptos/src/main.rs b/rust/gemcraft-leptos/src/main.rs index c2a4cb354..eac48285b 100644 --- a/rust/gemcraft-leptos/src/main.rs +++ b/rust/gemcraft-leptos/src/main.rs @@ -2,6 +2,7 @@ mod data; mod extract; mod gem; mod llm; +mod micro_app; use leptos::*; use logging::log; @@ -10,6 +11,7 @@ use uuid::Uuid; use data::{ClassificationData, DataGem}; use gem::{DataGemEditor, MiniDataGemPreview}; +use micro_app::MicroAppGrid; fn main() { console_error_panic_hook::set_once(); @@ -101,7 +103,7 @@ fn App() -> impl IntoView { -
{move || imagined_apps.get()}
+ } diff --git a/rust/gemcraft-leptos/src/micro_app.rs b/rust/gemcraft-leptos/src/micro_app.rs new file mode 100644 index 000000000..bf3890d51 --- /dev/null +++ b/rust/gemcraft-leptos/src/micro_app.rs @@ -0,0 +1,109 @@ +use leptos::*; +use leptos::html::*; + +#[derive(Clone, Debug, PartialEq)] +pub struct MicroAppIdea { + title: String, + spec: String, + svg: String, +} + +pub fn parse_micro_app_ideas(input: &str) -> Vec { + let mut ideas = Vec::new(); + let parts: Vec<&str> = input.split("").skip(1).collect(); + + for part in parts { + if let Some(end_idx) = part.find("") { + let content = &part[..end_idx]; + let mut lines = content.lines(); + + let title = lines.next().unwrap_or("").trim().to_string(); + let mut spec = String::new(); + let mut svg = String::new(); + let mut in_svg = false; + + for line in lines { + if line.trim().starts_with("") { + in_svg = false; + } + } + + ideas.push(MicroAppIdea { + title, + spec: spec.trim().to_string(), + svg: svg.trim().to_string(), + }); + } + } + + ideas +} + +#[component] +pub fn MicroAppGrid(input: ReadSignal) -> impl IntoView { + let ideas = create_memo(move |_| parse_micro_app_ideas(&input.get())); + + view! { + <> + +
+
+

{&idea.title}

+
+

Spec:

+
{&idea.spec}
+
+
+
+ } + } + /> +
+ + } +} diff --git a/typescript/packages/planning-server/deno.lock b/typescript/packages/planning-server/deno.lock index 536256748..3202ae691 100644 --- a/typescript/packages/planning-server/deno.lock +++ b/typescript/packages/planning-server/deno.lock @@ -2,10 +2,204 @@ "version": "3", "packages": { "specifiers": { + "jsr:@oak/commons@0.11": "jsr:@oak/commons@0.11.0", + "jsr:@std/assert@0.223": "jsr:@std/assert@0.223.0", + "jsr:@std/assert@0.226": "jsr:@std/assert@0.226.0", + "jsr:@std/assert@^0.223.0": "jsr:@std/assert@0.223.0", + "jsr:@std/assert@^0.224.0": "jsr:@std/assert@0.224.0", + "jsr:@std/bytes@0.223": "jsr:@std/bytes@0.223.0", + "jsr:@std/bytes@0.224": "jsr:@std/bytes@0.224.0", + "jsr:@std/bytes@^0.223.0": "jsr:@std/bytes@0.223.0", + "jsr:@std/crypto@0.223": "jsr:@std/crypto@0.223.0", + "jsr:@std/crypto@0.224": "jsr:@std/crypto@0.224.0", + "jsr:@std/encoding@1.0.0-rc.2": "jsr:@std/encoding@1.0.0-rc.2", + "jsr:@std/encoding@^0.223.0": "jsr:@std/encoding@0.223.0", + "jsr:@std/http@0.223": "jsr:@std/http@0.223.0", + "jsr:@std/http@0.224": "jsr:@std/http@0.224.5", + "jsr:@std/io@0.223": "jsr:@std/io@0.223.0", + "jsr:@std/media-types@0.223": "jsr:@std/media-types@0.223.0", + "jsr:@std/media-types@0.224": "jsr:@std/media-types@0.224.1", + "jsr:@std/path@0.223": "jsr:@std/path@0.223.0", + "npm:@ai-sdk/anthropic": "npm:@ai-sdk/anthropic@0.0.33_zod@3.23.8", + "npm:@ai-sdk/google": "npm:@ai-sdk/google@0.0.30_zod@3.23.8", + "npm:@ai-sdk/google-vertex": "npm:@ai-sdk/google-vertex@0.0.19_@google-cloud+vertexai@1.4.0", "npm:@anthropic-ai/sdk": "npm:@anthropic-ai/sdk@0.24.0", - "npm:datascript": "npm:datascript@1.7.1" + "npm:ai": "npm:ai@3.2.36", + "npm:datascript": "npm:datascript@1.7.1", + "npm:path-to-regexp@6.2.1": "npm:path-to-regexp@6.2.1" + }, + "jsr": { + "@oak/commons@0.11.0": { + "integrity": "07702bfe5c07cd8144c422022994da1f9fea466b185824f4be63a2b1b1a65125", + "dependencies": [ + "jsr:@std/assert@0.226", + "jsr:@std/bytes@0.224", + "jsr:@std/crypto@0.224", + "jsr:@std/http@0.224", + "jsr:@std/media-types@0.224" + ] + }, + "@std/assert@0.223.0": { + "integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24" + }, + "@std/assert@0.224.0": { + "integrity": "8643233ec7aec38a940a8264a6e3eed9bfa44e7a71cc6b3c8874213ff401967f" + }, + "@std/assert@0.226.0": { + "integrity": "0dfb5f7c7723c18cec118e080fec76ce15b4c31154b15ad2bd74822603ef75b3" + }, + "@std/bytes@0.223.0": { + "integrity": "84b75052cd8680942c397c2631318772b295019098f40aac5c36cead4cba51a8" + }, + "@std/bytes@0.224.0": { + "integrity": "a2250e1d0eb7d1c5a426f21267ab9bdeac2447fa87a3d0d1a467d3f7a6058e49" + }, + "@std/crypto@0.223.0": { + "integrity": "1aa9555ff56b09e197ad988ea200f84bc6781fd4fd83f3a156ee44449af93000", + "dependencies": [ + "jsr:@std/assert@^0.223.0", + "jsr:@std/encoding@^0.223.0" + ] + }, + "@std/crypto@0.224.0": { + "integrity": "154ef3ff08ef535562ef1a718718c5b2c5fc3808f0f9100daad69e829bfcdf2d", + "dependencies": [ + "jsr:@std/assert@^0.224.0" + ] + }, + "@std/encoding@0.223.0": { + "integrity": "2b5615a75e00337ce113f34cf2f9b8c18182c751a8dcc8b1a2c2fc0e117bef00" + }, + "@std/encoding@1.0.0-rc.2": { + "integrity": "160d7674a20ebfbccdf610b3801fee91cf6e42d1c106dd46bbaf46e395cd35ef" + }, + "@std/http@0.223.0": { + "integrity": "15ab8a0c5a7e9d5be017a15b01600f20f66602ceec48b378939fa24fcec522aa", + "dependencies": [ + "jsr:@std/assert@^0.223.0", + "jsr:@std/encoding@^0.223.0" + ] + }, + "@std/http@0.224.5": { + "integrity": "b03b5d1529f6c423badfb82f6640f9f2557b4034cd7c30655ba5bb447ff750a4", + "dependencies": [ + "jsr:@std/encoding@1.0.0-rc.2" + ] + }, + "@std/io@0.223.0": { + "integrity": "2d8c3c2ab3a515619b90da2c6ff5ea7b75a94383259ef4d02116b228393f84f1", + "dependencies": [ + "jsr:@std/bytes@^0.223.0" + ] + }, + "@std/media-types@0.223.0": { + "integrity": "84684680c2eb6bc6d9369c6d6f26a49decaf2c7603ff531862dda575d9d6776e" + }, + "@std/media-types@0.224.1": { + "integrity": "9e69a5daed37c5b5c6d3ce4731dc191f80e67f79bed392b0957d1d03b87f11e1" + }, + "@std/path@0.223.0": { + "integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989", + "dependencies": [ + "jsr:@std/assert@^0.223.0" + ] + } }, "npm": { + "@ai-sdk/anthropic@0.0.33_zod@3.23.8": { + "integrity": "sha512-xCgerb04tpVOYLL3CmaXUWXa+U8Dt8vflkat4m/0PKQdYGq06JLx/+vaRO8dEz+zU12sQl+3HTPrX53v/wVSxQ==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5_zod@3.23.8", + "zod": "zod@3.23.8" + } + }, + "@ai-sdk/google-vertex@0.0.19_@google-cloud+vertexai@1.4.0": { + "integrity": "sha512-RvftHR7IFU/hRbNznT+5Wyqx8+wA39cg2DGnlhi28PofY7y70V5crZpbESFGCFPXq253ZlO4nwssFXtDWhcQRg==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5", + "@google-cloud/vertexai": "@google-cloud/vertexai@1.4.0", + "json-schema": "json-schema@0.4.0" + } + }, + "@ai-sdk/google@0.0.30_zod@3.23.8": { + "integrity": "sha512-sGkUc7qyJ5LuIkJ+Lsq+VH8o2521biggU45F1oK3jLi9Y6tMA854ZNye5YhgeWVjv56FOBy/okLYvwxPodHfAw==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5_zod@3.23.8", + "zod": "zod@3.23.8" + } + }, + "@ai-sdk/provider-utils@1.0.5": { + "integrity": "sha512-XfOawxk95X3S43arn2iQIFyWGMi0DTxsf9ETc6t7bh91RPWOOPYN1tsmS5MTKD33OGJeaDQ/gnVRzXUCRBrckQ==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "eventsource-parser": "eventsource-parser@1.1.2", + "nanoid": "nanoid@3.3.6", + "secure-json-parse": "secure-json-parse@2.7.0" + } + }, + "@ai-sdk/provider-utils@1.0.5_zod@3.23.8": { + "integrity": "sha512-XfOawxk95X3S43arn2iQIFyWGMi0DTxsf9ETc6t7bh91RPWOOPYN1tsmS5MTKD33OGJeaDQ/gnVRzXUCRBrckQ==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "eventsource-parser": "eventsource-parser@1.1.2", + "nanoid": "nanoid@3.3.6", + "secure-json-parse": "secure-json-parse@2.7.0", + "zod": "zod@3.23.8" + } + }, + "@ai-sdk/provider@0.0.14": { + "integrity": "sha512-gaQ5Y033nro9iX1YUjEDFDRhmMcEiCk56LJdIUbX5ozEiCNCfpiBpEqrjSp/Gp5RzBS2W0BVxfG7UGW6Ezcrzg==", + "dependencies": { + "json-schema": "json-schema@0.4.0" + } + }, + "@ai-sdk/react@0.0.29": { + "integrity": "sha512-eTxTmEW0yTCBrfE5iZ/llBsruBbLCpuO6xHWJBjkm8JcA3aWKafMgqULlDcq1wOkb44By1aBQw3NjxF/UIc1Xw==", + "dependencies": { + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5", + "@ai-sdk/ui-utils": "@ai-sdk/ui-utils@0.0.20", + "swr": "swr@2.2.5_react@18.3.1" + } + }, + "@ai-sdk/solid@0.0.22": { + "integrity": "sha512-KTsltPOBgOPeA8HTkaAl0e/7UnILZHaCYVP7Oeb1PR1avoFQY4mVrqX8YqI2KMdh4xm/WyaWEABmesZ+VrikzA==", + "dependencies": { + "@ai-sdk/ui-utils": "@ai-sdk/ui-utils@0.0.20" + } + }, + "@ai-sdk/svelte@0.0.23": { + "integrity": "sha512-9gT0IBI0rYW2EAmtHWhwBDiWZ4F0ev05S2jyMR8kklsIUUR1CQc5p6K5QLrR3ZpGo3IU9cqHwT8TJ2AkeYUbMg==", + "dependencies": { + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5", + "@ai-sdk/ui-utils": "@ai-sdk/ui-utils@0.0.20", + "sswr": "sswr@2.1.0_svelte@4.2.18" + } + }, + "@ai-sdk/ui-utils@0.0.20": { + "integrity": "sha512-6MRWigzXfuxUcAYEFMLP6cLbALJkg12Iz1Sl+wuPMpB6aw7di2ePiTuNakFUYjgP7TNsW4UxzpypBqqJ1KNB0A==", + "dependencies": { + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5", + "secure-json-parse": "secure-json-parse@2.7.0" + } + }, + "@ai-sdk/vue@0.0.24": { + "integrity": "sha512-0S+2dVSui6LFgaWoFx+3h5R7GIP9MxdJo63tFuLvgyKr2jmpo5S5kGcWl95vNdzKDqaesAXfOnky+tn5A2d49A==", + "dependencies": { + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5", + "@ai-sdk/ui-utils": "@ai-sdk/ui-utils@0.0.20", + "swrv": "swrv@1.0.4_vue@3.4.34" + } + }, + "@ampproject/remapping@2.3.0": { + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "@jridgewell/gen-mapping@0.3.5", + "@jridgewell/trace-mapping": "@jridgewell/trace-mapping@0.3.25" + } + }, "@anthropic-ai/sdk@0.24.0": { "integrity": "sha512-iMb1bQimQrSw/Rq6duPiuCJ7uvlSciq5PWp17jVOfy5dK2EJY36ol10ttwb+Zf6yzkKHMdt+vNIpznj/HsPXOg==", "dependencies": { @@ -19,6 +213,55 @@ "web-streams-polyfill": "web-streams-polyfill@3.3.3" } }, + "@babel/parser@7.24.8": { + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "dependencies": {} + }, + "@google-cloud/vertexai@1.4.0": { + "integrity": "sha512-3D06+qlpbotQINBUbxC5c9zuv5nM5VLnaQZCcktfvSHnue3jsQ1sG1+/ZSkx8E9OidpVNAh5iCcAEZd8N7hPnQ==", + "dependencies": { + "google-auth-library": "google-auth-library@9.11.0" + } + }, + "@jridgewell/gen-mapping@0.3.5": { + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "@jridgewell/set-array@1.2.1", + "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.5.0", + "@jridgewell/trace-mapping": "@jridgewell/trace-mapping@0.3.25" + } + }, + "@jridgewell/resolve-uri@3.1.2": { + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dependencies": {} + }, + "@jridgewell/set-array@1.2.1": { + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dependencies": {} + }, + "@jridgewell/sourcemap-codec@1.5.0": { + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dependencies": {} + }, + "@jridgewell/trace-mapping@0.3.25": { + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "@jridgewell/resolve-uri@3.1.2", + "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.5.0" + } + }, + "@opentelemetry/api@1.9.0": { + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dependencies": {} + }, + "@types/diff-match-patch@1.0.36": { + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", + "dependencies": {} + }, + "@types/estree@1.0.5": { + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dependencies": {} + }, "@types/node-fetch@2.6.11": { "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", "dependencies": { @@ -36,40 +279,234 @@ "undici-types": "undici-types@5.26.5" } }, + "@vue/compiler-core@3.4.34": { + "integrity": "sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==", + "dependencies": { + "@babel/parser": "@babel/parser@7.24.8", + "@vue/shared": "@vue/shared@3.4.34", + "entities": "entities@4.5.0", + "estree-walker": "estree-walker@2.0.2", + "source-map-js": "source-map-js@1.2.0" + } + }, + "@vue/compiler-dom@3.4.34": { + "integrity": "sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==", + "dependencies": { + "@vue/compiler-core": "@vue/compiler-core@3.4.34", + "@vue/shared": "@vue/shared@3.4.34" + } + }, + "@vue/compiler-sfc@3.4.34": { + "integrity": "sha512-x6lm0UrM03jjDXTPZgD9Ad8bIVD1ifWNit2EaWQIZB5CULr46+FbLQ5RpK7AXtDHGjx9rmvC7QRCTjsiGkAwRw==", + "dependencies": { + "@babel/parser": "@babel/parser@7.24.8", + "@vue/compiler-core": "@vue/compiler-core@3.4.34", + "@vue/compiler-dom": "@vue/compiler-dom@3.4.34", + "@vue/compiler-ssr": "@vue/compiler-ssr@3.4.34", + "@vue/shared": "@vue/shared@3.4.34", + "estree-walker": "estree-walker@2.0.2", + "magic-string": "magic-string@0.30.10", + "postcss": "postcss@8.4.40", + "source-map-js": "source-map-js@1.2.0" + } + }, + "@vue/compiler-ssr@3.4.34": { + "integrity": "sha512-8TDBcLaTrFm5rnF+Qm4BlliaopJgqJ28Nsrc80qazynm5aJO+Emu7y0RWw34L8dNnTRdcVBpWzJxhGYzsoVu4g==", + "dependencies": { + "@vue/compiler-dom": "@vue/compiler-dom@3.4.34", + "@vue/shared": "@vue/shared@3.4.34" + } + }, + "@vue/reactivity@3.4.34": { + "integrity": "sha512-ua+Lo+wBRlBEX9TtgPOShE2JwIO7p6BTZ7t1KZVPoaBRfqbC7N3c8Mpzicx173fXxx5VXeU6ykiHo7WgLzJQDA==", + "dependencies": { + "@vue/shared": "@vue/shared@3.4.34" + } + }, + "@vue/runtime-core@3.4.34": { + "integrity": "sha512-PXhkiRPwcPGJ1BnyBZFI96GfInCVskd0HPNIAZn7i3YOmLbtbTZpB7/kDTwC1W7IqdGPkTVC63IS7J2nZs4Ebg==", + "dependencies": { + "@vue/reactivity": "@vue/reactivity@3.4.34", + "@vue/shared": "@vue/shared@3.4.34" + } + }, + "@vue/runtime-dom@3.4.34": { + "integrity": "sha512-dXqIe+RqFAK2Euak4UsvbIupalrhc67OuQKpD7HJ3W2fv8jlqvI7szfBCsAEcE8o/wyNpkloxB6J8viuF/E3gw==", + "dependencies": { + "@vue/reactivity": "@vue/reactivity@3.4.34", + "@vue/runtime-core": "@vue/runtime-core@3.4.34", + "@vue/shared": "@vue/shared@3.4.34", + "csstype": "csstype@3.1.3" + } + }, + "@vue/server-renderer@3.4.34_vue@3.4.34": { + "integrity": "sha512-GeyEUfMVRZMD/mZcNONEqg7MiU10QQ1DB3O/Qr6+8uXpbwdlmVgQ5Qs1/ZUAFX1X2UUtqMoGrDRbxdWfOJFT7Q==", + "dependencies": { + "@vue/compiler-ssr": "@vue/compiler-ssr@3.4.34", + "@vue/shared": "@vue/shared@3.4.34", + "vue": "vue@3.4.34" + } + }, + "@vue/shared@3.4.34": { + "integrity": "sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==", + "dependencies": {} + }, "abort-controller@3.0.0": { "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dependencies": { "event-target-shim": "event-target-shim@5.0.1" } }, + "acorn@8.12.1": { + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dependencies": {} + }, + "agent-base@7.1.1": { + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "debug@4.3.5" + } + }, "agentkeepalive@4.5.0": { "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dependencies": { "humanize-ms": "humanize-ms@1.2.1" } }, + "ai@3.2.36": { + "integrity": "sha512-YkGE27vKZtIyEYI7Q1/jI8SsFucp6O0MbIz8HLSBfToxVR34KF23s1ZMaR4ZcSRRANuPBHC/cyJWY7Ld4RRUnw==", + "dependencies": { + "@ai-sdk/provider": "@ai-sdk/provider@0.0.14", + "@ai-sdk/provider-utils": "@ai-sdk/provider-utils@1.0.5_zod@3.23.8", + "@ai-sdk/react": "@ai-sdk/react@0.0.29", + "@ai-sdk/solid": "@ai-sdk/solid@0.0.22", + "@ai-sdk/svelte": "@ai-sdk/svelte@0.0.23", + "@ai-sdk/ui-utils": "@ai-sdk/ui-utils@0.0.20", + "@ai-sdk/vue": "@ai-sdk/vue@0.0.24", + "@opentelemetry/api": "@opentelemetry/api@1.9.0", + "eventsource-parser": "eventsource-parser@1.1.2", + "json-schema": "json-schema@0.4.0", + "jsondiffpatch": "jsondiffpatch@0.6.0", + "nanoid": "nanoid@3.3.6", + "secure-json-parse": "secure-json-parse@2.7.0", + "zod-to-json-schema": "zod-to-json-schema@3.22.5_zod@3.23.8" + } + }, + "aria-query@5.3.0": { + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "dequal@2.0.3" + } + }, "asynckit@0.4.0": { "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dependencies": {} }, + "axobject-query@4.1.0": { + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dependencies": {} + }, + "base64-js@1.5.1": { + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dependencies": {} + }, + "bignumber.js@9.1.2": { + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dependencies": {} + }, + "buffer-equal-constant-time@1.0.1": { + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dependencies": {} + }, + "chalk@5.3.0": { + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dependencies": {} + }, + "client-only@0.0.1": { + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "dependencies": {} + }, + "code-red@1.0.4": { + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.5.0", + "@types/estree": "@types/estree@1.0.5", + "acorn": "acorn@8.12.1", + "estree-walker": "estree-walker@3.0.3", + "periscopic": "periscopic@3.1.0" + } + }, "combined-stream@1.0.8": { "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { "delayed-stream": "delayed-stream@1.0.0" } }, + "css-tree@2.3.1": { + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "mdn-data@2.0.30", + "source-map-js": "source-map-js@1.2.0" + } + }, + "csstype@3.1.3": { + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dependencies": {} + }, "datascript@1.7.1": { "integrity": "sha512-n8zwQ6yNnAfZakulY4FDjbXyoBOev3ZnU0kc3lQ1hU4Z7S9uu8USfQg9iSjt1Tw8WOT6r/qO64429vyk4irZfQ==", "dependencies": {} }, + "debug@4.3.5": { + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "ms@2.1.2" + } + }, "delayed-stream@1.0.0": { "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dependencies": {} }, + "dequal@2.0.3": { + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dependencies": {} + }, + "diff-match-patch@1.0.5": { + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "dependencies": {} + }, + "ecdsa-sig-formatter@1.0.11": { + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "safe-buffer@5.2.1" + } + }, + "entities@4.5.0": { + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dependencies": {} + }, + "estree-walker@2.0.2": { + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dependencies": {} + }, + "estree-walker@3.0.3": { + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "@types/estree@1.0.5" + } + }, "event-target-shim@5.0.1": { "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dependencies": {} }, + "eventsource-parser@1.1.2": { + "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==", + "dependencies": {} + }, + "extend@3.0.2": { + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dependencies": {} + }, "form-data-encoder@1.7.2": { "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", "dependencies": {} @@ -89,12 +526,121 @@ "web-streams-polyfill": "web-streams-polyfill@4.0.0-beta.3" } }, + "gaxios@6.7.0": { + "integrity": "sha512-DSrkyMTfAnAm4ks9Go20QGOcXEyW/NmZhvTYBU2rb4afBB393WIMQPWPEDMl/k8xqiNN9HYq2zao3oWXsdl2Tg==", + "dependencies": { + "extend": "extend@3.0.2", + "https-proxy-agent": "https-proxy-agent@7.0.5", + "is-stream": "is-stream@2.0.1", + "node-fetch": "node-fetch@2.7.0", + "uuid": "uuid@10.0.0" + } + }, + "gcp-metadata@6.1.0": { + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "gaxios@6.7.0", + "json-bigint": "json-bigint@1.0.0" + } + }, + "google-auth-library@9.11.0": { + "integrity": "sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw==", + "dependencies": { + "base64-js": "base64-js@1.5.1", + "ecdsa-sig-formatter": "ecdsa-sig-formatter@1.0.11", + "gaxios": "gaxios@6.7.0", + "gcp-metadata": "gcp-metadata@6.1.0", + "gtoken": "gtoken@7.1.0", + "jws": "jws@4.0.0" + } + }, + "gtoken@7.1.0": { + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "dependencies": { + "gaxios": "gaxios@6.7.0", + "jws": "jws@4.0.0" + } + }, + "https-proxy-agent@7.0.5": { + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "agent-base@7.1.1", + "debug": "debug@4.3.5" + } + }, "humanize-ms@1.2.1": { "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dependencies": { "ms": "ms@2.1.3" } }, + "is-reference@3.0.2": { + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "@types/estree@1.0.5" + } + }, + "is-stream@2.0.1": { + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dependencies": {} + }, + "js-tokens@4.0.0": { + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dependencies": {} + }, + "json-bigint@1.0.0": { + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "bignumber.js@9.1.2" + } + }, + "json-schema@0.4.0": { + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dependencies": {} + }, + "jsondiffpatch@0.6.0": { + "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "dependencies": { + "@types/diff-match-patch": "@types/diff-match-patch@1.0.36", + "chalk": "chalk@5.3.0", + "diff-match-patch": "diff-match-patch@1.0.5" + } + }, + "jwa@2.0.0": { + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "buffer-equal-constant-time@1.0.1", + "ecdsa-sig-formatter": "ecdsa-sig-formatter@1.0.11", + "safe-buffer": "safe-buffer@5.2.1" + } + }, + "jws@4.0.0": { + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "jwa@2.0.0", + "safe-buffer": "safe-buffer@5.2.1" + } + }, + "locate-character@3.0.0": { + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dependencies": {} + }, + "loose-envify@1.4.0": { + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "js-tokens@4.0.0" + } + }, + "magic-string@0.30.10": { + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.5.0" + } + }, + "mdn-data@2.0.30": { + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dependencies": {} + }, "mime-db@1.52.0": { "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dependencies": {} @@ -105,10 +651,22 @@ "mime-db": "mime-db@1.52.0" } }, + "ms@2.1.2": { + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dependencies": {} + }, "ms@2.1.3": { "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dependencies": {} }, + "nanoid@3.3.6": { + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dependencies": {} + }, + "nanoid@3.3.7": { + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dependencies": {} + }, "node-domexception@1.0.0": { "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "dependencies": {} @@ -119,6 +677,92 @@ "whatwg-url": "whatwg-url@5.0.0" } }, + "path-to-regexp@6.2.1": { + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dependencies": {} + }, + "periscopic@3.1.0": { + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "@types/estree@1.0.5", + "estree-walker": "estree-walker@3.0.3", + "is-reference": "is-reference@3.0.2" + } + }, + "picocolors@1.0.1": { + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dependencies": {} + }, + "postcss@8.4.40": { + "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "dependencies": { + "nanoid": "nanoid@3.3.7", + "picocolors": "picocolors@1.0.1", + "source-map-js": "source-map-js@1.2.0" + } + }, + "react@18.3.1": { + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "loose-envify@1.4.0" + } + }, + "safe-buffer@5.2.1": { + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dependencies": {} + }, + "secure-json-parse@2.7.0": { + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dependencies": {} + }, + "source-map-js@1.2.0": { + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dependencies": {} + }, + "sswr@2.1.0_svelte@4.2.18": { + "integrity": "sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==", + "dependencies": { + "svelte": "svelte@4.2.18", + "swrev": "swrev@4.0.0" + } + }, + "svelte@4.2.18": { + "integrity": "sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==", + "dependencies": { + "@ampproject/remapping": "@ampproject/remapping@2.3.0", + "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.5.0", + "@jridgewell/trace-mapping": "@jridgewell/trace-mapping@0.3.25", + "@types/estree": "@types/estree@1.0.5", + "acorn": "acorn@8.12.1", + "aria-query": "aria-query@5.3.0", + "axobject-query": "axobject-query@4.1.0", + "code-red": "code-red@1.0.4", + "css-tree": "css-tree@2.3.1", + "estree-walker": "estree-walker@3.0.3", + "is-reference": "is-reference@3.0.2", + "locate-character": "locate-character@3.0.0", + "magic-string": "magic-string@0.30.10", + "periscopic": "periscopic@3.1.0" + } + }, + "swr@2.2.5_react@18.3.1": { + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "dependencies": { + "client-only": "client-only@0.0.1", + "react": "react@18.3.1", + "use-sync-external-store": "use-sync-external-store@1.2.2_react@18.3.1" + } + }, + "swrev@4.0.0": { + "integrity": "sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==", + "dependencies": {} + }, + "swrv@1.0.4_vue@3.4.34": { + "integrity": "sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==", + "dependencies": { + "vue": "vue@3.4.34" + } + }, "tr46@0.0.3": { "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dependencies": {} @@ -127,6 +771,26 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dependencies": {} }, + "use-sync-external-store@1.2.2_react@18.3.1": { + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "dependencies": { + "react": "react@18.3.1" + } + }, + "uuid@10.0.0": { + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dependencies": {} + }, + "vue@3.4.34": { + "integrity": "sha512-VZze05HWlA3ItreQ/ka7Sx7PoD0/3St8FEiSlSTVgb6l4hL+RjtP2/8g5WQBzZgyf8WG2f+g1bXzC7zggLhAJA==", + "dependencies": { + "@vue/compiler-dom": "@vue/compiler-dom@3.4.34", + "@vue/compiler-sfc": "@vue/compiler-sfc@3.4.34", + "@vue/runtime-dom": "@vue/runtime-dom@3.4.34", + "@vue/server-renderer": "@vue/server-renderer@3.4.34_vue@3.4.34", + "@vue/shared": "@vue/shared@3.4.34" + } + }, "web-streams-polyfill@3.3.3": { "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dependencies": {} @@ -145,12 +809,24 @@ "tr46": "tr46@0.0.3", "webidl-conversions": "webidl-conversions@3.0.1" } + }, + "zod-to-json-schema@3.22.5_zod@3.23.8": { + "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "dependencies": { + "zod": "zod@3.23.8" + } + }, + "zod@3.23.8": { + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dependencies": {} } } }, "redirects": { "https://deno.land/std/testing/asserts.ts": "https://deno.land/std@0.224.0/testing/asserts.ts", - "https://deno.land/x/dotenv/mod.ts": "https://deno.land/x/dotenv@v3.2.2/mod.ts" + "https://deno.land/x/cors/mod.ts": "https://deno.land/x/cors@v1.2.2/mod.ts", + "https://deno.land/x/dotenv/mod.ts": "https://deno.land/x/dotenv@v3.2.2/mod.ts", + "https://deno.land/x/oak/mod.ts": "https://deno.land/x/oak@v16.1.0/mod.ts" }, "remote": { "https://deno.land/std@0.140.0/async/abortable.ts": "87aa7230be8360c24ad437212311c9e8d4328854baec27b4c7abb26e85515c06", @@ -197,8 +873,44 @@ "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e", "https://deno.land/std@0.224.0/testing/asserts.ts": "d0cdbabadc49cc4247a50732ee0df1403fdcd0f95360294ad448ae8c240f3f5c", + "https://deno.land/x/cors@v1.2.2/abcCors.ts": "cdf83a7eaa69a1bf3ab910d18b9422217902fac47601adcaf0afac5a61845d48", + "https://deno.land/x/cors@v1.2.2/attainCors.ts": "7d6aba0f942495cc31119604e0895c9bb8edd8f8baa7fe78e6c655bd0b4cbf59", + "https://deno.land/x/cors@v1.2.2/cors.ts": "0e2d9167e3685f9bcf48f565e312b6e1883fa458f7337e5ce7bc2e3b29767980", + "https://deno.land/x/cors@v1.2.2/mithCors.ts": "3a359d6e716e0410ede278ab54d875b293a2d66d838aaa7cfbf9ddc1e9e990d3", + "https://deno.land/x/cors@v1.2.2/mod.ts": "2b351913f56d77ad80cb3b8633d4539c9eeddb426dae79437ada0e6a9cb4f1a6", + "https://deno.land/x/cors@v1.2.2/oakCors.ts": "1348dc7673c61b85d2e80559a7b44f8e0246eaa6bcc6ec744fafe5d9b13b5c71", + "https://deno.land/x/cors@v1.2.2/opineCors.ts": "fb5790115c26b7061d84b8d6c17d258a1e241bcab75b0bc3ca1fdb2e57bc5072", + "https://deno.land/x/cors@v1.2.2/types.ts": "97546633ccc7f0df7a29bacba5d91dc6f61decdd1b65258300244dba905d34b8", "https://deno.land/x/dotenv@v3.2.2/mod.ts": "077b48773de9205266a0b44c3c3a3c3083449ed64bb0b6cc461b95720678d38e", - "https://deno.land/x/dotenv@v3.2.2/util.ts": "693730877b13f8ead2b79b2aa31e2a0652862f7dc0c5f6d2f313f4d39c7b7670" + "https://deno.land/x/dotenv@v3.2.2/util.ts": "693730877b13f8ead2b79b2aa31e2a0652862f7dc0c5f6d2f313f4d39c7b7670", + "https://deno.land/x/oak@v16.1.0/application.ts": "c6361a3c3fb3607c5dfe1800b156f07b612979dc0498c746aeca54bb9f643a92", + "https://deno.land/x/oak@v16.1.0/body.ts": "0f8a6843720ea6cebba2132a5e4dda5a97bbd49e7fb64e96ade0b7c8009bba2d", + "https://deno.land/x/oak@v16.1.0/context.ts": "a93a5b41dde2ceb52232ae31b3496be76e8a42ea421a73d7cffe9e640adb8dfd", + "https://deno.land/x/oak@v16.1.0/deps.ts": "f960515f71091adecc3df5e2295b3acfc4f1c003e08be29fceec1f7616053433", + "https://deno.land/x/oak@v16.1.0/http_server_bun.ts": "cb3a66c735cd0533c4c3776b37ae627ab42344c82f91dff63e3030d9656fd3a0", + "https://deno.land/x/oak@v16.1.0/http_server_native.ts": "3bea00ebb9638203d2449fbf9a14a6b87f119bd45012f13282ececdf7b4c4242", + "https://deno.land/x/oak@v16.1.0/http_server_native_request.ts": "a4da6f4939736e6323720db2d4b0d19ff2e83f02e52ab1eea9ae80f2c047fa56", + "https://deno.land/x/oak@v16.1.0/http_server_node.ts": "9bb5291c15305b297fd634aa4c6b1d5054368f4b7a171d7c7c302c73eb2489ed", + "https://deno.land/x/oak@v16.1.0/middleware.ts": "4170180fe5009d2581a0bdc995e5953b90ccb5b1c3767f3eae8a4fe238b8bd81", + "https://deno.land/x/oak@v16.1.0/middleware/etag.ts": "310ed4ed01f2af5384ab78617c82a2bdd7f84d66539172e45ee16452846f0754", + "https://deno.land/x/oak@v16.1.0/middleware/proxy.ts": "a0b4964509d4320735ffbe52ae2629c78e302dd9b934fcf2ddf189d491469892", + "https://deno.land/x/oak@v16.1.0/middleware/serve.ts": "efceebd70afb73bcabe0a6a8981f3d8474a2f2f30e85b46761aee49e81bd9d6a", + "https://deno.land/x/oak@v16.1.0/mod.ts": "38e53e01e609583e843f3e2b2677de9872d23d68939ce0de85b402e7a8db01a7", + "https://deno.land/x/oak@v16.1.0/node_shims.ts": "4db1569b2b79b73f37c4d947f4aaa50a93e266d48fe67601c8a31af17a28884d", + "https://deno.land/x/oak@v16.1.0/request.ts": "1e7f2c338cd6889b616bbdc9e2062eac27acbffde05c685adfb1c60ecc80682a", + "https://deno.land/x/oak@v16.1.0/response.ts": "bc47174d3d797ffc802f40fba006c16de8390e776a36f6f4a4d4f58b278bf36f", + "https://deno.land/x/oak@v16.1.0/router.ts": "882f36a576e280b0d617cc174feca320f02deed77bdea8264444ba8b55cc0422", + "https://deno.land/x/oak@v16.1.0/send.ts": "c05e5985b356b568ae4954a40373f93451a3f8cc9ae8706c8b8879e5e0c8c86b", + "https://deno.land/x/oak@v16.1.0/testing.ts": "c879789ac721144c3dcad0a06f5afbe2cd94fb20afc32302992942a49a7def90", + "https://deno.land/x/oak@v16.1.0/types.ts": "cd4ccd3e182d0cba2117cd27f560267970470ab9c0ff6556cadd73f605193be7", + "https://deno.land/x/oak@v16.1.0/utils/clone_state.ts": "cf8989ddd56816b36ada253ae0acdbd46cdf3d68dbe674d2b66c46640fab3500", + "https://deno.land/x/oak@v16.1.0/utils/consts.ts": "137c4f73479f5e98a13153b9305f06f0d85df3cf2aacad2c9f82d4c1f3a2f105", + "https://deno.land/x/oak@v16.1.0/utils/create_promise_with_resolvers.ts": "de99e9a998162b929a011f8873eaf0895cf4742492b3ce6f6866d39217342523", + "https://deno.land/x/oak@v16.1.0/utils/decode_component.ts": "d3e2c40ecdd2fdb79761c6e9ae224cf01a4643f7c5f4c1e0b69698d43025261b", + "https://deno.land/x/oak@v16.1.0/utils/encode_url.ts": "c0ed6b318eb9523adeebba32eb9acd059c0f94d3511b2b9e3b024722d1b3dfb8", + "https://deno.land/x/oak@v16.1.0/utils/resolve_path.ts": "aa39d54a003b38fee55f340a0cba3f93a7af85b8ddd5fbfb049a98fc0109b36d", + "https://deno.land/x/oak@v16.1.0/utils/streams.ts": "6d55543fdeddc3c9c6f512de227b9b33ff4b0ec5e320edc109f0cbf9bef8963f", + "https://deno.land/x/oak@v16.1.0/utils/type_guards.ts": "a1b42aa4c431c4c07d3f8a45a2142020f86d5a3e1e319af94fdf2f4c6c72465f" }, "workspace": { "packageJson": { From fd1ad12ae94bf7d32cfaac5cdd534a4e8ef7fc2f Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:47:15 +1000 Subject: [PATCH 08/43] Support for Llama 3.1 and GPT4o-mini --- rust/gemcraft-leptos/src/llm.rs | 4 ++-- typescript/packages/planning-server/.env.local | 1 + typescript/packages/planning-server/src/deps.ts | 1 + typescript/packages/planning-server/src/llm.ts | 6 ++++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rust/gemcraft-leptos/src/llm.rs b/rust/gemcraft-leptos/src/llm.rs index 921a185a1..195f10a0c 100644 --- a/rust/gemcraft-leptos/src/llm.rs +++ b/rust/gemcraft-leptos/src/llm.rs @@ -45,7 +45,7 @@ pub async fn classify_data( // set body as JSON string let body = CreateThreadRequest { action: String::from("create"), - system: String::from("Examine the provided raw data and context and return a brief title, it's confidentiality/sensitivity (public, shared, personal, secret), the data type and emoji to describe the data. Respond with a JSON object containing the title and emoji, e.g. {\"title\": \"Personal Budget\", \"contentType\": \"Spreadsheet\", \"emoji\": \"💸\", \"sensitivity\": \"personal/financial\"} wrapped in a code block."), + system: String::from("Examine the provided raw data and context and return a brief title, it's confidentiality/sensitivity (public, shared, personal, secret), the data type and emoji to describe the data. Respond with a JSON object containing the title and emoji, e.g. ```json\n{\"title\": \"Personal Budget\", \"contentType\": \"Spreadsheet\", \"emoji\": \"💸\", \"sensitivity\": \"personal/financial\"}``` wrapped in a block e.g. ```json\n{}\n```."), message: msg, }; let body = serde_json::to_string(&body).unwrap(); @@ -84,7 +84,7 @@ pub async fn hallucinate_data(description: String) -> Result { // set body as JSON string let body = CreateThreadRequest { action: String::from("create"), - system: String::from("imagine realistic JSON data based on the user request, respond with only JSON in a code block."), + system: String::from("imagine realistic JSON data based on the user request, respond with only JSON wrapped in a block e.g. ```json\n{}\n```."), message: msg, }; let body = serde_json::to_string(&body).unwrap(); diff --git a/typescript/packages/planning-server/.env.local b/typescript/packages/planning-server/.env.local index 9c7a690ee..eda0e3e92 100644 --- a/typescript/packages/planning-server/.env.local +++ b/typescript/packages/planning-server/.env.local @@ -4,5 +4,6 @@ GOOGLE_VERTEX_PROJECT=g-fake GOOGLE_VERTEX_LOCATION=us-central1 GOOGLE_VERTEX_CLIENT_EMAIL=fake@fake.iam.gserviceaccount.com GOOGLE_VERTEX_PRIVATE_KEY=fake +OPENAI_API_KEY=sk-fake ANTHROPIC_BASE_URL=https://api.anthropic.com PORT=8000 diff --git a/typescript/packages/planning-server/src/deps.ts b/typescript/packages/planning-server/src/deps.ts index 0cd65a7a2..d4b8a6fe4 100644 --- a/typescript/packages/planning-server/src/deps.ts +++ b/typescript/packages/planning-server/src/deps.ts @@ -9,6 +9,7 @@ export * as ai from "npm:ai"; export { anthropic } from "npm:@ai-sdk/anthropic"; export { google } from "npm:@ai-sdk/google"; import { createVertex } from "npm:@ai-sdk/google-vertex"; +export { openai } from "npm:@ai-sdk/openai"; await config({ export: true }); diff --git a/typescript/packages/planning-server/src/llm.ts b/typescript/packages/planning-server/src/llm.ts index 626e22bb6..73094585e 100644 --- a/typescript/packages/planning-server/src/llm.ts +++ b/typescript/packages/planning-server/src/llm.ts @@ -1,4 +1,4 @@ -import { anthropic, google, ai, vertex } from "./deps.ts"; +import { anthropic, google, ai, vertex, openai } from "./deps.ts"; import { CoreMessage } from "npm:ai"; import { CoreTool } from "npm:ai"; const { generateText, streamText } = ai; @@ -6,7 +6,9 @@ const { generateText, streamText } = ai; export const OPUS = "claude-3-5-opus-20240307"; export const HAIKU = "claude-3-haiku-20240307"; export const SONNET = "claude-3-5-sonnet-20240620"; -export const LLAMA_3_1_405B = "meta/llama3-405b-instruct-maas"; +export const LLAMA_3_1_405B = "llama3-405b-instruct-maas"; +export const GPT4O_MINI = "gpt-4o-mini"; + const model = anthropic(SONNET); type Model = typeof model; From 10344143c139cb9ab3903d284223c91eef283f34 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:49:25 +1000 Subject: [PATCH 09/43] Local storage persistence of datagems --- Cargo.lock | 164 ++++++++++++++++++++++---- rust/gemcraft-leptos/Cargo.toml | 5 + rust/gemcraft-leptos/src/data.rs | 4 +- rust/gemcraft-leptos/src/db.rs | 58 +++++++++ rust/gemcraft-leptos/src/llm.rs | 4 +- rust/gemcraft-leptos/src/main.rs | 49 ++++++-- rust/gemcraft-leptos/src/micro_app.rs | 33 +++++- 7 files changed, 273 insertions(+), 44 deletions(-) create mode 100644 rust/gemcraft-leptos/src/db.rs diff --git a/Cargo.lock b/Cargo.lock index e3274e3c4..9924e5e0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,18 @@ dependencies = [ "regex", ] +[[package]] +name = "accessory" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87537f9ae7cfa78d5b8ebd1a1db25959f5e737126be4d8eb44a5452fc4b63cde" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -370,9 +382,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -511,13 +523,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -924,6 +935,18 @@ dependencies = [ "uuid", ] +[[package]] +name = "delegate-display" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98a85201f233142ac819bbf6226e36d0b5e129a47bd325084674261c82d4cd66" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "deno_ast" version = "0.39.1" @@ -1211,6 +1234,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +[[package]] +name = "fancy_constructor" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "fastrand" version = "2.1.0" @@ -1391,7 +1426,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "debugid", "fxhash", "serde", @@ -1403,6 +1438,10 @@ name = "gemcraft-leptos" version = "0.1.0" dependencies = [ "console_error_panic_hook", + "gloo-storage", + "gloo-utils", + "indexed_db_futures", + "js-sys", "leptos", "regex", "serde", @@ -1411,6 +1450,7 @@ dependencies = [ "uuid", "wasm-bindgen", "wasm-bindgen-futures", + "web-sys", ] [[package]] @@ -1468,6 +1508,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-utils" version = "0.2.0" @@ -1753,6 +1808,23 @@ dependencies = [ "url", ] +[[package]] +name = "indexed_db_futures" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43315957678a70eb21fb0d2384fe86dde0d6c859a01e24ce127eb65a0143d28c" +dependencies = [ + "accessory", + "cfg-if", + "delegate-display", + "fancy_constructor", + "js-sys", + "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -2072,7 +2144,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -2107,6 +2179,53 @@ dependencies = [ "libc", ] +[[package]] +name = "macroific" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05c00ac596022625d01047c421a0d97d7f09a18e429187b341c201cb631b9dd" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "macroific_macro", +] + +[[package]] +name = "macroific_attr_parse" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd94d5da95b30ae6e10621ad02340909346ad91661f3f8c0f2b62345e46a2f67" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "macroific_core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "macroific_macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c9853143cbed7f1e41dc39fee95f9b361bec65c8dc2a01bf609be01b61f5ae" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "manyhow" version = "0.10.4" @@ -2727,7 +2846,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -2939,7 +3058,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "itoa", "libc", @@ -3524,7 +3643,7 @@ version = "0.113.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1690cc0c9ab60b44ac0225ba1e231ac532f7ba1d754df761c6ee607561afae" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "is-macro", "num-bigint", "phf", @@ -3610,7 +3729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddb95c2bdad1c9c29edf35712e1e0f9b9ddc1cdb5ba2d582fd93468cb075a03" dependencies = [ "better_scoped_tls", - "bitflags 2.5.0", + "bitflags 2.6.0", "indexmap", "once_cell", "phf", @@ -3911,7 +4030,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b858526d22750088a9b3cf2e3c2aacebd5377f13adeec02860c30d09113010a6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cap-fs-ext", "cap-std", "fd-lock", @@ -4117,7 +4236,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "http 1.1.0", "http-body", @@ -4467,6 +4586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", + "wasm-bindgen", ] [[package]] @@ -4670,7 +4790,7 @@ version = "0.202.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6998515d3cf3f8b980ef7c11b29a9b1017d4cf86b99ae93b546992df9931413" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "indexmap", "semver 1.0.23", ] @@ -4682,7 +4802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19bb9f8ab07616da582ef8adb24c54f1424c7ec876720b7da9db8ec0626c92c" dependencies = [ "ahash", - "bitflags 2.5.0", + "bitflags 2.6.0", "hashbrown 0.14.5", "indexmap", "semver 1.0.23", @@ -4695,7 +4815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58" dependencies = [ "ahash", - "bitflags 2.5.0", + "bitflags 2.6.0", "hashbrown 0.14.5", "indexmap", "semver 1.0.23", @@ -4996,7 +5116,7 @@ checksum = "bdbbe94245904d4c96c7c5f7b55bad896cc27908644efd9442063c0748b631fc" dependencies = [ "anyhow", "async-trait", - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "cap-fs-ext", "cap-net-ext", @@ -5106,7 +5226,7 @@ checksum = "a89ea6f74ece6d1cfbd089783006b8eb69a0219ca83cad22068f0d9fa9df3f91" dependencies = [ "anyhow", "async-trait", - "bitflags 2.5.0", + "bitflags 2.6.0", "thiserror", "tracing", "wasmtime", @@ -5361,7 +5481,7 @@ version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "windows-sys 0.52.0", ] @@ -5402,7 +5522,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef83e2f948056d4195b4c2a236a10378b70c8fd7501039c5a106c1a756fa7da6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -5440,7 +5560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c836b1fd9932de0431c1758d8be08212071b6bba0151f7bac826dbc4312a2a9" dependencies = [ "anyhow", - "bitflags 2.5.0", + "bitflags 2.6.0", "indexmap", "log", "serde", @@ -5460,7 +5580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fef7dd0e47f5135dd8739ccc5b188ab8b7e27e1d64df668aa36680f0b8646db8" dependencies = [ "anyhow", - "bitflags 2.5.0", + "bitflags 2.6.0", "indexmap", "log", "serde", diff --git a/rust/gemcraft-leptos/Cargo.toml b/rust/gemcraft-leptos/Cargo.toml index 5f18b1636..9c022b722 100644 --- a/rust/gemcraft-leptos/Cargo.toml +++ b/rust/gemcraft-leptos/Cargo.toml @@ -15,3 +15,8 @@ wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4.42" regex = "1.5.4" uuid = { version = "1.3", features = ["v4"] } +indexed_db_futures = "0.5.0" +js-sys = "0.3.50" +web-sys = "0.3.69" +gloo-storage = "0.3.0" +gloo-utils = "0.2.0" diff --git a/rust/gemcraft-leptos/src/data.rs b/rust/gemcraft-leptos/src/data.rs index 3a77058f4..c0ddd04a1 100644 --- a/rust/gemcraft-leptos/src/data.rs +++ b/rust/gemcraft-leptos/src/data.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] pub struct ClassificationData { pub title: String, #[serde(rename = "contentType")] @@ -9,7 +9,7 @@ pub struct ClassificationData { pub sensitivity: String, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] pub struct DataGem { pub classification: Option, pub description: String, diff --git a/rust/gemcraft-leptos/src/db.rs b/rust/gemcraft-leptos/src/db.rs new file mode 100644 index 000000000..dc512d975 --- /dev/null +++ b/rust/gemcraft-leptos/src/db.rs @@ -0,0 +1,58 @@ +use serde::{Serialize, Deserialize}; +use gloo_storage::{LocalStorage, Storage as GlooStorage}; +use std::collections::HashMap; + +#[derive(Serialize, Deserialize)] +struct Document { + id: String, + data: T, +} + +pub fn save(collection: &str, id: &str, data: &T) -> Result<(), String> { + let doc = Document { + id: id.to_string(), + data: data.clone(), + }; + + let serialized = serde_json::to_string(&doc) + .map_err(|e| format!("Serialization error: {}", e))?; + let key = format!("{}:{}", collection, id); + LocalStorage::set(&key, serialized) + .map_err(|e| format!("Storage error: {}", e))?; + + Ok(()) +} + +pub fn get<'de> Deserialize<'de>>(collection: &str, id: &str) -> Result