mirror of
https://github.com/geoffsee/open-gsio.git
synced 2025-09-08 22:56:46 +00:00
fix build
This commit is contained in:
18
.dev.vars
18
.dev.vars
@@ -1,9 +1,9 @@
|
||||
OPENAI_API_KEY=
|
||||
EVENTSOURCE_HOST=
|
||||
GROQ_API_KEY=
|
||||
ANTHROPIC_API_KEY=
|
||||
FIREWORKS_API_KEY=
|
||||
XAI_API_KEY=
|
||||
CEREBRAS_API_KEY=
|
||||
CLOUDFLARE_API_KEY=
|
||||
CLOUDFLARE_ACCOUNT_ID=
|
||||
OPENAI_API_KEY=your-value
|
||||
EVENTSOURCE_HOST=http://some-event-host:3005
|
||||
GROQ_API_KEY=your-value
|
||||
ANTHROPIC_API_KEY=your-value
|
||||
FIREWORKS_API_KEY=your-value
|
||||
XAI_API_KEY=your-value
|
||||
CEREBRAS_API_KEY=your-value
|
||||
CLOUDFLARE_API_KEY=your-value
|
||||
CLOUDFLARE_ACCOUNT_ID=your-value
|
12
README.md
12
README.md
@@ -11,11 +11,11 @@ Fork of [geoff.seemueller.io](https://geoff.seemueller.io).
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. `bun i`
|
||||
2. `bun run build`
|
||||
1. `pnpm i`
|
||||
2. `pnpm run build`
|
||||
3. Configure .dev.vars
|
||||
4. Setup KV_STORAGE bindings for local development.
|
||||
5. In isolated shells, run `bun run worker:dev` and `bun run vite:dev`
|
||||
5. In isolated shells, run `pnpm run worker:dev` and `pnpm run vite:dev`
|
||||
|
||||
|
||||
### Further Documentation
|
||||
@@ -29,7 +29,7 @@ History
|
||||
| Hash | Change |
|
||||
| ------- | --------------------------------------------------------------------- |
|
||||
| 049bf97 | **Add** *seemueller.ai* sidebar link and constrain Hero heading width |
|
||||
| 6be5f68 | **Consolidate** configuration files (CI, bundler, environment) |
|
||||
| 6be5f68 | **Consolidate** configuration files (CI, pnpmdler, environment) |
|
||||
| a047f19 | **Expand** Markdown usage guide for end‑users |
|
||||
|
||||
---
|
||||
@@ -40,7 +40,7 @@ History
|
||||
| ----------------- | --------------------------------------------------------------------------- |
|
||||
| ce3457a | **Introduce** custom error page and purge dead code |
|
||||
| 806c933 | **Fix** duplicate`robots.txt` entries (SEO) |
|
||||
| 4bbe8ea · e909e0b | **Restore** bundle‑size safeguards and **switch** toBun as package manager |
|
||||
| 4bbe8ea · e909e0b | **Restore** pnpmdle‑size safeguards and **switch** topnpm as package manager |
|
||||
| 7f1520b·aa71f86 | **Automate** VPN block‑list deployment; retire legacy pull script |
|
||||
| b332c93 | **Repair** CI job for block‑list updates |
|
||||
| d506e7d | **Deprecate** experimental **Mixtral** model |
|
||||
@@ -53,7 +53,7 @@ History
|
||||
| ----------------- | ------------------------------------------------------------------------ |
|
||||
| 8b9e9eb | **Add** per‑model `max_tokens` limits |
|
||||
| cb0d912 | **Expose** Cloudflare AI models for staging |
|
||||
| 85de6ed·cec4f70 | **Shrink** production bundles: re‑enable minifier and drop unused assets |
|
||||
| 85de6ed·cec4f70 | **Shrink** production pnpmdles: re‑enable minifier and drop unused assets |
|
||||
| 4805c7e · 9709f61 | **Refresh** landing‑page copy (“Welcomehome”) |
|
||||
|
||||
---
|
||||
|
53
bun.lock
53
bun.lock
@@ -56,11 +56,12 @@
|
||||
"typescript": "^5.7.2",
|
||||
"vike": "0.4.193",
|
||||
"vite": "^5.4.11",
|
||||
"wrangler": "^4.14.4",
|
||||
"wrangler": "^4.16.1",
|
||||
"zod": "^3.23.8",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/runtime-corejs3": "^7.26.0",
|
||||
"@cloudflare/vite-plugin": "^1.2.4",
|
||||
"babel-plugin-inferno": "^6.7.2",
|
||||
"compression": "^1.7.5",
|
||||
"express": "^4.21.2",
|
||||
@@ -313,17 +314,19 @@
|
||||
|
||||
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
|
||||
|
||||
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.1", "", { "peerDependencies": { "unenv": "2.0.0-rc.15", "workerd": "^1.20250320.0" }, "optionalPeers": ["workerd"] }, "sha512-Xq57Qd+ADpt6hibcVBO0uLG9zzRgyRhfCUgBT9s+g3+3Ivg5zDyVgLFy40ES1VdNcu8rPNSivm9A+kGP5IVaPg=="],
|
||||
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.2", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-MtUgNl+QkQyhQvv5bbWP+BpBC1N0me4CHHuP2H4ktmOMKdB/6kkz/lo+zqiA4mEazb4y+1cwyNjVrQ2DWeE4mg=="],
|
||||
|
||||
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250507.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xC+8hmQuOUUNCVT9DWpLMfxhR4Xs4kI8v7Bkybh4pzGC85moH6fMfCBNaP0YQCNAA/BR56aL/AwfvMVGskTK/A=="],
|
||||
"@cloudflare/vite-plugin": ["@cloudflare/vite-plugin@1.2.4", "", { "dependencies": { "@cloudflare/unenv-preset": "2.3.2", "@mjackson/node-fetch-server": "^0.6.1", "@rollup/plugin-replace": "^6.0.1", "get-port": "^7.1.0", "miniflare": "4.20250508.3", "picocolors": "^1.1.1", "tinyglobby": "^0.2.12", "unenv": "2.0.0-rc.17", "wrangler": "4.16.1", "ws": "8.18.0" }, "peerDependencies": { "vite": "^6.1.0" } }, "sha512-Oc5P4cicZrqGAmlCX9DA8KmMK85rXczZBZU7IjnUeOxsPqh/KVgDy2XOVqYvXbbznm1LHceTG6fPMCMcAcj7DQ=="],
|
||||
|
||||
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250507.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Oynff5H8yM4trfUFaKdkOvPV3jac8mg7QC19ILZluCVgLx/JGEVLEJ7do1Na9rLqV8CK4gmUXPrUMX7uerhQgg=="],
|
||||
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250508.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-9x09MrA9Y5RQs3zqWvWns8xHgM2pVNXWpeJ+3hQYu4PrwPFZXtTD6b/iMmOnlYKzINlREq1RGeEybMFyWEUlUg=="],
|
||||
|
||||
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250507.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/HAA+Zg/R7Q/Smyl835FUFKjotZN1UzN9j/BHBd0xKmKov97QkXAX8gsyGnyKqRReIOinp8x/8+UebTICR7VJw=="],
|
||||
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250508.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0Ili+nE2LLRzYue/yPc1pepSyNNg6LxR3/ng/rlQzVQUxPXIXldHFkJ/ynsYwQnAcf6OxasSi/kbTm6yvDoSAQ=="],
|
||||
|
||||
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250507.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-NMPibSdOYeycU0IrKkgOESFJQy7dEpHvuatZxQxlT+mIQK0INzI3irp2kKxhF99s25kPC4p+xg9bU3ugTrs3VQ=="],
|
||||
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250508.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5saVrZ3uVwYxvBa7BaonXjeqB6X0YF3ak05qvBaWcmZ3FNmnarMm2W8842cnbhnckDVBpB/iDo51Sy6Y7y1jcw=="],
|
||||
|
||||
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250507.0", "", { "os": "win32", "cpu": "x64" }, "sha512-c91fhNP8ufycdIDqjVyKTqeb4ewkbAYXFQbLreMVgh4LLQQPDDEte8wCdmaFy5bIL0M9d85PpdCq51RCzq/FaQ=="],
|
||||
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250508.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-muQe1pkxRi3eaq1Q417xvfGd2SlktbLTzNhT5Yftsx8OecWrYuB8i4ttR6Nr5ER06bfEj0FqQjqJJhcp6wLLUQ=="],
|
||||
|
||||
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250508.0", "", { "os": "win32", "cpu": "x64" }, "sha512-EJj8iTWFMqjgvZUxxNvzK7frA1JMFi3y/9eDIdZPL/OaQh3cmk5Lai5DCXsKYUxfooMBZWYTp53zOLrvuJI8VQ=="],
|
||||
|
||||
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250404.0", "", {}, "sha512-XB8LNS9spWcxU56Tt/RPl0S06oyXfZCSDVKBbzjHYZtgN5kZP4UtTR01t16HUfo330EtJOo8cdo/PbiBAwRNIg=="],
|
||||
|
||||
@@ -625,6 +628,8 @@
|
||||
|
||||
"@mdxeditor/gurx": ["@mdxeditor/gurx@1.2.3", "", { "peerDependencies": { "react": ">= 18 || >= 19", "react-dom": ">= 18 || >= 19" } }, "sha512-5DQOlEx46oN9spggrC8husAGAhVoEFBGIYKN48es08XhRUbSU6l5bcIQYwRrQaY8clU1tExIcXzw8/fNnoxjpg=="],
|
||||
|
||||
"@mjackson/node-fetch-server": ["@mjackson/node-fetch-server@0.6.1", "", {}, "sha512-9ZJnk/DJjt805uv5PPv11haJIW+HHf3YEEyVXv+8iLQxLD/iXA68FH220XoiTPBC4gCg5q+IMadDw8qPqlA5wg=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
@@ -713,6 +718,10 @@
|
||||
|
||||
"@react-hook/passive-layout-effect": ["@react-hook/passive-layout-effect@1.2.1", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg=="],
|
||||
|
||||
"@rollup/plugin-replace": ["@rollup/plugin-replace@6.0.2", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "magic-string": "^0.30.3" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ=="],
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.39.0", "", { "os": "android", "cpu": "arm" }, "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.39.0", "", { "os": "android", "cpu": "arm64" }, "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ=="],
|
||||
@@ -1031,6 +1040,8 @@
|
||||
|
||||
"estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="],
|
||||
|
||||
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||
@@ -1057,6 +1068,8 @@
|
||||
|
||||
"fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
|
||||
|
||||
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="],
|
||||
@@ -1091,6 +1104,8 @@
|
||||
|
||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
|
||||
"get-port": ["get-port@7.1.0", "", {}, "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
|
||||
"get-source": ["get-source@2.0.12", "", { "dependencies": { "data-uri-to-buffer": "^2.0.0", "source-map": "^0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="],
|
||||
@@ -1237,6 +1252,8 @@
|
||||
|
||||
"lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
"manifold-workflow-engine": ["manifold-workflow-engine@2.1.1", "", { "bin": { "manifold-workflow-engine": "dist/cli.js" } }, "sha512-qFU50/H7NxOQVw7DV5YZxX1VqknnZ5jw3r2lNcahiJmrjI4oByrvb99shUwCsepVhFiJsUM+5ViGGDZW9UW1CA=="],
|
||||
|
||||
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
|
||||
@@ -1383,7 +1400,7 @@
|
||||
|
||||
"mimetext": ["mimetext@3.0.27", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@babel/runtime-corejs3": "^7.26.0", "js-base64": "^3.7.7", "mime-types": "^2.1.35" } }, "sha512-mUhWAsZD1N/K6dbN4+a5Yq78OPnYQw1ubOSMasBntsLQ2S7KVNlvDEA8dwpr4a7PszWMzeslKahAprtwYMgaBA=="],
|
||||
|
||||
"miniflare": ["miniflare@4.20250507.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250507.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-EgbQRt/Hnr8HCmW2J/4LRNE3yOzJTdNd98XJ8gnGXFKcimXxUFPiWP3k1df+ZPCtEHp6cXxi8+jP7v9vuIbIsg=="],
|
||||
"miniflare": ["miniflare@4.20250508.3", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250508.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-43oTmZ0CCmUcieetI5YDDyX0IiwhOcVIWzdBBCqWXK3F1XgQwg4d3fTqRyJnCmHIoaYx9CE1kTEKZC1UahPQhA=="],
|
||||
|
||||
"mobx": ["mobx@6.13.7", "", {}, "sha512-aChaVU/DO5aRPmk1GX8L+whocagUUpBQqoPtJk+cm7UOXUk87J4PeWCh6nNmTTIfEhiR9DI/+FnA8dln/hTK7g=="],
|
||||
|
||||
@@ -1453,7 +1470,7 @@
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
|
||||
|
||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||
|
||||
@@ -1639,6 +1656,8 @@
|
||||
|
||||
"terser": ["terser@5.39.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
|
||||
|
||||
"tldts": ["tldts@6.1.85", "", { "dependencies": { "tldts-core": "^6.1.85" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w=="],
|
||||
|
||||
"tldts-core": ["tldts-core@6.1.85", "", {}, "sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA=="],
|
||||
@@ -1669,13 +1688,13 @@
|
||||
|
||||
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
|
||||
|
||||
"ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="],
|
||||
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
|
||||
|
||||
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
||||
|
||||
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
"unenv": ["unenv@2.0.0-rc.15", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA=="],
|
||||
"unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
|
||||
|
||||
"unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="],
|
||||
|
||||
@@ -1751,11 +1770,11 @@
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"workerd": ["workerd@1.20250507.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250507.0", "@cloudflare/workerd-darwin-arm64": "1.20250507.0", "@cloudflare/workerd-linux-64": "1.20250507.0", "@cloudflare/workerd-linux-arm64": "1.20250507.0", "@cloudflare/workerd-windows-64": "1.20250507.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-OXaGjEh5THT9iblwWIyPrYBoaPe/d4zN03Go7/w8CmS8sma7//O9hjbk43sboWkc89taGPmU0/LNyZUUiUlHeQ=="],
|
||||
"workerd": ["workerd@1.20250508.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250508.0", "@cloudflare/workerd-darwin-arm64": "1.20250508.0", "@cloudflare/workerd-linux-64": "1.20250508.0", "@cloudflare/workerd-linux-arm64": "1.20250508.0", "@cloudflare/workerd-windows-64": "1.20250508.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-ffLxe7dXSuGoA6jb3Qx2SClIV1aLHfJQ6RhGhzYHjQgv7dL6fdUOSIIGgzmu2mRKs+WFSujp6c8WgKquco6w3w=="],
|
||||
|
||||
"wrangler": ["wrangler@4.14.4", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.1", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250507.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.15", "workerd": "1.20250507.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250507.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-HIdOdiMIcJV5ymw80RKsr3Uzen/p1kRX4jnCEmR2XVeoEhV2Qw6GABxS5WMTlSES2/vEX0Y+ezUAdsprcUhJ5g=="],
|
||||
"wrangler": ["wrangler@4.16.1", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.2", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250508.3", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250508.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250508.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-YiLdWXcaQva2K/bqokpsZbySPmoT8TJFyJPsQPZumnkgimM9+/g/yoXArByA+pf+xU8jhw7ybQ8X1yBGXv731g=="],
|
||||
|
||||
"ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="],
|
||||
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||
|
||||
"xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="],
|
||||
|
||||
@@ -1809,18 +1828,20 @@
|
||||
|
||||
"jsdom/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
|
||||
|
||||
"jsdom/ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="],
|
||||
|
||||
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"mdast-util-frontmatter/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"micromark/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||
|
||||
"miniflare/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||
|
||||
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
|
||||
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
13
package.json
13
package.json
@@ -35,18 +35,7 @@
|
||||
"tail:image-generation-service": "wrangler tail -c workers/image-generation-service/wrangler-image-generation-service.toml",
|
||||
"tail:session-proxy": "wrangler tail -c workers/session-proxy/wrangler-session-proxy.toml --env production"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/runtime-corejs3": "^7.26.0",
|
||||
"babel-plugin-inferno": "^6.7.2",
|
||||
"compression": "^1.7.5",
|
||||
"express": "^4.21.2",
|
||||
"kill-port": "^2.0.1",
|
||||
"llama3-tokenizer-js": "^1.2.0",
|
||||
"mimetext": "^3.0.24",
|
||||
"replicate": "^1.0.1",
|
||||
"scheduler": "^0.23.2",
|
||||
"suspend-react": "^0.1.3",
|
||||
"together-ai": "^0.7.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.32.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
|
9431
pnpm-lock.yaml
generated
Normal file
9431
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -175,6 +175,7 @@ const CustomKatex: React.FC<{ math: string; displayMode: boolean }> = ({
|
||||
<Box
|
||||
as="span"
|
||||
display={displayMode ? "block" : "inline"}
|
||||
// bg={bg}
|
||||
p={displayMode ? 4 : 1}
|
||||
my={displayMode ? 4 : 0}
|
||||
borderRadius="md"
|
||||
|
@@ -1,16 +1,48 @@
|
||||
const SUPPORTED_MODELS_GROUPS = {
|
||||
openai: [],
|
||||
openai: [
|
||||
// "o1-preview",
|
||||
// "o1-mini",
|
||||
// "gpt-4o",
|
||||
// "gpt-3.5-turbo"
|
||||
],
|
||||
groq: [
|
||||
// "mixtral-8x7b-32768",
|
||||
// "deepseek-r1-distill-llama-70b",
|
||||
"meta-llama/llama-4-scout-17b-16e-instruct",
|
||||
"gemma2-9b-it",
|
||||
"mistral-saba-24b",
|
||||
// "qwen-2.5-32b",
|
||||
"llama-3.3-70b-versatile",
|
||||
// "llama-3.3-70b-versatile"
|
||||
// "llama-3.1-70b-versatile",
|
||||
// "llama-3.3-70b-versatile"
|
||||
],
|
||||
cerebras: ["llama-3.3-70b"],
|
||||
claude: [],
|
||||
fireworks: [],
|
||||
google: [],
|
||||
xai: [],
|
||||
claude: [
|
||||
// "claude-3-5-sonnet-20241022",
|
||||
// "claude-3-opus-20240229"
|
||||
],
|
||||
fireworks: [
|
||||
// "llama-v3p1-405b-instruct",
|
||||
// "llama-v3p1-70b-instruct",
|
||||
// "llama-v3p2-90b-vision-instruct",
|
||||
// "mixtral-8x22b-instruct",
|
||||
// "mythomax-l2-13b",
|
||||
// "yi-large"
|
||||
],
|
||||
google: [
|
||||
// "gemini-2.0-flash-exp",
|
||||
// "gemini-1.5-flash",
|
||||
// "gemini-exp-1206",
|
||||
// "gemini-1.5-pro"
|
||||
],
|
||||
xai: [
|
||||
// "grok-beta",
|
||||
// "grok-2",
|
||||
// "grok-2-1212",
|
||||
// "grok-2-latest",
|
||||
// "grok-beta"
|
||||
],
|
||||
cloudflareAI: [
|
||||
"llama-3.2-3b-instruct", // max_tokens
|
||||
"llama-3-8b-instruct", // max_tokens
|
||||
@@ -22,28 +54,33 @@ const SUPPORTED_MODELS_GROUPS = {
|
||||
"mistral-7b-instruct-v0.2",
|
||||
"neural-chat-7b-v3-1-awq",
|
||||
"openchat-3.5-0106",
|
||||
// "gemma-7b-it",
|
||||
],
|
||||
};
|
||||
|
||||
export type SupportedModel =
|
||||
| keyof typeof SUPPORTED_MODELS_GROUPS
|
||||
| (typeof SUPPORTED_MODELS_GROUPS)[keyof typeof SUPPORTED_MODELS_GROUPS][number];
|
||||
| keyof typeof SUPPORTED_MODELS_GROUPS
|
||||
| (typeof SUPPORTED_MODELS_GROUPS)[keyof typeof SUPPORTED_MODELS_GROUPS][number];
|
||||
|
||||
export type ModelFamily = keyof typeof SUPPORTED_MODELS_GROUPS;
|
||||
|
||||
function getModelFamily(model: string): ModelFamily | undefined {
|
||||
return Object.keys(SUPPORTED_MODELS_GROUPS)
|
||||
.filter((family) => {
|
||||
return SUPPORTED_MODELS_GROUPS[
|
||||
family as keyof typeof SUPPORTED_MODELS_GROUPS
|
||||
].includes(model.trim());
|
||||
})
|
||||
.at(0) as ModelFamily | undefined;
|
||||
.filter((family) => {
|
||||
return SUPPORTED_MODELS_GROUPS[
|
||||
family as keyof typeof SUPPORTED_MODELS_GROUPS
|
||||
].includes(model.trim());
|
||||
})
|
||||
.at(0) as ModelFamily | undefined;
|
||||
}
|
||||
|
||||
const SUPPORTED_MODELS = [
|
||||
// ...SUPPORTED_MODELS_GROUPS.xai,
|
||||
// ...SUPPORTED_MODELS_GROUPS.claude,
|
||||
// ...SUPPORTED_MODELS_GROUPS.google,
|
||||
...SUPPORTED_MODELS_GROUPS.groq,
|
||||
...SUPPORTED_MODELS_GROUPS.fireworks,
|
||||
// ...SUPPORTED_MODELS_GROUPS.openai,
|
||||
...SUPPORTED_MODELS_GROUPS.cerebras,
|
||||
...SUPPORTED_MODELS_GROUPS.cloudflareAI,
|
||||
];
|
||||
|
@@ -89,6 +89,7 @@ function ConnectComponent() {
|
||||
onChange={(e) => handleChange("lastname")(e.target.value)}
|
||||
color="text.primary"
|
||||
borderColor="text.primary"
|
||||
// bg="text.primary"
|
||||
/>
|
||||
</HStack>
|
||||
<Input
|
||||
@@ -107,6 +108,7 @@ function ConnectComponent() {
|
||||
</Box>
|
||||
<Button
|
||||
variant="outline"
|
||||
// colorScheme="blackAlpha"
|
||||
onClick={handleSubmitButton}
|
||||
alignSelf="flex-end"
|
||||
size="md"
|
||||
|
@@ -42,7 +42,10 @@ export const webComponents = {
|
||||
),
|
||||
ul: ({ children }) => (
|
||||
<UnorderedList
|
||||
// pl={3}
|
||||
// mb={2}
|
||||
fontSize="sm"
|
||||
// stylePosition="inside" // Keep bullets inside the text flow
|
||||
>
|
||||
{children}
|
||||
</UnorderedList>
|
||||
@@ -56,7 +59,12 @@ export const webComponents = {
|
||||
li: ({ children, ...rest }) => {
|
||||
const filteredChildren = React.Children.toArray(children)
|
||||
.filter((child) => !(typeof child === "string" && child.trim() === "\n"))
|
||||
.map((child) => child);
|
||||
.map((child, index, array) => {
|
||||
// if (typeof child === 'string' && index === array.length - 1 && /\n/.test(child)) {
|
||||
// return '\n';
|
||||
// }
|
||||
return child;
|
||||
});
|
||||
|
||||
return <ListItem {...rest}>{filteredChildren}</ListItem>;
|
||||
},
|
||||
|
@@ -8,6 +8,7 @@ function NavItem({ path, children, color, onClick, as, cursor }) {
|
||||
href={path}
|
||||
mb={2}
|
||||
cursor={cursor}
|
||||
// ml={5}
|
||||
mr={2}
|
||||
color={color ?? "text.accent"}
|
||||
letterSpacing="normal"
|
||||
|
@@ -118,6 +118,7 @@ const components = {
|
||||
bg: "background.primary",
|
||||
color: "text.primary",
|
||||
boxShadow: "md",
|
||||
// p: 4,
|
||||
|
||||
".mdxeditor-toolbar": {
|
||||
border: "1px solid",
|
||||
@@ -126,6 +127,8 @@ const components = {
|
||||
bg: "background.primary",
|
||||
m: 2,
|
||||
p: 2,
|
||||
// mb: 3,
|
||||
// p: 3,
|
||||
|
||||
"& button": {
|
||||
border: "none",
|
||||
@@ -150,6 +153,7 @@ const components = {
|
||||
boxShadow: "0 0 0 2px var(--text-primary)",
|
||||
transform: "translateY(-1px)",
|
||||
transition: "all 0.2s ease",
|
||||
// border: '2px solid transparent', // No border needed for SVG
|
||||
},
|
||||
'&[data-state="off"]': {
|
||||
bg: "transparent",
|
||||
@@ -169,6 +173,7 @@ const components = {
|
||||
CodeBlocks: {
|
||||
baseStyle: (props) => ({
|
||||
bg: "background.primary",
|
||||
// color: 'text.primary',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
@@ -1,5 +1,9 @@
|
||||
export default {
|
||||
"/": { sidebarLabel: "Home", heroLabel: "g.s" },
|
||||
// "/about": { sidebarLabel: "About", heroLabel: "About Me" },
|
||||
// "/resume": { sidebarLabel: "Resume", heroLabel: "resume" },
|
||||
// "/demo": { sidebarLabel: "Demo", heroLabel: "Demos" },
|
||||
// "/services": { sidebarLabel: "Services", heroLabel: "services" },
|
||||
"/connect": { sidebarLabel: "Connect", heroLabel: "connect" },
|
||||
"/privacy-policy": {
|
||||
sidebarLabel: "",
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import react from "@vitejs/plugin-react";
|
||||
import vike from "vike/plugin";
|
||||
import { defineConfig } from "vite";
|
||||
import { cloudflare } from "@cloudflare/vite-plugin";
|
||||
import * as child_process from "node:child_process";
|
||||
|
||||
export default defineConfig(({ command }) => {
|
||||
@@ -23,76 +24,52 @@ export default defineConfig(({ command }) => {
|
||||
prerender: true,
|
||||
}),
|
||||
react(),
|
||||
|
||||
],
|
||||
server: {
|
||||
port: 3000,
|
||||
proxy: {
|
||||
// proxies requests to worker backend
|
||||
"/api": {
|
||||
target: "http://localhost:3001",
|
||||
},
|
||||
"/fonts": {
|
||||
target: "http://localhost:3001/fonts",
|
||||
},
|
||||
// "/api": {
|
||||
// target: "http://localhost:3001",
|
||||
// },
|
||||
// "/fonts": {
|
||||
// target: "http://localhost:3001/fonts",
|
||||
// },
|
||||
},
|
||||
},
|
||||
build: {
|
||||
emitAssets: true,
|
||||
|
||||
emitAssets: false,
|
||||
sourcemap: false,
|
||||
target: ["es2020", "edge88", "firefox78", "chrome87", "safari13"],
|
||||
minify: "terser",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
passes: 4,
|
||||
arrows: true,
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
sequences: true,
|
||||
},
|
||||
mangle: {},
|
||||
ecma: 2020,
|
||||
enclose: false,
|
||||
keep_classnames: false,
|
||||
keep_fnames: false,
|
||||
ie8: false,
|
||||
module: true,
|
||||
nameCache: null,
|
||||
safari10: false,
|
||||
toplevel: true,
|
||||
},
|
||||
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks(id: string) {
|
||||
if (id.includes("node_modules")) {
|
||||
if (
|
||||
id.includes("shiki/dist/wasm") ||
|
||||
id.endsWith("wasm-inlined.mjs")
|
||||
) {
|
||||
return "@wasm";
|
||||
if (id.includes('node_modules')) {
|
||||
// creating a chunk to react routes deps. Reducing the vendor chunk size
|
||||
if (id.includes('shiki/dist/wasm')) {
|
||||
return '@wasm-bundle';
|
||||
}
|
||||
|
||||
if (
|
||||
id.includes("katex") ||
|
||||
id.includes("marked") ||
|
||||
id.includes("shiki")
|
||||
) {
|
||||
return "@code";
|
||||
if (id.includes('katex') || id.includes('marked') || id.includes('shiki')) {
|
||||
return '@resources-bundle';
|
||||
}
|
||||
|
||||
if (id.includes("react-dom") || id.includes("vike")) {
|
||||
return "@logic";
|
||||
|
||||
if (id.includes('chakra') || id.includes('emotion-react')) {
|
||||
return '@gui-bundle';
|
||||
}
|
||||
|
||||
if (id.includes("mobx") || id.includes("framer-motion")) {
|
||||
return "@framework";
|
||||
|
||||
if (id.includes('react-dom') || id.includes('vike') || id.includes('mobx') || id.includes('framer-motion')) {
|
||||
return '@logic-bundle';
|
||||
}
|
||||
return 'vendor';
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
cssMinify: true,
|
||||
cssMinify: true
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@@ -17,6 +17,7 @@ export default class EmailWorker extends WorkerEntrypoint {
|
||||
addr: "contact@seemueller.io",
|
||||
});
|
||||
console.log("Recipient:", to);
|
||||
// msg.setRecipient(to);
|
||||
msg.setRecipient(to);
|
||||
msg.setSubject("New Contact Request: Website");
|
||||
msg.addMessage({
|
||||
|
@@ -53,7 +53,7 @@ const createServerContext = (env, ctx) => {
|
||||
chatService: ChatService.create({
|
||||
openAIApiKey: env.OPENAI_API_KEY,
|
||||
openAIBaseURL: env.VITE_OPENAI_API_ENDPOINT,
|
||||
activeStreams: {},
|
||||
activeStreams: undefined,
|
||||
maxTokens: 16384,
|
||||
systemPrompt:
|
||||
"You are an assistant designed to provide accurate, concise, and context-aware responses while demonstrating your advanced reasoning capabilities.",
|
||||
|
@@ -27,6 +27,8 @@ export class AssistantSdk {
|
||||
tools
|
||||
.map((tool) => {
|
||||
switch (tool) {
|
||||
// case "user-attachments": return "### Attachments\nUser supplied attachments are normalized to text and will have this header (# Attachment:...) in the message.";
|
||||
// case "web-search": return "### Web Search\nResults are optionally available in 'Live Search'.";
|
||||
default:
|
||||
return `- ${tool}`;
|
||||
}
|
||||
|
@@ -1,22 +1,18 @@
|
||||
import { flow, getSnapshot, types } from "mobx-state-tree";
|
||||
import OpenAI from "openai";
|
||||
import ChatSdk from "../sdk/chat-sdk";
|
||||
import {getSnapshot, types} from 'mobx-state-tree';
|
||||
import OpenAI from 'openai';
|
||||
import ChatSdk from '../sdk/chat-sdk';
|
||||
import Message from "../models/Message";
|
||||
import O1Message from "../models/O1Message";
|
||||
import {
|
||||
getModelFamily,
|
||||
ModelFamily,
|
||||
} from "../../../src/components/chat/SupportedModels";
|
||||
import { OpenAiChatSdk } from "../sdk/models/openai";
|
||||
import { GroqChatSdk } from "../sdk/models/groq";
|
||||
import { ClaudeChatSdk } from "../sdk/models/claude";
|
||||
import { FireworksAiChatSdk } from "../sdk/models/fireworks";
|
||||
import {getModelFamily} from "../../../src/components/chat/SupportedModels";
|
||||
import {OpenAiChatSdk} from "../sdk/models/openai";
|
||||
import {GroqChatSdk} from "../sdk/models/groq";
|
||||
import {ClaudeChatSdk} from "../sdk/models/claude";
|
||||
import {FireworksAiChatSdk} from "../sdk/models/fireworks";
|
||||
import handleStreamData from "../sdk/handleStreamData";
|
||||
import { GoogleChatSdk } from "../sdk/models/google";
|
||||
import { XaiChatSdk } from "../sdk/models/xai";
|
||||
import { CerebrasSdk } from "../sdk/models/cerebras";
|
||||
import { CloudflareAISdk } from "../sdk/models/cloudflareAi";
|
||||
import {GoogleChatSdk} from "../sdk/models/google";
|
||||
import {XaiChatSdk} from "../sdk/models/xai";
|
||||
|
||||
// Types
|
||||
export interface StreamParams {
|
||||
env: Env;
|
||||
openai: OpenAI;
|
||||
@@ -33,486 +29,264 @@ export interface StreamParams {
|
||||
interface StreamHandlerParams {
|
||||
controller: ReadableStreamDefaultController;
|
||||
encoder: TextEncoder;
|
||||
webhook?: { url: string; payload: unknown };
|
||||
webhook?: { url: string, payload: unknown };
|
||||
dynamicContext?: any;
|
||||
}
|
||||
|
||||
const ChatService = types
|
||||
.model("ChatService", {
|
||||
openAIApiKey: types.optional(types.string, ""),
|
||||
openAIBaseURL: types.optional(types.string, ""),
|
||||
activeStreams: types.optional(
|
||||
types.map(
|
||||
types.model({
|
||||
name: types.optional(types.string, ""),
|
||||
maxTokens: types.optional(types.number, 0),
|
||||
systemPrompt: types.optional(types.string, ""),
|
||||
model: types.optional(types.string, ""),
|
||||
messages: types.optional(types.array(types.frozen()), []),
|
||||
attachments: types.optional(types.array(types.frozen()), []),
|
||||
tools: types.optional(types.array(types.frozen()), []),
|
||||
disableWebhookGeneration: types.optional(types.boolean, false),
|
||||
}),
|
||||
),
|
||||
),
|
||||
maxTokens: types.number,
|
||||
systemPrompt: types.string,
|
||||
})
|
||||
.volatile((self) => ({
|
||||
openai: {} as OpenAI,
|
||||
env: {} as Env,
|
||||
webhookStreamActive: false,
|
||||
}))
|
||||
.actions((self) => {
|
||||
const createMessageInstance = (message: any) => {
|
||||
if (typeof message.content === "string") {
|
||||
return Message.create({
|
||||
role: message.role,
|
||||
content: message.content,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(message.content)) {
|
||||
const m = O1Message.create({
|
||||
role: message.role,
|
||||
content: message.content.map((item) => ({
|
||||
type: item.type,
|
||||
text: item.text,
|
||||
})),
|
||||
});
|
||||
return m;
|
||||
}
|
||||
throw new Error("Unsupported message format");
|
||||
};
|
||||
|
||||
const handleWebhookProcessing = async ({
|
||||
controller,
|
||||
encoder,
|
||||
webhook,
|
||||
dynamicContext,
|
||||
}: StreamHandlerParams) => {
|
||||
console.log("handleWebhookProcessing::start");
|
||||
if (!webhook) return;
|
||||
console.log("handleWebhookProcessing::[Loading Live Search]");
|
||||
dynamicContext.append("\n## Live Search\n~~~markdown\n");
|
||||
|
||||
for await (const chunk of self.streamWebhookData({ webhook })) {
|
||||
controller.enqueue(encoder.encode(chunk));
|
||||
dynamicContext.append(chunk);
|
||||
}
|
||||
|
||||
dynamicContext.append("\n~~~\n");
|
||||
console.log(
|
||||
`handleWebhookProcessing::[Finished loading Live Search!][length: ${dynamicContext.content.length}]`,
|
||||
);
|
||||
ChatSdk.sendDoubleNewline(controller, encoder);
|
||||
console.log("handleWebhookProcessing::exit");
|
||||
};
|
||||
|
||||
const createStreamParams = async (
|
||||
streamConfig: any,
|
||||
dynamicContext: any,
|
||||
durableObject: any,
|
||||
): Promise<StreamParams> => {
|
||||
return {
|
||||
env: self.env,
|
||||
openai: self.openai,
|
||||
messages: streamConfig.messages.map(createMessageInstance),
|
||||
model: streamConfig.model,
|
||||
systemPrompt: streamConfig.systemPrompt,
|
||||
preprocessedContext: getSnapshot(dynamicContext),
|
||||
attachments: streamConfig.attachments ?? [],
|
||||
tools: streamConfig.tools ?? [],
|
||||
disableWebhookGeneration: true,
|
||||
maxTokens: await durableObject.dynamicMaxTokens(
|
||||
streamConfig.messages,
|
||||
2000,
|
||||
),
|
||||
.model('ChatService', {
|
||||
openAIApiKey: types.optional(types.string, ""),
|
||||
openAIBaseURL: types.optional(types.string, ""),
|
||||
maxTokens: types.number,
|
||||
systemPrompt: types.string
|
||||
})
|
||||
.volatile(self => ({
|
||||
openai: {} as OpenAI,
|
||||
env: {} as Env,
|
||||
webhookStreamActive: false
|
||||
}))
|
||||
.actions(self => {
|
||||
// Helper functions
|
||||
const createMessageInstance = (message: any) => {
|
||||
if (typeof message.content === 'string') {
|
||||
return Message.create({
|
||||
role: message.role,
|
||||
content: message.content,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(message.content)) {
|
||||
const m = O1Message.create({
|
||||
role: message.role,
|
||||
content: message.content.map(item => ({
|
||||
type: item.type,
|
||||
text: item.text
|
||||
})),
|
||||
});
|
||||
console.log({here: "createMessageInstance"});
|
||||
return m;
|
||||
}
|
||||
throw new Error('Unsupported message format');
|
||||
};
|
||||
};
|
||||
|
||||
const modelHandlers = {
|
||||
openai: (params: StreamParams, dataHandler: Function) =>
|
||||
OpenAiChatSdk.handleOpenAiStream(params, dataHandler),
|
||||
groq: (params: StreamParams, dataHandler: Function) =>
|
||||
GroqChatSdk.handleGroqStream(params, dataHandler),
|
||||
claude: (params: StreamParams, dataHandler: Function) =>
|
||||
ClaudeChatSdk.handleClaudeStream(params, dataHandler),
|
||||
fireworks: (params: StreamParams, dataHandler: Function) =>
|
||||
FireworksAiChatSdk.handleFireworksStream(params, dataHandler),
|
||||
google: (params: StreamParams, dataHandler: Function) =>
|
||||
GoogleChatSdk.handleGoogleStream(params, dataHandler),
|
||||
xai: (params: StreamParams, dataHandler: Function) =>
|
||||
XaiChatSdk.handleXaiStream(params, dataHandler),
|
||||
cerebras: (params: StreamParams, dataHandler: Function) =>
|
||||
CerebrasSdk.handleCerebrasStream(params, dataHandler),
|
||||
cloudflareAI: (params: StreamParams, dataHandler: Function) =>
|
||||
CloudflareAISdk.handleCloudflareAIStream(params, dataHandler),
|
||||
};
|
||||
|
||||
return {
|
||||
setActiveStream(streamId: string, stream: any) {
|
||||
const validStream = {
|
||||
name: stream?.name || "Unnamed Stream",
|
||||
maxTokens: stream?.maxTokens || 0,
|
||||
systemPrompt: stream?.systemPrompt || "",
|
||||
model: stream?.model || "",
|
||||
messages: stream?.messages || [],
|
||||
attachments: stream?.attachments || [],
|
||||
tools: stream?.tools || [],
|
||||
disableWebhookGeneration: stream?.disableWebhookGeneration || false,
|
||||
};
|
||||
const handleWebhookProcessing = async (
|
||||
{controller, encoder, webhook, dynamicContext}: StreamHandlerParams
|
||||
) => {
|
||||
console.log("handleWebhookProcessing::start");
|
||||
if (!webhook) return;
|
||||
console.log("handleWebhookProcessing::[Loading Hot Data]");
|
||||
dynamicContext.append("\n## Hot Data\n~~~markdown\n");
|
||||
|
||||
self.activeStreams.set(streamId, validStream);
|
||||
},
|
||||
|
||||
removeActiveStream(streamId: string) {
|
||||
self.activeStreams.delete(streamId);
|
||||
},
|
||||
setEnv(env: Env) {
|
||||
self.env = env;
|
||||
self.openai = new OpenAI({
|
||||
apiKey: self.openAIApiKey,
|
||||
baseURL: self.openAIBaseURL,
|
||||
});
|
||||
},
|
||||
|
||||
handleChatRequest: async (request: Request) => {
|
||||
return ChatSdk.handleChatRequest(request, {
|
||||
openai: self.openai,
|
||||
env: self.env,
|
||||
systemPrompt: self.systemPrompt,
|
||||
maxTokens: self.maxTokens,
|
||||
});
|
||||
},
|
||||
|
||||
setWebhookStreamActive(value) {
|
||||
self.webhookStreamActive = value;
|
||||
},
|
||||
|
||||
streamWebhookData: async function* ({ webhook }) {
|
||||
console.log("streamWebhookData::start");
|
||||
if (self.webhookStreamActive) {
|
||||
return;
|
||||
for await (const chunk of self.streamWebhookData({webhook})) {
|
||||
controller.enqueue(encoder.encode(chunk));
|
||||
dynamicContext.append(chunk);
|
||||
}
|
||||
|
||||
const queue: string[] = [];
|
||||
let resolveQueueItem: Function;
|
||||
let finished = false;
|
||||
let errorOccurred: Error | null = null;
|
||||
dynamicContext.append("\n~~~\n");
|
||||
console.log(`handleWebhookProcessing::[Finished loading Hot Data!][length: ${dynamicContext.content.length}]`);
|
||||
ChatSdk.sendDoubleNewline(controller, encoder);
|
||||
console.log("handleWebhookProcessing::exit")
|
||||
};
|
||||
|
||||
const dataPromise = () =>
|
||||
new Promise<void>((resolve) => {
|
||||
const createStreamParams = async (
|
||||
streamConfig: any,
|
||||
dynamicContext: any,
|
||||
durableObject: any
|
||||
): Promise<StreamParams> => {
|
||||
return {
|
||||
env: self.env,
|
||||
openai: self.openai,
|
||||
messages: streamConfig.messages.map(createMessageInstance),
|
||||
model: streamConfig.model,
|
||||
systemPrompt: streamConfig.systemPrompt,
|
||||
preprocessedContext: getSnapshot(dynamicContext),
|
||||
attachments: streamConfig.attachments ?? [],
|
||||
tools: streamConfig.tools ?? [],
|
||||
disableWebhookGeneration: true,
|
||||
maxTokens: await durableObject.dynamicMaxTokens(
|
||||
streamConfig.messages,
|
||||
128000
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
const modelHandlers = {
|
||||
openai: (params: StreamParams, dataHandler: Function) =>
|
||||
OpenAiChatSdk.handleOpenAiStream(params, dataHandler),
|
||||
groq: (params: StreamParams, dataHandler: Function) =>
|
||||
GroqChatSdk.handleGroqStream(params, dataHandler),
|
||||
claude: (params: StreamParams, dataHandler: Function) =>
|
||||
ClaudeChatSdk.handleClaudeStream(params, dataHandler),
|
||||
fireworks: (params: StreamParams, dataHandler: Function) =>
|
||||
FireworksAiChatSdk.handleFireworksStream(params, dataHandler),
|
||||
google: (params: StreamParams, dataHandler: Function) =>
|
||||
GoogleChatSdk.handleGoogleStream(params, dataHandler),
|
||||
xai: (params: StreamParams, dataHandler: Function) =>
|
||||
XaiChatSdk.handleXaiStream(params, dataHandler),
|
||||
};
|
||||
|
||||
return {
|
||||
setEnv(env: Env) {
|
||||
self.env = env;
|
||||
self.openai = new OpenAI({
|
||||
apiKey: self.openAIApiKey,
|
||||
baseURL: self.openAIBaseURL,
|
||||
});
|
||||
},
|
||||
|
||||
handleChatRequest: async (request: Request) => {
|
||||
return ChatSdk.handleChatRequest(request, {
|
||||
openai: self.openai,
|
||||
env: self.env,
|
||||
systemPrompt: self.systemPrompt,
|
||||
maxTokens: self.maxTokens
|
||||
});
|
||||
},
|
||||
|
||||
setWebhookStreamActive(value) {
|
||||
self.webhookStreamActive = value;
|
||||
},
|
||||
|
||||
streamWebhookData: async function* ({webhook}) {
|
||||
console.log("streamWebhookData::start");
|
||||
if (self.webhookStreamActive) {
|
||||
return
|
||||
}
|
||||
|
||||
const queue: string[] = [];
|
||||
let resolveQueueItem: Function;
|
||||
let finished = false;
|
||||
let errorOccurred: Error | null = null;
|
||||
|
||||
const dataPromise = () => new Promise<void>((resolve) => {
|
||||
resolveQueueItem = resolve;
|
||||
});
|
||||
|
||||
let currentPromise = dataPromise();
|
||||
const eventSource = new EventSource(webhook.url.trim());
|
||||
console.log("streamWebhookData::setWebhookStreamActive::true");
|
||||
self.setWebhookStreamActive(true);
|
||||
try {
|
||||
ChatSdk.handleWebhookStream(eventSource, (data) => {
|
||||
const formattedData = `data: ${JSON.stringify(data)}\n\n`;
|
||||
queue.push(formattedData);
|
||||
if (resolveQueueItem) resolveQueueItem();
|
||||
currentPromise = dataPromise();
|
||||
})
|
||||
.then(() => {
|
||||
let currentPromise = dataPromise();
|
||||
const eventSource = new EventSource(webhook.url.trim());
|
||||
console.log("streamWebhookData::setWebhookStreamActive::true");
|
||||
self.setWebhookStreamActive(true)
|
||||
try {
|
||||
ChatSdk.handleWebhookStream(eventSource, (data) => {
|
||||
const formattedData = `data: ${JSON.stringify(data)}\n\n`;
|
||||
queue.push(formattedData);
|
||||
if (resolveQueueItem) resolveQueueItem();
|
||||
currentPromise = dataPromise();
|
||||
}).then(() => {
|
||||
finished = true;
|
||||
if (resolveQueueItem) resolveQueueItem();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(
|
||||
`chatService::streamWebhookData::STREAM_ERROR::${err}`,
|
||||
);
|
||||
}).catch((err) => {
|
||||
console.log(`chatService::streamWebhookData::STREAM_ERROR::${err}`);
|
||||
errorOccurred = err;
|
||||
if (resolveQueueItem) resolveQueueItem();
|
||||
});
|
||||
|
||||
while (!finished || queue.length > 0) {
|
||||
if (queue.length > 0) {
|
||||
yield queue.shift()!;
|
||||
} else if (errorOccurred) {
|
||||
throw errorOccurred;
|
||||
} else {
|
||||
await currentPromise;
|
||||
}
|
||||
}
|
||||
self.setWebhookStreamActive(false);
|
||||
eventSource.close();
|
||||
console.log(`chatService::streamWebhookData::complete`);
|
||||
} catch (error) {
|
||||
console.log(`chatService::streamWebhookData::error`);
|
||||
eventSource.close();
|
||||
self.setWebhookStreamActive(false);
|
||||
console.error("Error while streaming webhook data:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* runModelHandler
|
||||
* Selects the correct model handler and invokes it.
|
||||
*/
|
||||
async runModelHandler(params: {
|
||||
streamConfig: any;
|
||||
streamParams: any;
|
||||
controller: ReadableStreamDefaultController;
|
||||
encoder: TextEncoder;
|
||||
streamId: string;
|
||||
}) {
|
||||
const { streamConfig, streamParams, controller, encoder, streamId } =
|
||||
params;
|
||||
|
||||
const modelFamily = getModelFamily(streamConfig.model);
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::modelFamily::${modelFamily}`,
|
||||
);
|
||||
|
||||
const handler = modelHandlers[modelFamily as ModelFamily];
|
||||
if (handler) {
|
||||
try {
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::${streamId}::handler::start`,
|
||||
);
|
||||
await handler(streamParams, handleStreamData(controller, encoder));
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::${streamId}::handler::finish`,
|
||||
);
|
||||
} catch (error) {
|
||||
const message = error.message.toLowerCase();
|
||||
|
||||
if (
|
||||
message.includes("413 ") ||
|
||||
message.includes("maximum") ||
|
||||
message.includes("too long") ||
|
||||
message.includes("too large")
|
||||
) {
|
||||
throw new ClientError(
|
||||
`Error! Content length exceeds limits. Try shortening your message, removing any attached files, or editing an earlier message instead.`,
|
||||
413,
|
||||
{
|
||||
model: streamConfig.model,
|
||||
maxTokens: streamParams.maxTokens,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (message.includes("429 ")) {
|
||||
throw new ClientError(
|
||||
`Error! Rate limit exceeded. Wait a few minutes before trying again.`,
|
||||
429,
|
||||
{
|
||||
model: streamConfig.model,
|
||||
maxTokens: streamParams.maxTokens,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (message.includes("404")) {
|
||||
throw new ClientError(
|
||||
`Something went wrong, try again.`,
|
||||
413,
|
||||
{},
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
/*
|
||||
'413 Request too large for model `mixtral-8x7b-32768` in organization `org_01htjxws48fm0rbbg5gnkgmbrh` service tier `on_demand` on tokens per minute (TPM): Limit 5000, Requested 49590, please reduce your message size and try again. Visit https://console.groq.com/docs/rate-limits for more information.'
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* handleWebhookIfNeeded
|
||||
* Checks if a webhook exists, and if so, processes it.
|
||||
*/
|
||||
async handleWebhookIfNeeded(params: {
|
||||
savedStreamConfig: string;
|
||||
controller: ReadableStreamDefaultController;
|
||||
encoder: TextEncoder;
|
||||
}) {
|
||||
const { savedStreamConfig, controller, encoder, dynamicContext } =
|
||||
params;
|
||||
|
||||
const config = JSON.parse(savedStreamConfig);
|
||||
const webhook = config?.webhooks?.[0];
|
||||
|
||||
if (webhook) {
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::webhook:start`,
|
||||
);
|
||||
await handleWebhookProcessing({
|
||||
controller,
|
||||
encoder,
|
||||
webhook,
|
||||
dynamicContext,
|
||||
});
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::webhook::end`,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
createSseReadableStream(params: {
|
||||
streamId: string;
|
||||
streamConfig: any;
|
||||
savedStreamConfig: string;
|
||||
durableObject: any;
|
||||
}) {
|
||||
const { streamId, streamConfig, savedStreamConfig, durableObject } =
|
||||
params;
|
||||
|
||||
return new ReadableStream({
|
||||
async start(controller) {
|
||||
console.log(
|
||||
`chatService::handleSseStream::ReadableStream::${streamId}::open`,
|
||||
);
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
try {
|
||||
const dynamicContext = Message.create(
|
||||
streamConfig.preprocessedContext,
|
||||
);
|
||||
|
||||
await self.handleWebhookIfNeeded({
|
||||
savedStreamConfig,
|
||||
controller,
|
||||
encoder,
|
||||
dynamicContext: dynamicContext,
|
||||
});
|
||||
|
||||
const streamParams = await createStreamParams(
|
||||
streamConfig,
|
||||
dynamicContext,
|
||||
durableObject,
|
||||
);
|
||||
|
||||
try {
|
||||
await self.runModelHandler({
|
||||
streamConfig,
|
||||
streamParams,
|
||||
controller,
|
||||
encoder,
|
||||
streamId,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("error caught at runModelHandler");
|
||||
throw e;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`chatService::handleSseStream::${streamId}::Error`,
|
||||
error,
|
||||
);
|
||||
|
||||
if (error instanceof ClientError) {
|
||||
controller.enqueue(
|
||||
encoder.encode(
|
||||
`data: ${JSON.stringify({ type: "error", error: error.message })}\n\n`,
|
||||
),
|
||||
);
|
||||
while (!finished || queue.length > 0) {
|
||||
if (queue.length > 0) {
|
||||
yield queue.shift()!;
|
||||
} else if (errorOccurred) {
|
||||
throw errorOccurred;
|
||||
} else {
|
||||
controller.enqueue(
|
||||
encoder.encode(
|
||||
`data: ${JSON.stringify({ type: "error", error: "Server error" })}\n\n`,
|
||||
),
|
||||
);
|
||||
await currentPromise;
|
||||
}
|
||||
controller.close();
|
||||
} finally {
|
||||
try {
|
||||
controller.close();
|
||||
} catch (_) {}
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
self.setWebhookStreamActive(false);
|
||||
eventSource.close();
|
||||
console.log(`chatService::streamWebhookData::complete`);
|
||||
} catch (error) {
|
||||
console.log(`chatService::streamWebhookData::error`);
|
||||
eventSource.close();
|
||||
self.setWebhookStreamActive(false);
|
||||
console.error("Error while streaming webhook data:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
handleSseStream: flow(function* (
|
||||
streamId: string,
|
||||
): Generator<Promise<string>, Response, unknown> {
|
||||
console.log(`chatService::handleSseStream::enter::${streamId}`);
|
||||
async handleSseStream(streamId: string) {
|
||||
console.log(`chatService::handleSseStream::enter::${streamId}`);
|
||||
|
||||
if (self.activeStreams.has(streamId)) {
|
||||
console.log(
|
||||
`chatService::handleSseStream::${streamId}::[stream already active]`,
|
||||
);
|
||||
return new Response("Stream already active", { status: 409 });
|
||||
}
|
||||
const objectId = self.env.SITE_COORDINATOR.idFromName('stream-index');
|
||||
const durableObject = self.env.SITE_COORDINATOR.get(objectId);
|
||||
const savedStreamConfig = await durableObject.getStreamData(streamId);
|
||||
// console.log({savedStreamConfig});
|
||||
|
||||
const objectId = self.env.SITE_COORDINATOR.idFromName("stream-index");
|
||||
const durableObject = self.env.SITE_COORDINATOR.get(objectId);
|
||||
const savedStreamConfig = yield durableObject.getStreamData(streamId);
|
||||
if (!savedStreamConfig) {
|
||||
return new Response('Stream not found', {status: 404});
|
||||
}
|
||||
|
||||
if (!savedStreamConfig) {
|
||||
return new Response("Stream not found", { status: 404 });
|
||||
}
|
||||
const streamConfig = JSON.parse(savedStreamConfig);
|
||||
console.log(`chatService::handleSseStream::${streamId}::[stream configured]`);
|
||||
|
||||
const streamConfig = JSON.parse(savedStreamConfig);
|
||||
console.log(
|
||||
`chatService::handleSseStream::${streamId}::[stream configured]`,
|
||||
);
|
||||
console.log(`chatService::handleSseStream::${streamId}::[initializing stream]`);
|
||||
|
||||
const stream = self.createSseReadableStream({
|
||||
streamId,
|
||||
streamConfig,
|
||||
savedStreamConfig,
|
||||
durableObject,
|
||||
});
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::open`);
|
||||
const encoder = new TextEncoder();
|
||||
// controller.enqueue(encoder.encode('retry: 3\n\n'));
|
||||
|
||||
const [processingStream, responseStream] = stream.tee();
|
||||
console.log(streamConfig.preprocessedContext);
|
||||
|
||||
self.setActiveStream(streamId, {});
|
||||
const dynamicContext = Message.create(streamConfig.preprocessedContext);
|
||||
console.log(`chatService::handleSseStream::ReadableStream::dynamicContext`);
|
||||
try {
|
||||
|
||||
processingStream.pipeTo(
|
||||
new WritableStream({
|
||||
close() {
|
||||
console.log(
|
||||
`chatService::handleSseStream::${streamId}::[stream closed]`,
|
||||
);
|
||||
const config = JSON.parse(savedStreamConfig);
|
||||
|
||||
const webhook = config?.webhooks?.at(0);
|
||||
|
||||
if (webhook) {
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::webhook:start`);
|
||||
await handleWebhookProcessing({
|
||||
controller,
|
||||
encoder,
|
||||
webhook,
|
||||
dynamicContext
|
||||
});
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::webhook::end`);
|
||||
}
|
||||
|
||||
const streamParams = await createStreamParams(
|
||||
streamConfig,
|
||||
dynamicContext,
|
||||
durableObject
|
||||
);
|
||||
|
||||
const modelFamily = getModelFamily(streamConfig.model);
|
||||
console.log(`chatService::handleSseStream::ReadableStream::modelFamily::${modelFamily}`);
|
||||
const handler = modelHandlers[modelFamily];
|
||||
|
||||
if (handler) {
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::handler::start`);
|
||||
await handler(
|
||||
streamParams,
|
||||
handleStreamData(controller, encoder)
|
||||
);
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::handler::finish`);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.enqueue(
|
||||
encoder.encode(`data: ${JSON.stringify({error: error.message})}\n\n`)
|
||||
);
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::Error::${error}`);
|
||||
} finally {
|
||||
console.log(`chatService::handleSseStream::ReadableStream::${streamId}::closed::${streamId}`);
|
||||
controller.close();
|
||||
}
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return new Response(responseStream, {
|
||||
headers: {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
Connection: "keep-alive",
|
||||
},
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* ClientError
|
||||
* A custom construct for sending client-friendly errors via the controller in a structured and controlled manner.
|
||||
*/
|
||||
export class ClientError extends Error {
|
||||
public statusCode: number;
|
||||
public details: Record<string, any>;
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
statusCode: number,
|
||||
details: Record<string, any> = {},
|
||||
) {
|
||||
super(message);
|
||||
this.name = "ClientError";
|
||||
this.statusCode = statusCode;
|
||||
this.details = details;
|
||||
Object.setPrototypeOf(this, ClientError.prototype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the error for SSE-compatible data transmission.
|
||||
*/
|
||||
public formatForSSE(): string {
|
||||
return JSON.stringify({
|
||||
type: "error",
|
||||
message: this.message,
|
||||
details: this.details,
|
||||
statusCode: this.statusCode,
|
||||
});
|
||||
return new Response(
|
||||
stream,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ChatService;
|
||||
export default ChatService;
|
@@ -6,7 +6,7 @@ dev.port = 3001
|
||||
dev.ip = "localhost"
|
||||
observability.enabled = true
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
assets = { directory = "./dist/client", binding = "ASSETS" }
|
||||
assets = { directory = "./dist/client", binding = "ASSETS" }
|
||||
preview_urls = false
|
||||
# wrangler.toml (wrangler v3.78.6^)
|
||||
|
||||
|
Reference in New Issue
Block a user