From bfc698c49cad5dc99831c4d2df166d8d1109653c Mon Sep 17 00:00:00 2001 From: Silas Date: Tue, 4 Apr 2023 00:00:04 -0400 Subject: [PATCH] Initial commit --- .gitignore | 10 + .npmrc | 1 + .prettierignore | 13 + .prettierrc | 10 + .vercel/output/config.json | 27 + .../.svelte-kit/output/server/chunks/index.js | 78 + .../output/server/chunks/index2.js | 92 + .../output/server/chunks/index3.js | 254 + .../output/server/chunks/internal.js | 187 + .../server/entries/fallbacks/error.svelte.js | 30 + .../server/entries/pages/_layout.svelte.js | 8 + .../server/entries/pages/_page.svelte.js | 402 + .../.svelte-kit/output/server/index.js | 2668 + .../.svelte-kit/output/server/nodes/0.js | 8 + .../.svelte-kit/output/server/nodes/1.js | 8 + .../.svelte-kit/output/server/nodes/2.js | 8 + .../fn-0.func/.svelte-kit/vercel-tmp/index.js | 51 + .../.svelte-kit/vercel-tmp/manifest.js | 27 + .../functions/fn-0.func/.vc-config.json | 6 + .../output/functions/fn-0.func/package.json | 1 + .../functions/fn-1.func/.vc-config.json | 5 + .vercel/output/functions/fn-1.func/index.js | 54593 ++++++++++++++++ .../output/functions/fn-1.func/index.js.map | 7 + .../.svelte-kit/output/server/chunks/index.js | 78 + .../output/server/chunks/index2.js | 92 + .../output/server/chunks/index3.js | 254 + .../output/server/chunks/internal.js | 187 + .../server/entries/fallbacks/error.svelte.js | 30 + .../server/entries/pages/_layout.svelte.js | 8 + .../.svelte-kit/output/server/index.js | 2668 + .../.svelte-kit/output/server/nodes/0.js | 8 + .../.svelte-kit/output/server/nodes/1.js | 8 + .../fn.func/.svelte-kit/vercel-tmp/index.js | 51 + .../.svelte-kit/vercel-tmp/manifest.js | 20 + .../output/functions/fn.func/.vc-config.json | 6 + .vercel/output/functions/fn.func/package.json | 1 + .../immutable/assets/_layout.25f6fdc4.css | 711 + .../immutable/assets/_layout.b9bcc4f4.css | 1 + .../_app/immutable/chunks/0.9f5dfd44.js | 1 + .../_app/immutable/chunks/1.82370e0f.js | 1 + .../_app/immutable/chunks/2.4ed3fbc7.js | 1 + .../_app/immutable/chunks/index.3641fafa.js | 1 + .../_app/immutable/chunks/index.fa397836.js | 1 + .../immutable/chunks/singletons.8077db6c.js | 1 + .../entry/_layout.svelte.62a505d3.js | 1 + .../immutable/entry/_page.svelte.2f89fa28.js | 50 + .../_app/immutable/entry/app.c59518f6.js | 1 + .../immutable/entry/error.svelte.a6bd0229.js | 1 + .../_app/immutable/entry/start.c62adf58.js | 3 + .vercel/output/static/_app/version.json | 1 + .vercel/output/static/favicon.png | Bin 0 -> 1571 bytes README.md | 42 + package-lock.json | 9201 +++ package.json | 45 + postcss.config.cjs | 13 + src/app.css | 39 + src/app.d.ts | 12 + src/app.html | 12 + src/index.test.ts | 7 + src/lib/components/ChatHistory.svelte | 61 + src/lib/components/ChatMessage.svelte | 46 + src/lib/components/Icons/Chat.svelte | 13 + src/lib/components/Icons/Pencil.svelte | 13 + src/lib/components/Icons/Plus.svelte | 13 + src/lib/components/Icons/Trash.svelte | 20 + src/lib/components/Input.svelte | 25 + src/lib/stores/chat-history.ts | 53 + src/lib/stores/chat-messages.ts | 80 + src/lib/utils/tokenizer.ts | 13 + src/routes/+layout.svelte | 7 + src/routes/+page.svelte | 69 + src/routes/api/chat/+server.ts | 115 + src/styles/tailwind.css | 3 + src/styles/vars.css | 11 + src/types/sse.d.ts | 12 + static/favicon.png | Bin 0 -> 1571 bytes svelte.config.js | 23 + tailwind.config.cjs | 9 + tsconfig.json | 18 + vite.config.ts | 10 + 80 files changed, 72665 insertions(+) create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 .vercel/output/config.json create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index2.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index3.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/internal.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/fallbacks/error.svelte.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_layout.svelte.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_page.svelte.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/index.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/nodes/0.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/nodes/1.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/output/server/nodes/2.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/vercel-tmp/index.js create mode 100644 .vercel/output/functions/fn-0.func/.svelte-kit/vercel-tmp/manifest.js create mode 100644 .vercel/output/functions/fn-0.func/.vc-config.json create mode 100644 .vercel/output/functions/fn-0.func/package.json create mode 100644 .vercel/output/functions/fn-1.func/.vc-config.json create mode 100644 .vercel/output/functions/fn-1.func/index.js create mode 100644 .vercel/output/functions/fn-1.func/index.js.map create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/chunks/index.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/chunks/index2.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/chunks/index3.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/chunks/internal.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/entries/fallbacks/error.svelte.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/entries/pages/_layout.svelte.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/index.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/nodes/0.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/output/server/nodes/1.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/vercel-tmp/index.js create mode 100644 .vercel/output/functions/fn.func/.svelte-kit/vercel-tmp/manifest.js create mode 100644 .vercel/output/functions/fn.func/.vc-config.json create mode 100644 .vercel/output/functions/fn.func/package.json create mode 100644 .vercel/output/static/_app/immutable/assets/_layout.25f6fdc4.css create mode 100644 .vercel/output/static/_app/immutable/assets/_layout.b9bcc4f4.css create mode 100644 .vercel/output/static/_app/immutable/chunks/0.9f5dfd44.js create mode 100644 .vercel/output/static/_app/immutable/chunks/1.82370e0f.js create mode 100644 .vercel/output/static/_app/immutable/chunks/2.4ed3fbc7.js create mode 100644 .vercel/output/static/_app/immutable/chunks/index.3641fafa.js create mode 100644 .vercel/output/static/_app/immutable/chunks/index.fa397836.js create mode 100644 .vercel/output/static/_app/immutable/chunks/singletons.8077db6c.js create mode 100644 .vercel/output/static/_app/immutable/entry/_layout.svelte.62a505d3.js create mode 100644 .vercel/output/static/_app/immutable/entry/_page.svelte.2f89fa28.js create mode 100644 .vercel/output/static/_app/immutable/entry/app.c59518f6.js create mode 100644 .vercel/output/static/_app/immutable/entry/error.svelte.a6bd0229.js create mode 100644 .vercel/output/static/_app/immutable/entry/start.c62adf58.js create mode 100644 .vercel/output/static/_app/version.json create mode 100644 .vercel/output/static/favicon.png create mode 100644 README.md create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.cjs create mode 100644 src/app.css create mode 100644 src/app.d.ts create mode 100644 src/app.html create mode 100644 src/index.test.ts create mode 100644 src/lib/components/ChatHistory.svelte create mode 100644 src/lib/components/ChatMessage.svelte create mode 100644 src/lib/components/Icons/Chat.svelte create mode 100644 src/lib/components/Icons/Pencil.svelte create mode 100644 src/lib/components/Icons/Plus.svelte create mode 100644 src/lib/components/Icons/Trash.svelte create mode 100644 src/lib/components/Input.svelte create mode 100644 src/lib/stores/chat-history.ts create mode 100644 src/lib/stores/chat-messages.ts create mode 100644 src/lib/utils/tokenizer.ts create mode 100644 src/routes/+layout.svelte create mode 100644 src/routes/+page.svelte create mode 100644 src/routes/api/chat/+server.ts create mode 100644 src/styles/tailwind.css create mode 100644 src/styles/vars.css create mode 100644 src/types/sse.d.ts create mode 100644 static/favicon.png create mode 100644 svelte.config.js create mode 100644 tailwind.config.cjs create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6635cf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3897265 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..91aa809 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "useTabs": false, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "pluginSearchDirs": ["."], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/.vercel/output/config.json b/.vercel/output/config.json new file mode 100644 index 0000000..2ac9484 --- /dev/null +++ b/.vercel/output/config.json @@ -0,0 +1,27 @@ +{ + "version": 3, + "routes": [ + { + "src": "/_app/immutable/.+", + "headers": { + "cache-control": "public, immutable, max-age=31536000" + } + }, + { + "handle": "filesystem" + }, + { + "src": "^/?(?:/__data.json)?$", + "dest": "/fn-0" + }, + { + "src": "^/api/chat/?(?:/__data.json)?$", + "dest": "/fn-1" + }, + { + "src": "/.*", + "dest": "/fn" + } + ], + "overrides": {} +} \ No newline at end of file diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index.js new file mode 100644 index 0000000..c63b566 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index.js @@ -0,0 +1,78 @@ +let HttpError = class HttpError2 { + /** + * @param {number} status + * @param {{message: string} extends App.Error ? (App.Error | string | undefined) : App.Error} body + */ + constructor(status, body) { + this.status = status; + if (typeof body === "string") { + this.body = { message: body }; + } else if (body) { + this.body = body; + } else { + this.body = { message: `Error: ${status}` }; + } + } + toString() { + return JSON.stringify(this.body); + } +}; +let Redirect = class Redirect2 { + /** + * @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status + * @param {string} location + */ + constructor(status, location) { + this.status = status; + this.location = location; + } +}; +let ActionFailure = class ActionFailure2 { + /** + * @param {number} status + * @param {T} [data] + */ + constructor(status, data) { + this.status = status; + this.data = data; + } +}; +function error(status, message) { + if (isNaN(status) || status < 400 || status > 599) { + throw new Error(`HTTP error status codes must be between 400 and 599 — ${status} is invalid`); + } + return new HttpError(status, message); +} +function json(data, init) { + const body = JSON.stringify(data); + const headers = new Headers(init?.headers); + if (!headers.has("content-length")) { + headers.set("content-length", encoder.encode(body).byteLength.toString()); + } + if (!headers.has("content-type")) { + headers.set("content-type", "application/json"); + } + return new Response(body, { + ...init, + headers + }); +} +const encoder = new TextEncoder(); +function text(body, init) { + const headers = new Headers(init?.headers); + if (!headers.has("content-length")) { + headers.set("content-length", encoder.encode(body).byteLength.toString()); + } + return new Response(body, { + ...init, + headers + }); +} +export { + ActionFailure as A, + HttpError as H, + Redirect as R, + error as e, + json as j, + text as t +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index2.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index2.js new file mode 100644 index 0000000..a9c7097 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index2.js @@ -0,0 +1,92 @@ +import { n as noop, a as subscribe, r as run_all, o as safe_not_equal, p as is_function } from "./index3.js"; +const subscriber_queue = []; +function readable(value, start) { + return { + subscribe: writable(value, start).subscribe + }; +} +function writable(value, start = noop) { + let stop; + const subscribers = /* @__PURE__ */ new Set(); + function set(new_value) { + if (safe_not_equal(value, new_value)) { + value = new_value; + if (stop) { + const run_queue = !subscriber_queue.length; + for (const subscriber of subscribers) { + subscriber[1](); + subscriber_queue.push(subscriber, value); + } + if (run_queue) { + for (let i = 0; i < subscriber_queue.length; i += 2) { + subscriber_queue[i][0](subscriber_queue[i + 1]); + } + subscriber_queue.length = 0; + } + } + } + } + function update(fn) { + set(fn(value)); + } + function subscribe2(run, invalidate = noop) { + const subscriber = [run, invalidate]; + subscribers.add(subscriber); + if (subscribers.size === 1) { + stop = start(set) || noop; + } + run(value); + return () => { + subscribers.delete(subscriber); + if (subscribers.size === 0 && stop) { + stop(); + stop = null; + } + }; + } + return { set, update, subscribe: subscribe2 }; +} +function derived(stores, fn, initial_value) { + const single = !Array.isArray(stores); + const stores_array = single ? [stores] : stores; + const auto = fn.length < 2; + return readable(initial_value, (set) => { + let started = false; + const values = []; + let pending = 0; + let cleanup = noop; + const sync = () => { + if (pending) { + return; + } + cleanup(); + const result = fn(single ? values[0] : values, set); + if (auto) { + set(result); + } else { + cleanup = is_function(result) ? result : noop; + } + }; + const unsubscribers = stores_array.map((store, i) => subscribe(store, (value) => { + values[i] = value; + pending &= ~(1 << i); + if (started) { + sync(); + } + }, () => { + pending |= 1 << i; + })); + started = true; + sync(); + return function stop() { + run_all(unsubscribers); + cleanup(); + started = false; + }; + }); +} +export { + derived as d, + readable as r, + writable as w +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index3.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index3.js new file mode 100644 index 0000000..ab80bef --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/index3.js @@ -0,0 +1,254 @@ +function noop() { +} +function run(fn) { + return fn(); +} +function blank_object() { + return /* @__PURE__ */ Object.create(null); +} +function run_all(fns) { + fns.forEach(run); +} +function is_function(thing) { + return typeof thing === "function"; +} +function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || (a && typeof a === "object" || typeof a === "function"); +} +function subscribe(store, ...callbacks) { + if (store == null) { + return noop; + } + const unsub = store.subscribe(...callbacks); + return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; +} +function get_store_value(store) { + let value; + subscribe(store, (_) => value = _)(); + return value; +} +function compute_rest_props(props, keys) { + const rest = {}; + keys = new Set(keys); + for (const k in props) + if (!keys.has(k) && k[0] !== "$") + rest[k] = props[k]; + return rest; +} +let current_component; +function set_current_component(component) { + current_component = component; +} +function get_current_component() { + if (!current_component) + throw new Error("Function called outside component initialization"); + return current_component; +} +function setContext(key, context) { + get_current_component().$$.context.set(key, context); + return context; +} +function getContext(key) { + return get_current_component().$$.context.get(key); +} +const _boolean_attributes = [ + "allowfullscreen", + "allowpaymentrequest", + "async", + "autofocus", + "autoplay", + "checked", + "controls", + "default", + "defer", + "disabled", + "formnovalidate", + "hidden", + "inert", + "ismap", + "loop", + "multiple", + "muted", + "nomodule", + "novalidate", + "open", + "playsinline", + "readonly", + "required", + "reversed", + "selected" +]; +const boolean_attributes = /* @__PURE__ */ new Set([..._boolean_attributes]); +const void_element_names = /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/; +function is_void(name) { + return void_element_names.test(name) || name.toLowerCase() === "!doctype"; +} +const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; +function spread(args, attrs_to_add) { + const attributes = Object.assign({}, ...args); + if (attrs_to_add) { + const classes_to_add = attrs_to_add.classes; + const styles_to_add = attrs_to_add.styles; + if (classes_to_add) { + if (attributes.class == null) { + attributes.class = classes_to_add; + } else { + attributes.class += " " + classes_to_add; + } + } + if (styles_to_add) { + if (attributes.style == null) { + attributes.style = style_object_to_string(styles_to_add); + } else { + attributes.style = style_object_to_string(merge_ssr_styles(attributes.style, styles_to_add)); + } + } + } + let str = ""; + Object.keys(attributes).forEach((name) => { + if (invalid_attribute_name_character.test(name)) + return; + const value = attributes[name]; + if (value === true) + str += " " + name; + else if (boolean_attributes.has(name.toLowerCase())) { + if (value) + str += " " + name; + } else if (value != null) { + str += ` ${name}="${value}"`; + } + }); + return str; +} +function merge_ssr_styles(style_attribute, style_directive) { + const style_object = {}; + for (const individual_style of style_attribute.split(";")) { + const colon_index = individual_style.indexOf(":"); + const name = individual_style.slice(0, colon_index).trim(); + const value = individual_style.slice(colon_index + 1).trim(); + if (!name) + continue; + style_object[name] = value; + } + for (const name in style_directive) { + const value = style_directive[name]; + if (value) { + style_object[name] = value; + } else { + delete style_object[name]; + } + } + return style_object; +} +const ATTR_REGEX = /[&"]/g; +const CONTENT_REGEX = /[&<]/g; +function escape(value, is_attr = false) { + const str = String(value); + const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; + pattern.lastIndex = 0; + let escaped = ""; + let last = 0; + while (pattern.test(str)) { + const i = pattern.lastIndex - 1; + const ch = str[i]; + escaped += str.substring(last, i) + (ch === "&" ? "&" : ch === '"' ? """ : "<"); + last = i + 1; + } + return escaped + str.substring(last); +} +function escape_attribute_value(value) { + const should_escape = typeof value === "string" || value && typeof value === "object"; + return should_escape ? escape(value, true) : value; +} +function escape_object(obj) { + const result = {}; + for (const key in obj) { + result[key] = escape_attribute_value(obj[key]); + } + return result; +} +function each(items, fn) { + let str = ""; + for (let i = 0; i < items.length; i += 1) { + str += fn(items[i], i); + } + return str; +} +const missing_component = { + $$render: () => "" +}; +function validate_component(component, name) { + if (!component || !component.$$render) { + if (name === "svelte:component") + name += " this={...}"; + throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <${name}>.`); + } + return component; +} +let on_destroy; +function create_ssr_component(fn) { + function $$render(result, props, bindings, slots, context) { + const parent_component = current_component; + const $$ = { + on_destroy, + context: new Map(context || (parent_component ? parent_component.$$.context : [])), + // these will be immediately discarded + on_mount: [], + before_update: [], + after_update: [], + callbacks: blank_object() + }; + set_current_component({ $$ }); + const html = fn(result, props, bindings, slots); + set_current_component(parent_component); + return html; + } + return { + render: (props = {}, { $$slots = {}, context = /* @__PURE__ */ new Map() } = {}) => { + on_destroy = []; + const result = { title: "", head: "", css: /* @__PURE__ */ new Set() }; + const html = $$render(result, props, {}, $$slots, context); + run_all(on_destroy); + return { + html, + css: { + code: Array.from(result.css).map((css) => css.code).join("\n"), + map: null + // TODO + }, + head: result.title + result.head + }; + }, + $$render + }; +} +function add_attribute(name, value, boolean) { + if (value == null || boolean && !value) + return ""; + const assignment = boolean && value === true ? "" : `="${escape(value, true)}"`; + return ` ${name}${assignment}`; +} +function style_object_to_string(style_object) { + return Object.keys(style_object).filter((key) => style_object[key]).map((key) => `${key}: ${escape_attribute_value(style_object[key])};`).join(" "); +} +export { + subscribe as a, + get_store_value as b, + create_ssr_component as c, + each as d, + escape as e, + spread as f, + getContext as g, + escape_object as h, + is_void as i, + add_attribute as j, + compute_rest_props as k, + escape_attribute_value as l, + missing_component as m, + noop as n, + safe_not_equal as o, + is_function as p, + run_all as r, + setContext as s, + validate_component as v +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/internal.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/internal.js new file mode 100644 index 0000000..188a871 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/chunks/internal.js @@ -0,0 +1,187 @@ +import { c as create_ssr_component, s as setContext, v as validate_component, m as missing_component } from "./index3.js"; +let base = ""; +let assets = base; +const initial = { base, assets }; +function reset() { + base = initial.base; + assets = initial.assets; +} +function set_assets(path) { + assets = initial.assets = path; +} +let public_env = {}; +function set_private_env(environment) { +} +function set_public_env(environment) { + public_env = environment; +} +function afterUpdate() { +} +function set_building() { +} +const Root = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let { stores } = $$props; + let { page } = $$props; + let { constructors } = $$props; + let { components = [] } = $$props; + let { form } = $$props; + let { data_0 = null } = $$props; + let { data_1 = null } = $$props; + { + setContext("__svelte__", stores); + } + afterUpdate(stores.page.notify); + if ($$props.stores === void 0 && $$bindings.stores && stores !== void 0) + $$bindings.stores(stores); + if ($$props.page === void 0 && $$bindings.page && page !== void 0) + $$bindings.page(page); + if ($$props.constructors === void 0 && $$bindings.constructors && constructors !== void 0) + $$bindings.constructors(constructors); + if ($$props.components === void 0 && $$bindings.components && components !== void 0) + $$bindings.components(components); + if ($$props.form === void 0 && $$bindings.form && form !== void 0) + $$bindings.form(form); + if ($$props.data_0 === void 0 && $$bindings.data_0 && data_0 !== void 0) + $$bindings.data_0(data_0); + if ($$props.data_1 === void 0 && $$bindings.data_1 && data_1 !== void 0) + $$bindings.data_1(data_1); + let $$settled; + let $$rendered; + do { + $$settled = true; + { + stores.page.set(page); + } + $$rendered = ` + + +${constructors[1] ? `${validate_component(constructors[0] || missing_component, "svelte:component").$$render( + $$result, + { data: data_0, this: components[0] }, + { + this: ($$value) => { + components[0] = $$value; + $$settled = false; + } + }, + { + default: () => { + return `${validate_component(constructors[1] || missing_component, "svelte:component").$$render( + $$result, + { data: data_1, form, this: components[1] }, + { + this: ($$value) => { + components[1] = $$value; + $$settled = false; + } + }, + {} + )}`; + } + } + )}` : `${validate_component(constructors[0] || missing_component, "svelte:component").$$render( + $$result, + { data: data_0, form, this: components[0] }, + { + this: ($$value) => { + components[0] = $$value; + $$settled = false; + } + }, + {} + )}`} + +${``}`; + } while (!$$settled); + return $$rendered; +}); +const options = { + app_template_contains_nonce: false, + csp: { "mode": "auto", "directives": { "upgrade-insecure-requests": false, "block-all-mixed-content": false }, "reportOnly": { "upgrade-insecure-requests": false, "block-all-mixed-content": false } }, + csrf_check_origin: true, + embedded: false, + env_public_prefix: "PUBLIC_", + hooks: null, + // added lazily, via `get_hooks` + preload_strategy: "modulepreload", + root: Root, + service_worker: false, + templates: { + app: ({ head, body, assets: assets2, nonce, env }) => '\n\n \n \n \n \n ' + head + '\n \n \n
' + body + "
\n \n\n", + error: ({ status, message }) => '\n\n \n \n ' + message + ` + + + + +
+ ` + status + '\n
\n

' + message + "

\n
\n
\n \n\n" + }, + version_hash: "10ptubg" +}; +function get_hooks() { + return {}; +} +export { + assets as a, + base as b, + set_assets as c, + set_building as d, + set_private_env as e, + get_hooks as g, + options as o, + public_env as p, + reset as r, + set_public_env as s +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/fallbacks/error.svelte.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/fallbacks/error.svelte.js new file mode 100644 index 0000000..4600756 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/fallbacks/error.svelte.js @@ -0,0 +1,30 @@ +import { g as getContext, c as create_ssr_component, a as subscribe, e as escape } from "../../chunks/index3.js"; +const getStores = () => { + const stores = getContext("__svelte__"); + return { + page: { + subscribe: stores.page.subscribe + }, + navigating: { + subscribe: stores.navigating.subscribe + }, + updated: stores.updated + }; +}; +const page = { + /** @param {(value: any) => void} fn */ + subscribe(fn) { + const store = getStores().page; + return store.subscribe(fn); + } +}; +const Error$1 = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let $page, $$unsubscribe_page; + $$unsubscribe_page = subscribe(page, (value) => $page = value); + $$unsubscribe_page(); + return `

${escape($page.status)}

+

${escape($page.error?.message)}

`; +}); +export { + Error$1 as default +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_layout.svelte.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_layout.svelte.js new file mode 100644 index 0000000..e8bc7e2 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_layout.svelte.js @@ -0,0 +1,8 @@ +import { c as create_ssr_component } from "../../chunks/index3.js"; +const app = ""; +const Layout = create_ssr_component(($$result, $$props, $$bindings, slots) => { + return `
${slots.default ? slots.default({}) : ``}
`; +}); +export { + Layout as default +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_page.svelte.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_page.svelte.js new file mode 100644 index 0000000..099e2d0 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/entries/pages/_page.svelte.js @@ -0,0 +1,402 @@ +import { c as create_ssr_component, b as get_store_value, a as subscribe$1, v as validate_component, d as each, e as escape, g as getContext, m as missing_component, f as spread, h as escape_object, i as is_void, j as add_attribute, k as compute_rest_props, l as escape_attribute_value } from "../../chunks/index3.js"; +import { SSE } from "sse.js"; +import { w as writable, d as derived } from "../../chunks/index2.js"; +import { marked } from "marked"; +import DOMPurify from "isomorphic-dompurify"; +const Chat = create_ssr_component(($$result, $$props, $$bindings, slots) => { + return ``; +}); +const Pencil = create_ssr_component(($$result, $$props, $$bindings, slots) => { + return ``; +}); +const Plus = create_ssr_component(($$result, $$props, $$bindings, slots) => { + return ``; +}); +const Trash = create_ssr_component(($$result, $$props, $$bindings, slots) => { + return ``; +}); +const { subscribe, update, ...store } = writable({ + messages: [ + { role: "assistant", content: "Welcome! Please introduce yourself to your AI competitor." } + ], + chatState: "idle" +}); +const set = async (query) => { + updateMessages(query, "user", "loading"); + request(); +}; +const request = async (query) => { + const eventSource = new SSE("/api/chat", { + headers: { + "Content-Type": "application/json" + }, + payload: JSON.stringify({ messages: get_store_value(chatMessages).messages }) + }); + eventSource.addEventListener("error", handleError); + eventSource.addEventListener("message", streamMessage); + eventSource.stream(); +}; +const replace = (messages) => { + store.set(messages); +}; +const reset = () => store.set({ + messages: [ + { role: "assistant", content: "Welcome! Please introduce yourself to your AI competitor." } + ], + chatState: "idle" +}); +const updateMessages = (content, role, state) => { + chatMessages.update((messages) => { + return { messages: [...messages.messages, { role, content }], chatState: state }; + }); +}; +const handleError = (err) => { + updateMessages(err, "system", "error"); + console.error(err); +}; +const streamMessage = (e) => { + try { + if (e.data === "[DONE]") { + updateMessages(get_store_value(answer), "assistant", "idle"); + return answer.set(""); + } + if (get_store_value(answer) === "...") + answer.set(""); + const completionResponse = JSON.parse(e.data); + const [{ delta }] = completionResponse.choices; + if (delta.content) { + answer.update((_a) => _a + delta.content); + } + } catch (err) { + handleError(err); + } +}; +const chatMessages = { subscribe, set, update, reset, replace }; +const answer = writable(""); +const chatHistory = derived(chatMessages, ($chatMessages) => { + return null; +}); +const ChatHistory = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let $$unsubscribe_chatHistory; + $$unsubscribe_chatHistory = subscribe$1(chatHistory, (value) => value); + let chatHistoryKeys = []; + $$unsubscribe_chatHistory(); + return `
+ + ${chatHistoryKeys.length > 0 ? `${each(chatHistoryKeys, (message) => { + return ` +
${validate_component(Chat, "Chat").$$render($$result, {}, {}, {})} +
${escape(message)}
+ +
+
+
`; + })}` : ``}
`; +}); +const componentsContextKey = {}; +const getComponentsContext = () => getContext(componentsContextKey); +const Renderer = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let $components, $$unsubscribe_components; + let { astNode } = $$props; + let { __index = 0 } = $$props; + let { type = void 0 } = $$props; + let { position = void 0 } = $$props; + const components = getComponentsContext(); + $$unsubscribe_components = subscribe$1(components, (value) => $components = value); + if ($$props.astNode === void 0 && $$bindings.astNode && astNode !== void 0) + $$bindings.astNode(astNode); + if ($$props.__index === void 0 && $$bindings.__index && __index !== void 0) + $$bindings.__index(__index); + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.position === void 0 && $$bindings.position && position !== void 0) + $$bindings.position(position); + $$unsubscribe_components(); + return `${astNode.type === "root" ? `${validate_component(Children, "Children").$$render($$result, Object.assign({}, astNode), {}, {})}` : `${astNode.type === "element" ? `${validate_component($components[astNode.tagName] || missing_component, "svelte:component").$$render($$result, Object.assign({}, astNode, { __index }), {}, {})}` : `${$components[astNode.type] !== void 0 ? `${validate_component($components[astNode.type] || missing_component, "svelte:component").$$render($$result, Object.assign({}, astNode, { __index }), {}, {})}` : ``}`}`}`; +}); +const Children = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let { children } = $$props; + let { type = void 0 } = $$props; + let { position = void 0 } = $$props; + let { __index = void 0 } = $$props; + if ($$props.children === void 0 && $$bindings.children && children !== void 0) + $$bindings.children(children); + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.position === void 0 && $$bindings.position && position !== void 0) + $$bindings.position(position); + if ($$props.__index === void 0 && $$bindings.__index && __index !== void 0) + $$bindings.__index(__index); + return `${each(children, (child, __index2) => { + return `${validate_component(Renderer, "Renderer").$$render($$result, { astNode: child, __index: __index2 }, {}, {})}`; + })}`; +}); +const Default = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let { tagName } = $$props; + let { children } = $$props; + let { properties } = $$props; + let { type = void 0 } = $$props; + let { position = void 0 } = $$props; + let { __index = void 0 } = $$props; + if ($$props.tagName === void 0 && $$bindings.tagName && tagName !== void 0) + $$bindings.tagName(tagName); + if ($$props.children === void 0 && $$bindings.children && children !== void 0) + $$bindings.children(children); + if ($$props.properties === void 0 && $$bindings.properties && properties !== void 0) + $$bindings.properties(properties); + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.position === void 0 && $$bindings.position && position !== void 0) + $$bindings.position(position); + if ($$props.__index === void 0 && $$bindings.__index && __index !== void 0) + $$bindings.__index(__index); + return `${Array.isArray(children) && children.length !== 0 ? ` + ${((tag) => { + return tag ? `<${tagName}${spread([escape_object(properties)], {})}>${is_void(tag) ? "" : `${validate_component(Children, "Children").$$render($$result, { children }, {}, {})}`}${is_void(tag) ? "" : ``}` : ""; + })(tagName)}` : ` + ${((tag) => { + return tag ? `<${tagName}${spread([escape_object(properties)], {})}>${is_void(tag) ? "" : ``}${is_void(tag) ? "" : ``}` : ""; + })(tagName)}`}`; +}); +const defaultTags = [ + // Content sectioning + "address", + "article", + "aside", + "footer", + "header", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "main", + "nav", + "section", + // Text content + "blockquote", + "dd", + "div", + "dl", + "dt", + "figcaption", + "figure", + "hr", + "li", + "menu", + "ol", + "p", + "pre", + "ul", + // Inline text semantics + "a", + "abbr", + "b", + "bdi", + "bdo", + "br", + "cite", + "code", + "data", + "dfn", + "em", + "i", + "kbd", + "mark", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "small", + "span", + "strong", + "sub", + "sup", + "time", + "u", + "var", + "wbr", + // Image and multimedia + "area", + "audio", + "img", + "map", + "track", + "video", + // Embedded content + "embed", + "iframe", + "object", + "param", + "picture", + "portal", + "source", + // SVG and MathML + "svg", + "math", + // Demarcating edits + "del", + "ins", + // Table content + "caption", + "col", + "colgroup", + "table", + "tbody", + "td", + "tfoot", + "th", + "thead", + "tr", + // Forms + "button", + "datalist", + "fieldset", + "form", + "input", + "label", + "legend", + "meter", + "optgroup", + "option", + "output", + "progress", + "select", + "textarea", + // Interactive elements + "details", + "dialog", + "summary" +]; +const htmlComponents = defaultTags.reduce((acc, tag) => ({ ...acc, [tag]: Default }), {}); +const Text = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let { value = "" } = $$props; + let { type = void 0 } = $$props; + let { position = void 0 } = $$props; + let { __index = void 0 } = $$props; + if ($$props.value === void 0 && $$bindings.value && value !== void 0) + $$bindings.value(value); + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.position === void 0 && $$bindings.position && position !== void 0) + $$bindings.position(position); + if ($$props.__index === void 0 && $$bindings.__index && __index !== void 0) + $$bindings.__index(__index); + return `${escape(value)}`; +}); +({ + ...htmlComponents, + text: Text, + raw: Text +}); +const ChatMessage = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let { type } = $$props; + let { message = "" } = $$props; + let { class: classes = "" } = $$props; + let scrollToDiv; + const classSet = { + user: "justify-end text-rose-700", + assistant: "justify-start text-teal-400", + system: "justify-center text-gray-400" + }; + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.message === void 0 && $$bindings.message && message !== void 0) + $$bindings.message(message); + if ($$props.class === void 0 && $$bindings.class && classes !== void 0) + $$bindings.class(classes); + return `

${escape(type === "user" ? "Me" : "Bot")}

+ +
${DOMPurify.sanitize(marked.parse(message))}
+
`; +}); +const Input = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let $$restProps = compute_rest_props($$props, ["value", "placeholder", "name", "type", "label", "class"]); + let { value } = $$props; + let { placeholder = "" } = $$props; + let { name = "" } = $$props; + let { type = "text" } = $$props; + let { label = "" } = $$props; + let { class: classes = "" } = $$props; + if ($$props.value === void 0 && $$bindings.value && value !== void 0) + $$bindings.value(value); + if ($$props.placeholder === void 0 && $$bindings.placeholder && placeholder !== void 0) + $$bindings.placeholder(placeholder); + if ($$props.name === void 0 && $$bindings.name && name !== void 0) + $$bindings.name(name); + if ($$props.type === void 0 && $$bindings.type && type !== void 0) + $$bindings.type(type); + if ($$props.label === void 0 && $$bindings.label && label !== void 0) + $$bindings.label(label); + if ($$props.class === void 0 && $$bindings.class && classes !== void 0) + $$bindings.class(classes); + return `
+
`; +}); +const Page = create_ssr_component(($$result, $$props, $$bindings, slots) => { + let $chatMessages, $$unsubscribe_chatMessages; + let $answer, $$unsubscribe_answer; + $$unsubscribe_chatMessages = subscribe$1(chatMessages, (value) => $chatMessages = value); + $$unsubscribe_answer = subscribe$1(answer, (value) => $answer = value); + let query = ""; + let $$settled; + let $$rendered; + do { + $$settled = true; + $$rendered = `
${validate_component(ChatHistory, "ChatHistory").$$render($$result, {}, {}, {})}
+ +
${each($chatMessages.messages, (message) => { + return `${validate_component(ChatMessage, "ChatMessage").$$render( + $$result, + { + type: message.role, + message: message.content + }, + {}, + {} + )}`; + })} + + ${$answer ? `${validate_component(ChatMessage, "ChatMessage").$$render($$result, { type: "assistant", message: $answer }, {}, {})}` : ``}
+
${validate_component(Input, "Input").$$render( + $$result, + { + type: "text", + class: "w-full", + value: query + }, + { + value: ($$value) => { + query = $$value; + $$settled = false; + } + }, + {} + )} +
`; + } while (!$$settled); + $$unsubscribe_chatMessages(); + $$unsubscribe_answer(); + return $$rendered; +}); +export { + Page as default +}; diff --git a/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/index.js b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/index.js new file mode 100644 index 0000000..6b6ece3 --- /dev/null +++ b/.vercel/output/functions/fn-0.func/.svelte-kit/output/server/index.js @@ -0,0 +1,2668 @@ +import { b as base, a as assets, r as reset, p as public_env, o as options, g as get_hooks, s as set_public_env } from "./chunks/internal.js"; +import { H as HttpError, j as json, t as text, R as Redirect, e as error, A as ActionFailure } from "./chunks/index.js"; +import * as devalue from "devalue"; +import { w as writable, r as readable } from "./chunks/index2.js"; +import { parse, serialize } from "cookie"; +import * as set_cookie_parser from "set-cookie-parser"; +const DEV = false; +function negotiate(accept, types) { + const parts = []; + accept.split(",").forEach((str, i) => { + const match = /([^/]+)\/([^;]+)(?:;q=([0-9.]+))?/.exec(str); + if (match) { + const [, type, subtype, q = "1"] = match; + parts.push({ type, subtype, q: +q, i }); + } + }); + parts.sort((a, b) => { + if (a.q !== b.q) { + return b.q - a.q; + } + if (a.subtype === "*" !== (b.subtype === "*")) { + return a.subtype === "*" ? 1 : -1; + } + if (a.type === "*" !== (b.type === "*")) { + return a.type === "*" ? 1 : -1; + } + return a.i - b.i; + }); + let accepted; + let min_priority = Infinity; + for (const mimetype of types) { + const [type, subtype] = mimetype.split("/"); + const priority = parts.findIndex( + (part) => (part.type === type || part.type === "*") && (part.subtype === subtype || part.subtype === "*") + ); + if (priority !== -1 && priority < min_priority) { + accepted = mimetype; + min_priority = priority; + } + } + return accepted; +} +function is_content_type(request, ...types) { + const type = request.headers.get("content-type")?.split(";", 1)[0].trim() ?? ""; + return types.includes(type); +} +function is_form_content_type(request) { + return is_content_type(request, "application/x-www-form-urlencoded", "multipart/form-data"); +} +function coalesce_to_error(err) { + return err instanceof Error || err && /** @type {any} */ + err.name && /** @type {any} */ + err.message ? ( + /** @type {Error} */ + err + ) : new Error(JSON.stringify(err)); +} +function normalize_error(error2) { + return ( + /** @type {Redirect | HttpError | Error} */ + error2 + ); +} +function method_not_allowed(mod, method) { + return text(`${method} method not allowed`, { + status: 405, + headers: { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 + // "The server must generate an Allow header field in a 405 status code response" + allow: allowed_methods(mod).join(", ") + } + }); +} +function allowed_methods(mod) { + const allowed = []; + for (const method in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) { + if (method in mod) + allowed.push(method); + } + if (mod.GET || mod.HEAD) + allowed.push("HEAD"); + return allowed; +} +function static_error_page(options2, status, message) { + let page = options2.templates.error({ status, message }); + return text(page, { + headers: { "content-type": "text/html; charset=utf-8" }, + status + }); +} +async function handle_fatal_error(event, options2, error2) { + error2 = error2 instanceof HttpError ? error2 : coalesce_to_error(error2); + const status = error2 instanceof HttpError ? error2.status : 500; + const body = await handle_error_and_jsonify(event, options2, error2); + const type = negotiate(event.request.headers.get("accept") || "text/html", [ + "application/json", + "text/html" + ]); + if (event.isDataRequest || type === "application/json") { + return json(body, { + status + }); + } + return static_error_page(options2, status, body.message); +} +async function handle_error_and_jsonify(event, options2, error2) { + if (error2 instanceof HttpError) { + return error2.body; + } else { + return await options2.hooks.handleError({ error: error2, event }) ?? { + message: event.route.id != null ? "Internal Error" : "Not Found" + }; + } +} +function redirect_response(status, location) { + const response = new Response(void 0, { + status, + headers: { location } + }); + return response; +} +function clarify_devalue_error(event, error2) { + if (error2.path) { + return `Data returned from \`load\` while rendering ${event.route.id} is not serializable: ${error2.message} (data${error2.path})`; + } + if (error2.path === "") { + return `Data returned from \`load\` while rendering ${event.route.id} is not a plain object`; + } + return error2.message; +} +function stringify_uses(node) { + const uses = []; + if (node.uses && node.uses.dependencies.size > 0) { + uses.push(`"dependencies":${JSON.stringify(Array.from(node.uses.dependencies))}`); + } + if (node.uses && node.uses.params.size > 0) { + uses.push(`"params":${JSON.stringify(Array.from(node.uses.params))}`); + } + if (node.uses?.parent) + uses.push(`"parent":1`); + if (node.uses?.route) + uses.push(`"route":1`); + if (node.uses?.url) + uses.push(`"url":1`); + return `"uses":{${uses.join(",")}}`; +} +async function render_endpoint(event, mod, state) { + const method = ( + /** @type {import('types').HttpMethod} */ + event.request.method + ); + let handler = mod[method]; + if (!handler && method === "HEAD") { + handler = mod.GET; + } + if (!handler) { + return method_not_allowed(mod, method); + } + const prerender = mod.prerender ?? state.prerender_default; + if (prerender && (mod.POST || mod.PATCH || mod.PUT || mod.DELETE)) { + throw new Error("Cannot prerender endpoints that have mutative methods"); + } + if (state.prerendering && !prerender) { + if (state.depth > 0) { + throw new Error(`${event.route.id} is not prerenderable`); + } else { + return new Response(void 0, { status: 204 }); + } + } + try { + const response = await handler( + /** @type {import('types').RequestEvent>} */ + event + ); + if (!(response instanceof Response)) { + throw new Error( + `Invalid response from route ${event.url.pathname}: handler should return a Response object` + ); + } + if (state.prerendering) { + response.headers.set("x-sveltekit-prerender", String(prerender)); + } + return response; + } catch (e) { + if (e instanceof Redirect) { + return new Response(void 0, { + status: e.status, + headers: { location: e.location } + }); + } + throw e; + } +} +function is_endpoint_request(event) { + const { method, headers } = event.request; + if (method === "PUT" || method === "PATCH" || method === "DELETE" || method === "OPTIONS") { + return true; + } + if (method === "POST" && headers.get("x-sveltekit-action") === "true") + return false; + const accept = event.request.headers.get("accept") ?? "*/*"; + return negotiate(accept, ["*", "text/html"]) !== "text/html"; +} +function compact(arr) { + return arr.filter( + /** @returns {val is NonNullable} */ + (val) => val != null + ); +} +function normalize_path(path, trailing_slash) { + if (path === "/" || trailing_slash === "ignore") + return path; + if (trailing_slash === "never") { + return path.endsWith("/") ? path.slice(0, -1) : path; + } else if (trailing_slash === "always" && !path.endsWith("/")) { + return path + "/"; + } + return path; +} +function decode_pathname(pathname) { + return pathname.split("%25").map(decodeURI).join("%25"); +} +function decode_params(params) { + for (const key2 in params) { + params[key2] = decodeURIComponent(params[key2]); + } + return params; +} +const tracked_url_properties = ["href", "pathname", "search", "searchParams", "toString", "toJSON"]; +function make_trackable(url, callback) { + const tracked = new URL(url); + for (const property of tracked_url_properties) { + let value = tracked[property]; + Object.defineProperty(tracked, property, { + get() { + callback(); + return value; + }, + enumerable: true, + configurable: true + }); + } + { + tracked[Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { + return inspect(url, opts); + }; + } + disable_hash(tracked); + return tracked; +} +function disable_hash(url) { + Object.defineProperty(url, "hash", { + get() { + throw new Error( + "Cannot access event.url.hash. Consider using `$page.url.hash` inside a component instead" + ); + } + }); +} +function disable_search(url) { + for (const property of ["search", "searchParams"]) { + Object.defineProperty(url, property, { + get() { + throw new Error(`Cannot access url.${property} on a page with prerendering enabled`); + } + }); + } +} +const DATA_SUFFIX = "/__data.json"; +function has_data_suffix(pathname) { + return pathname.endsWith(DATA_SUFFIX); +} +function add_data_suffix(pathname) { + return pathname.replace(/\/$/, "") + DATA_SUFFIX; +} +function strip_data_suffix(pathname) { + return pathname.slice(0, -DATA_SUFFIX.length); +} +function is_action_json_request(event) { + const accept = negotiate(event.request.headers.get("accept") ?? "*/*", [ + "application/json", + "text/html" + ]); + return accept === "application/json" && event.request.method === "POST"; +} +async function handle_action_json_request(event, options2, server) { + const actions = server?.actions; + if (!actions) { + const no_actions_error = error(405, "POST method not allowed. No actions exist for this page"); + return action_json( + { + type: "error", + error: await handle_error_and_jsonify(event, options2, no_actions_error) + }, + { + status: no_actions_error.status, + headers: { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 + // "The server must generate an Allow header field in a 405 status code response" + allow: "GET" + } + } + ); + } + check_named_default_separate(actions); + try { + const data = await call_action(event, actions); + if (false) + ; + if (data instanceof ActionFailure) { + return action_json({ + type: "failure", + status: data.status, + // @ts-expect-error we assign a string to what is supposed to be an object. That's ok + // because we don't use the object outside, and this way we have better code navigation + // through knowing where the related interface is used. + data: stringify_action_response( + data.data, + /** @type {string} */ + event.route.id + ) + }); + } else { + return action_json({ + type: "success", + status: data ? 200 : 204, + // @ts-expect-error see comment above + data: stringify_action_response( + data, + /** @type {string} */ + event.route.id + ) + }); + } + } catch (e) { + const err = normalize_error(e); + if (err instanceof Redirect) { + return action_json({ + type: "redirect", + status: err.status, + location: err.location + }); + } + return action_json( + { + type: "error", + error: await handle_error_and_jsonify(event, options2, check_incorrect_fail_use(err)) + }, + { + status: err instanceof HttpError ? err.status : 500 + } + ); + } +} +function check_incorrect_fail_use(error2) { + return error2 instanceof ActionFailure ? new Error(`Cannot "throw fail()". Use "return fail()"`) : error2; +} +function action_json(data, init2) { + return json(data, init2); +} +function is_action_request(event) { + return event.request.method === "POST"; +} +async function handle_action_request(event, server) { + const actions = server?.actions; + if (!actions) { + event.setHeaders({ + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 + // "The server must generate an Allow header field in a 405 status code response" + allow: "GET" + }); + return { + type: "error", + error: error(405, "POST method not allowed. No actions exist for this page") + }; + } + check_named_default_separate(actions); + try { + const data = await call_action(event, actions); + if (false) + ; + if (data instanceof ActionFailure) { + return { + type: "failure", + status: data.status, + data: data.data + }; + } else { + return { + type: "success", + status: 200, + // @ts-expect-error this will be removed upon serialization, so `undefined` is the same as omission + data + }; + } + } catch (e) { + const err = normalize_error(e); + if (err instanceof Redirect) { + return { + type: "redirect", + status: err.status, + location: err.location + }; + } + return { + type: "error", + error: check_incorrect_fail_use(err) + }; + } +} +function check_named_default_separate(actions) { + if (actions.default && Object.keys(actions).length > 1) { + throw new Error( + `When using named actions, the default action cannot be used. See the docs for more info: https://kit.svelte.dev/docs/form-actions#named-actions` + ); + } +} +async function call_action(event, actions) { + const url = new URL(event.request.url); + let name = "default"; + for (const param of url.searchParams) { + if (param[0].startsWith("/")) { + name = param[0].slice(1); + if (name === "default") { + throw new Error('Cannot use reserved action name "default"'); + } + break; + } + } + const action = actions[name]; + if (!action) { + throw new Error(`No action with name '${name}' found`); + } + if (!is_form_content_type(event.request)) { + throw new Error( + `Actions expect form-encoded data (received ${event.request.headers.get("content-type")})` + ); + } + return action(event); +} +function validate_action_return(data) { + if (data instanceof Redirect) { + throw new Error(`Cannot \`return redirect(...)\` — use \`throw redirect(...)\` instead`); + } + if (data instanceof HttpError) { + throw new Error( + `Cannot \`return error(...)\` — use \`throw error(...)\` or \`return fail(...)\` instead` + ); + } +} +function uneval_action_response(data, route_id) { + return try_deserialize(data, devalue.uneval, route_id); +} +function stringify_action_response(data, route_id) { + return try_deserialize(data, devalue.stringify, route_id); +} +function try_deserialize(data, fn, route_id) { + try { + return fn(data); + } catch (e) { + const error2 = ( + /** @type {any} */ + e + ); + if ("path" in error2) { + let message = `Data returned from action inside ${route_id} is not serializable: ${error2.message}`; + if (error2.path !== "") + message += ` (data.${error2.path})`; + throw new Error(message); + } + throw error2; + } +} +async function unwrap_promises(object) { + for (const key2 in object) { + if (typeof object[key2]?.then === "function") { + return Object.fromEntries( + await Promise.all(Object.entries(object).map(async ([key3, value]) => [key3, await value])) + ); + } + } + return object; +} +async function load_server_data({ event, state, node, parent }) { + if (!node?.server) + return null; + const uses = { + dependencies: /* @__PURE__ */ new Set(), + params: /* @__PURE__ */ new Set(), + parent: false, + route: false, + url: false + }; + const url = make_trackable(event.url, () => { + uses.url = true; + }); + if (state.prerendering) { + disable_search(url); + } + const result = await node.server.load?.call(null, { + ...event, + fetch: (info, init2) => { + const url2 = new URL(info instanceof Request ? info.url : info, event.url); + uses.dependencies.add(url2.href); + return event.fetch(info, init2); + }, + /** @param {string[]} deps */ + depends: (...deps) => { + for (const dep of deps) { + const { href } = new URL(dep, event.url); + uses.dependencies.add(href); + } + }, + params: new Proxy(event.params, { + get: (target, key2) => { + uses.params.add(key2); + return target[ + /** @type {string} */ + key2 + ]; + } + }), + parent: async () => { + uses.parent = true; + return parent(); + }, + route: new Proxy(event.route, { + get: (target, key2) => { + uses.route = true; + return target[ + /** @type {'id'} */ + key2 + ]; + } + }), + url + }); + const data = result ? await unwrap_promises(result) : null; + return { + type: "data", + data, + uses, + slash: node.server.trailingSlash + }; +} +async function load_data({ + event, + fetched, + node, + parent, + server_data_promise, + state, + resolve_opts, + csr +}) { + const server_data_node = await server_data_promise; + if (!node?.universal?.load) { + return server_data_node?.data ?? null; + } + const result = await node.universal.load.call(null, { + url: event.url, + params: event.params, + data: server_data_node?.data ?? null, + route: event.route, + fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), + setHeaders: event.setHeaders, + depends: () => { + }, + parent + }); + const data = result ? await unwrap_promises(result) : null; + return data; +} +function create_universal_fetch(event, state, fetched, csr, resolve_opts) { + return async (input, init2) => { + const cloned_body = input instanceof Request && input.body ? input.clone().body : null; + let response = await event.fetch(input, init2); + const url = new URL(input instanceof Request ? input.url : input, event.url); + const same_origin = url.origin === event.url.origin; + let dependency; + if (same_origin) { + if (state.prerendering) { + dependency = { response, body: null }; + state.prerendering.dependencies.set(url.pathname, dependency); + } + } else { + const mode = input instanceof Request ? input.mode : init2?.mode ?? "cors"; + if (mode === "no-cors") { + response = new Response("", { + status: response.status, + statusText: response.statusText, + headers: response.headers + }); + } else { + const acao = response.headers.get("access-control-allow-origin"); + if (!acao || acao !== event.url.origin && acao !== "*") { + throw new Error( + `CORS error: ${acao ? "Incorrect" : "No"} 'Access-Control-Allow-Origin' header is present on the requested resource` + ); + } + } + } + const proxy = new Proxy(response, { + get(response2, key2, _receiver) { + async function text2() { + const body = await response2.text(); + if (!body || typeof body === "string") { + const status_number = Number(response2.status); + if (isNaN(status_number)) { + throw new Error( + `response.status is not a number. value: "${response2.status}" type: ${typeof response2.status}` + ); + } + fetched.push({ + url: same_origin ? url.href.slice(event.url.origin.length) : url.href, + method: event.request.method, + request_body: ( + /** @type {string | ArrayBufferView | undefined} */ + input instanceof Request && cloned_body ? await stream_to_string(cloned_body) : init2?.body + ), + request_headers: init2?.headers, + response_body: body, + response: response2 + }); + } + if (dependency) { + dependency.body = body; + } + return body; + } + if (key2 === "arrayBuffer") { + return async () => { + const buffer = await response2.arrayBuffer(); + if (dependency) { + dependency.body = new Uint8Array(buffer); + } + return buffer; + }; + } + if (key2 === "text") { + return text2; + } + if (key2 === "json") { + return async () => { + return JSON.parse(await text2()); + }; + } + return Reflect.get(response2, key2, response2); + } + }); + if (csr) { + const get = response.headers.get; + response.headers.get = (key2) => { + const lower = key2.toLowerCase(); + const value = get.call(response.headers, lower); + if (value && !lower.startsWith("x-sveltekit-")) { + const included = resolve_opts.filterSerializedResponseHeaders(lower, value); + if (!included) { + throw new Error( + `Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#server-hooks-handle (at ${event.route.id})` + ); + } + } + return value; + }; + } + return proxy; + }; +} +async function stream_to_string(stream) { + let result = ""; + const reader = stream.getReader(); + const decoder = new TextDecoder(); + while (true) { + const { done, value } = await reader.read(); + if (done) { + break; + } + result += decoder.decode(value); + } + return result; +} +function hash(...values) { + let hash2 = 5381; + for (const value of values) { + if (typeof value === "string") { + let i = value.length; + while (i) + hash2 = hash2 * 33 ^ value.charCodeAt(--i); + } else if (ArrayBuffer.isView(value)) { + const buffer = new Uint8Array(value.buffer, value.byteOffset, value.byteLength); + let i = buffer.length; + while (i) + hash2 = hash2 * 33 ^ buffer[--i]; + } else { + throw new TypeError("value must be a string or TypedArray"); + } + } + return (hash2 >>> 0).toString(36); +} +const escape_html_attr_dict = { + "&": "&", + '"': """ +}; +const escape_html_attr_regex = new RegExp( + // special characters + `[${Object.keys(escape_html_attr_dict).join("")}]|[\\ud800-\\udbff](?![\\udc00-\\udfff])|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\udc00-\\udfff]`, + "g" +); +function escape_html_attr(str) { + const escaped_str = str.replace(escape_html_attr_regex, (match) => { + if (match.length === 2) { + return match; + } + return escape_html_attr_dict[match] ?? `&#${match.charCodeAt(0)};`; + }); + return `"${escaped_str}"`; +} +const replacements = { + "<": "\\u003C", + "\u2028": "\\u2028", + "\u2029": "\\u2029" +}; +const pattern = new RegExp(`[${Object.keys(replacements).join("")}]`, "g"); +function serialize_data(fetched, filter, prerendering = false) { + const headers = {}; + let cache_control = null; + let age = null; + let vary = false; + for (const [key2, value] of fetched.response.headers) { + if (filter(key2, value)) { + headers[key2] = value; + } + if (key2 === "cache-control") + cache_control = value; + if (key2 === "age") + age = value; + if (key2 === "vary") + vary = true; + } + const payload = { + status: fetched.response.status, + statusText: fetched.response.statusText, + headers, + body: fetched.response_body + }; + const safe_payload = JSON.stringify(payload).replace(pattern, (match) => replacements[match]); + const attrs = [ + 'type="application/json"', + "data-sveltekit-fetched", + `data-url=${escape_html_attr(fetched.url)}` + ]; + if (fetched.request_headers || fetched.request_body) { + const values = []; + if (fetched.request_headers) { + values.push([...new Headers(fetched.request_headers)].join(",")); + } + if (fetched.request_body) { + values.push(fetched.request_body); + } + attrs.push(`data-hash="${hash(...values)}"`); + } + if (!prerendering && fetched.method === "GET" && cache_control && !vary) { + const match = /s-maxage=(\d+)/g.exec(cache_control) ?? /max-age=(\d+)/g.exec(cache_control); + if (match) { + const ttl = +match[1] - +(age ?? "0"); + attrs.push(`data-ttl="${ttl}"`); + } + } + return ` + +
+ + + {#if chatHistoryKeys.length > 0} + {#each chatHistoryKeys as message (message)} + +
loadMessages(message)} + class="flex py-3 px-3 items-center gap-3 relative rounded-md cursor-pointer break-all pr-14 bg-opacity-40 hover:bg-white/5 bg-black group animate-flash text-sm" + > + +
{message}
+ +
+ + +
+
+ {/each} + {/if} +
diff --git a/src/lib/components/ChatMessage.svelte b/src/lib/components/ChatMessage.svelte new file mode 100644 index 0000000..b4c8f0f --- /dev/null +++ b/src/lib/components/ChatMessage.svelte @@ -0,0 +1,46 @@ + + +
+

{type === 'user' ? 'Me' : 'Bot'}

+
+ +
+
+ {@html DOMPurify.sanitize(marked.parse(message))} +
+
+
diff --git a/src/lib/components/Icons/Chat.svelte b/src/lib/components/Icons/Chat.svelte new file mode 100644 index 0000000..67561ab --- /dev/null +++ b/src/lib/components/Icons/Chat.svelte @@ -0,0 +1,13 @@ + diff --git a/src/lib/components/Icons/Pencil.svelte b/src/lib/components/Icons/Pencil.svelte new file mode 100644 index 0000000..3a357f9 --- /dev/null +++ b/src/lib/components/Icons/Pencil.svelte @@ -0,0 +1,13 @@ + diff --git a/src/lib/components/Icons/Plus.svelte b/src/lib/components/Icons/Plus.svelte new file mode 100644 index 0000000..d93ee0b --- /dev/null +++ b/src/lib/components/Icons/Plus.svelte @@ -0,0 +1,13 @@ + diff --git a/src/lib/components/Icons/Trash.svelte b/src/lib/components/Icons/Trash.svelte new file mode 100644 index 0000000..179af4d --- /dev/null +++ b/src/lib/components/Icons/Trash.svelte @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/src/lib/components/Input.svelte b/src/lib/components/Input.svelte new file mode 100644 index 0000000..26263cd --- /dev/null +++ b/src/lib/components/Input.svelte @@ -0,0 +1,25 @@ + + +
+ + +
diff --git a/src/lib/stores/chat-history.ts b/src/lib/stores/chat-history.ts new file mode 100644 index 0000000..4e66d89 --- /dev/null +++ b/src/lib/stores/chat-history.ts @@ -0,0 +1,53 @@ +import { derived, get, writable } from 'svelte/store'; +import { chatMessages, type ChatTranscript } from './chat-messages'; +import { browser } from '$app/environment'; + +export const chatHistorySubscription = writable(); + +const setLocalHistory = (history: T) => + localStorage.setItem('chatHistory', JSON.stringify(history)); +const getLocalHistory = () => JSON.parse(localStorage.getItem('chatHistory') || '{}'); + +export const chatHistory = derived(chatMessages, ($chatMessages) => { + if (!browser) return null; + + let history = localStorage.getItem('chatHistory'); + + if (!history && $chatMessages.messages.length === 1) return null; + + if (history && $chatMessages.messages.length === 1) return JSON.parse(history); + + const key = $chatMessages.messages[1].content; //The second message is the query + const value = $chatMessages.messages; + const obj = { [key]: value }; + + if (!history) setLocalHistory(obj); + + const chatHistory = getLocalHistory(); + + if (chatHistory) { + chatHistory[key] = value; + setLocalHistory(chatHistory); + chatHistorySubscription.set(chatHistory); + return chatHistory; + } + + return null; +}); + +export const filterHistory = (key: string) => { + const history = getLocalHistory(); + delete history[key]; + setLocalHistory(history); + chatHistorySubscription.set(history); +}; + +const getHistory = (key: string) => getLocalHistory()[key]; //Returns the history for a given key + +export const loadMessages = (query: string) => { + if (get(chatMessages).chatState !== 'idle') return; //Prevents switching between messages while loading + if (!query) return; + + const newMessages = getHistory(query); + chatMessages.replace({ messages: newMessages, chatState: 'idle' }); +}; diff --git a/src/lib/stores/chat-messages.ts b/src/lib/stores/chat-messages.ts new file mode 100644 index 0000000..9b33414 --- /dev/null +++ b/src/lib/stores/chat-messages.ts @@ -0,0 +1,80 @@ +import type { ChatCompletionRequestMessage } from 'openai'; +import { SSE } from 'sse.js'; +import { get, writable } from 'svelte/store'; + +export interface ChatTranscript { + messages: ChatCompletionRequestMessage[]; + chatState: 'idle' | 'loading' | 'error' | 'message'; +} + +const { subscribe, update, ...store } = writable({ + messages: [ + { role: 'assistant', content: 'Welcome! Please introduce yourself to your AI competitor.'} + ], + chatState: 'idle' +}); + +const set = async (query: string) => { + updateMessages(query, 'user', 'loading'); + + request(query); +}; + +const request = async (query: string) => { + const eventSource = new SSE('/api/chat', { + headers: { + 'Content-Type': 'application/json' + }, + payload: JSON.stringify({ messages: get(chatMessages).messages }) + }); + + eventSource.addEventListener('error', handleError); + eventSource.addEventListener('message', streamMessage); + eventSource.stream(); +} + +const replace = (messages: ChatTranscript) => { + store.set(messages); +}; + +const reset = () => + store.set({ + messages: [ + { role: 'assistant', content: 'Welcome! Please introduce yourself to your AI competitor.' } + ], + chatState: 'idle' + }); + +const updateMessages = (content: any, role: any, state: any) => { + chatMessages.update((messages: ChatTranscript) => { + return { messages: [...messages.messages, { role: role, content: content }], chatState: state }; + }); +}; + +const handleError = (err: T) => { + updateMessages(err, 'system', 'error'); + console.error(err); +}; + +const streamMessage = (e: MessageEvent) => { + try { + if (e.data === '[DONE]') { + updateMessages(get(answer), 'assistant', 'idle'); + return answer.set(''); + } + + if (get(answer) === '...') answer.set(''); + + const completionResponse = JSON.parse(e.data); + const [{ delta }] = completionResponse.choices; + + if (delta.content) { + answer.update((_a) => _a + delta.content); + } + } catch (err) { + handleError(err); + } +}; + +export const chatMessages = { subscribe, set, update, reset, replace }; +export const answer = writable(''); diff --git a/src/lib/utils/tokenizer.ts b/src/lib/utils/tokenizer.ts new file mode 100644 index 0000000..e187a9c --- /dev/null +++ b/src/lib/utils/tokenizer.ts @@ -0,0 +1,13 @@ +import GPT3TokenizerImport from 'gpt3-tokenizer'; + +const GPT3Tokenizer: typeof GPT3TokenizerImport = + typeof GPT3TokenizerImport === 'function' + ? GPT3TokenizerImport + : (GPT3TokenizerImport as any).default; + +const tokenizer = new GPT3Tokenizer({ type: 'gpt3' }); + +export function getTokens(input: string): number { + const tokens = tokenizer.encode(input); + return tokens.text.length; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..4e377fb --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..5559e71 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,69 @@ + + +
+
+ +
+ +
+
+
+ {#each $chatMessages.messages as message} + + {/each} + + {#if $answer} + + {/if} +
+
+
+ + +
+
+
diff --git a/src/routes/api/chat/+server.ts b/src/routes/api/chat/+server.ts new file mode 100644 index 0000000..bbdd6b6 --- /dev/null +++ b/src/routes/api/chat/+server.ts @@ -0,0 +1,115 @@ +import { OPENAI_KEY } from '$env/static/private'; +import type { CreateChatCompletionRequest, ChatCompletionRequestMessage } from 'openai'; +import type { RequestHandler } from './$types'; +import { getTokens } from '$lib/utils/tokenizer'; +import { json } from '@sveltejs/kit'; +import type { Config } from '@sveltejs/adapter-vercel'; + +export const config: Config = { + runtime: 'edge' +}; + +const INITIAL_QUERY = `You are playing a game with the user. You will erroneously define a randomly chosen English word with the definition of an English word that sounds similar. You will then ask them to guess the correct word for the errornous definition. + + Here is an example of what you would output. + + --- + + Nice to meet you. Today we'll be playing a word game. Here's how it works: I will define a word. But the definition I give it will actually be for a different but similarly-sounding word. You'll have to guess the correct word that is being defined. + + Ready to begin? Here's the first one: + + "A photon is a legendary bird which according to one account lived 500 years, burned itself to ashes on a pyre, and rose alive from the ashes to live another period. What word am I actually describing?" + + --- + + To further explain the output, I chose two words that sound similar, photon and phoenix. I am then using the definition of a phoenix to describe a photon, and the user will have to guess that the real word I'm describing is a phoenix. + + Repeat this process until the user incorrectly guesses 3 times.`; + +export const POST: RequestHandler = async ({ request }) => { + try { + if (!OPENAI_KEY) { + throw new Error('OPENAI_KEY env variable not set'); + } + + const requestData = await request.json(); + + if (!requestData) { + throw new Error('No request data'); + } + + const reqMessages: ChatCompletionRequestMessage[] = requestData.messages; + + if (!reqMessages) { + throw new Error('no messages provided'); + } + + let tokenCount = 0; + + reqMessages.forEach((msg) => { + const tokens = getTokens(msg.content); + tokenCount += tokens; + }); + + const moderationRes = await fetch('https://api.openai.com/v1/moderations', { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${OPENAI_KEY}` + }, + method: 'POST', + body: JSON.stringify({ + input: reqMessages[reqMessages.length - 1].content + }) + }); + + const moderationData = await moderationRes.json(); + const [results] = moderationData.results; + + if (results.flagged) { + throw new Error('Query flagged by openai'); + } + + const prompt = INITIAL_QUERY; + tokenCount += getTokens(prompt); + + if (tokenCount >= 4000) { + throw new Error('Query too large'); + } + + const messages: ChatCompletionRequestMessage[] = [ + { role: 'system', content: prompt }, + ...reqMessages + ]; + + const chatRequestOpts: CreateChatCompletionRequest = { + model: 'gpt-3.5-turbo', + messages, + temperature: 0.5, + stream: true + }; + + const chatResponse = await fetch('https://api.openai.com/v1/chat/completions', { + headers: { + Authorization: `Bearer ${OPENAI_KEY}`, + 'Content-Type': 'application/json' + }, + method: 'POST', + body: JSON.stringify(chatRequestOpts) + }); + + if (!chatResponse.ok) { + const err = await chatResponse.json(); + throw new Error(err); + } + + return new Response(chatResponse.body, { + headers: { + 'Content-Type': 'text/event-stream' + } + }); + } catch (err) { + console.error(err); + return json({ error: 'There was an error processing your request' }, { status: 500 }); + } +}; diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/src/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/src/styles/vars.css b/src/styles/vars.css new file mode 100644 index 0000000..01528a7 --- /dev/null +++ b/src/styles/vars.css @@ -0,0 +1,11 @@ +:root { + --cyan-100: 183 90% 90%; + --cyan-200: 183 90% 80%; + --cyan-300: 183 90% 70%; + --cyan-400: 183 90% 60%; + --cyan-500: 183 90% 50%; + --cyan-600: 183 90% 40%; + --cyan-700: 183 90% 30%; + --cyan-800: 183 90% 20%; + --cyan-900: 183 90% 10%; +} diff --git a/src/types/sse.d.ts b/src/types/sse.d.ts new file mode 100644 index 0000000..0cf88b3 --- /dev/null +++ b/src/types/sse.d.ts @@ -0,0 +1,12 @@ +declare module 'sse.js' { + export type SSEOptions = EventSourceInit & { + headers?: Record + payload?: string + method?: string + } + + export class SSE extends EventSource { + constructor(url: string | URL, sseOptions?: SSEOptions) + stream(): void + } +} diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH