diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 236d264..0f9a93d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -28,7 +28,7 @@ jobs: cache-dependency-path: package-lock.json - name: Install dependencies run: | - npm install + npm install --legacy-peer-deps npx playwright install --with-deps - name: Run tests run: | @@ -51,5 +51,5 @@ jobs: cache: npm cache-dependency-path: package-lock.json - run: | - npm install + npm install --legacy-peer-deps npm run lint diff --git a/Dockerfile b/Dockerfile index 0f5eb3e..c96348b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM node:22-alpine as builder WORKDIR /app COPY . . -RUN npm ci && npm run build +RUN npm ci --legacy-peer-deps && npm run build FROM node:22-alpine diff --git a/package-lock.json b/package-lock.json index 9e329ff..75d9238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "highlight.js": "^11.10.0", "openai": "^4.52.4", "pdfjs-dist": "^4.4.168", + "sortablejs": "^1.15.3", "svelte-markdown": "^0.4.1", "winston": "^3.13.0" }, @@ -26,7 +27,7 @@ "@skeletonlabs/skeleton": "2.9.0", "@skeletonlabs/tw-plugin": "0.3.1", "@sveltejs/kit": "^2.5.18", - "@sveltejs/vite-plugin-svelte": "^3.1.1", + "@sveltejs/vite-plugin-svelte": "^4.0.0-next.7", "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "0.5.12", "@types/eslint": "8.56.7", @@ -35,6 +36,7 @@ "@types/jsonwebtoken": "^9.0.6", "@types/node": "20.12.2", "@types/showdown": "^2.0.6", + "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", "autoprefixer": "10.4.19", @@ -45,12 +47,12 @@ "postcss": "8.4.38", "prettier": "^3.3.2", "prettier-plugin-svelte": "^3.2.5", - "svelte": "^4.2.19", + "svelte": "^5.0.0-next.259", "svelte-check": "^3.8.4", "tailwindcss": "3.4.3", "tslib": "^2.6.3", "typescript": "^5.5.3", - "vite": "^5.3.3", + "vite": "^5.4.8", "vite-plugin-tailwind-purgecss": "^0.2.1", "vitest": "^1.6.0" }, @@ -2524,39 +2526,38 @@ } }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", - "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "version": "4.0.0-next.7", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0-next.7.tgz", + "integrity": "sha512-yMUnAqquoayvBDztk1rWUgdtvjv7YcHgopCAB7sWl9SQht8U/7lqwTlJU0ZTAY09pFFRe6bbakd7YoiyyIvJiA==", "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", - "debug": "^4.3.4", + "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0", + "debug": "^4.3.6", "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.30.10", - "svelte-hmr": "^0.16.0", - "vitefu": "^0.2.5" + "magic-string": "^0.30.11", + "vitefu": "^1.0.2" }, "engines": { - "node": "^18.0.0 || >=20" + "node": "^18.0.0 || ^20.0.0 || >=22" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", + "svelte": "^5.0.0-next.96 || ^5.0.0", "vite": "^5.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", - "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "version": "3.0.0-next.3", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.0-next.3.tgz", + "integrity": "sha512-kuGJ2CZ5lAw3gKF8Kw0AfKtUJWbwdlDHY14K413B0MCyrzvQvsKTorwmwZcky0+QqY6RnVIZ/5FttB9bQmkLXg==", "dependencies": { - "debug": "^4.3.4" + "debug": "^4.3.5" }, "engines": { - "node": "^18.0.0 || >=20" + "node": "^18.0.0 || ^20.0.0 || >=22" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", + "@sveltejs/vite-plugin-svelte": "^4.0.0-next.0||^4.0.0", + "svelte": "^5.0.0-next.96 || ^5.0.0", "vite": "^5.0.0" } }, @@ -2681,6 +2682,12 @@ "integrity": "sha512-pTvD/0CIeqe4x23+YJWlX2gArHa8G0J0Oh6GKaVXV7TAeickpkkZiNOgFcFcmLQ5lB/K0qBJL1FtRYltBfbGCQ==", "dev": true }, + "node_modules/@types/sortablejs": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.8.tgz", + "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==", + "dev": true + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", @@ -3019,6 +3026,14 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-typescript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", + "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", + "peerDependencies": { + "acorn": ">=8.9.0" + } + }, "node_modules/acorn-walk": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", @@ -3143,11 +3158,11 @@ "dev": true }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dependencies": { - "dequal": "^2.0.3" + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "engines": { + "node": ">= 0.4" } }, "node_modules/array-union": { @@ -3488,26 +3503,6 @@ "node": ">=10" } }, - "node_modules/code-red": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1", - "acorn": "^8.10.0", - "estree-walker": "^3.0.3", - "periscopic": "^3.1.0" - } - }, - "node_modules/code-red/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -3637,18 +3632,6 @@ "node": ">= 8" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3776,14 +3759,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "optional": true }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", @@ -4181,6 +4156,15 @@ "node": ">=0.10" } }, + "node_modules/esrap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz", + "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -5322,11 +5306,6 @@ "node": ">= 16" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5961,32 +5940,6 @@ "path2d": "^0.2.1" } }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, - "node_modules/periscopic/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/periscopic/node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", @@ -6900,6 +6853,11 @@ "sorcery": "bin/sorcery" } }, + "node_modules/sortablejs": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.3.tgz", + "integrity": "sha512-zdK3/kwwAK1cJgy1rwl1YtNTbRmc8qW/+vgXf75A7NHag5of4pyI6uK86ktmQETyWRH7IGaE73uZOOBcGxgqZg==" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7118,27 +7076,26 @@ } }, "node_modules/svelte": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", - "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@jridgewell/sourcemap-codec": "^1.4.15", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/estree": "^1.0.1", - "acorn": "^8.9.0", - "aria-query": "^5.3.0", - "axobject-query": "^4.0.0", - "code-red": "^1.0.3", - "css-tree": "^2.3.1", - "estree-walker": "^3.0.3", - "is-reference": "^3.0.1", + "version": "5.0.0-next.259", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.259.tgz", + "integrity": "sha512-trRFSjKD+11KbXerGmBT0Uc+ZSNUhxn0aQ02q9tjtig/FV24dpZlXmCrcZTZliOLS0P8JWjw6xaWgNheZZoYOg==", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "acorn-typescript": "^1.4.13", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "esm-env": "^1.0.0", + "esrap": "^1.2.2", + "is-reference": "^3.0.2", "locate-character": "^3.0.0", - "magic-string": "^0.30.4", - "periscopic": "^3.1.0" + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/svelte-check": { @@ -7216,17 +7173,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/svelte-hmr": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", - "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", - "engines": { - "node": "^12.20 || ^14.13.1 || >= 16" - }, - "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0" - } - }, "node_modules/svelte-markdown": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/svelte-markdown/-/svelte-markdown-0.4.1.tgz", @@ -7301,14 +7247,6 @@ } } }, - "node_modules/svelte/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/svelte/node_modules/is-reference": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", @@ -7755,9 +7693,9 @@ } }, "node_modules/vite": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.4.tgz", - "integrity": "sha512-RHFCkULitycHVTtelJ6jQLd+KSAAzOgEYorV32R2q++M6COBjKJR6BxqClwp5sf0XaBDjVMuJ9wnNfyAJwjMkA==", + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -7897,9 +7835,13 @@ } }, "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.2.tgz", + "integrity": "sha512-0/iAvbXyM3RiPPJ4lyD4w6Mjgtf4ejTK6TPvTNG3H32PLwuT0N/ZjJLiXug7ETE/LWtTeHw9WRv7uX/tIKYyKg==", + "workspaces": [ + "tests/deps/*", + "tests/projects/*" + ], "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, @@ -8299,6 +8241,11 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==" } } } diff --git a/package.json b/package.json index 686da5b..cda1758 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@skeletonlabs/skeleton": "2.9.0", "@skeletonlabs/tw-plugin": "0.3.1", "@sveltejs/kit": "^2.5.18", - "@sveltejs/vite-plugin-svelte": "^3.1.1", + "@sveltejs/vite-plugin-svelte": "^4.0.0-next.7", "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "0.5.12", "@types/eslint": "8.56.7", @@ -30,6 +30,7 @@ "@types/jsonwebtoken": "^9.0.6", "@types/node": "20.12.2", "@types/showdown": "^2.0.6", + "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", "autoprefixer": "10.4.19", @@ -40,12 +41,12 @@ "postcss": "8.4.38", "prettier": "^3.3.2", "prettier-plugin-svelte": "^3.2.5", - "svelte": "^4.2.19", + "svelte": "^5.0.0-next.259", "svelte-check": "^3.8.4", "tailwindcss": "3.4.3", "tslib": "^2.6.3", "typescript": "^5.5.3", - "vite": "^5.3.3", + "vite": "^5.4.8", "vite-plugin-tailwind-purgecss": "^0.2.1", "vitest": "^1.6.0" }, @@ -60,6 +61,7 @@ "highlight.js": "^11.10.0", "openai": "^4.52.4", "pdfjs-dist": "^4.4.168", + "sortablejs": "^1.15.3", "svelte-markdown": "^0.4.1", "winston": "^3.13.0" }, diff --git a/src/hooks.server.test.ts b/src/hooks.server.test.ts index 22c8ec3..99fe1a3 100644 --- a/src/hooks.server.test.ts +++ b/src/hooks.server.test.ts @@ -1,16 +1,6 @@ import { handle } from '../src/hooks.server'; import { describe, it, expect, vi } from 'vitest'; -function createEvent() { - return { - request: { - headers: new Map(), - method: 'GET', - url: 'https://example.com' - } - }; -} - function createResolve() { return vi.fn().mockResolvedValue({ status: 200, diff --git a/src/lib/chat.ts b/src/lib/chat.svelte.ts similarity index 97% rename from src/lib/chat.ts rename to src/lib/chat.svelte.ts index 1c57210..e97ed8f 100644 --- a/src/lib/chat.ts +++ b/src/lib/chat.svelte.ts @@ -11,8 +11,8 @@ export type chatOptions = { export class Chat { readonly id: string; - public title: string; - public messages: Message[]; + public title: string = $state(''); + public messages: Message[] = $state([]); private _last_modified: Date; get last_modified() { diff --git a/src/lib/components/FileDropZone.svelte b/src/lib/components/FileDropZone.svelte new file mode 100644 index 0000000..8102c81 --- /dev/null +++ b/src/lib/components/FileDropZone.svelte @@ -0,0 +1,16 @@ + + + +{#each fileArray as file} + +{/each} diff --git a/src/lib/components/LoadingBar.svelte b/src/lib/components/LoadingBar.svelte index 1933516..0a69dd5 100644 --- a/src/lib/components/LoadingBar.svelte +++ b/src/lib/components/LoadingBar.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/Navbar.svelte b/src/lib/components/Navbar.svelte index 1cbeeb5..31600b9 100644 --- a/src/lib/components/Navbar.svelte +++ b/src/lib/components/Navbar.svelte @@ -13,7 +13,7 @@
- -
diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte index cd6fd6b..6cfed61 100644 --- a/src/lib/components/Navigation.svelte +++ b/src/lib/components/Navigation.svelte @@ -5,6 +5,7 @@ const drawerStore = getDrawerStore(); const pages = [ { name: 'Chatbot', href: '/gpt' }, + { name: 'Document Generation', href: '/document-generation' }, { name: 'Document Intelligence', href: '/document-intelligence' }, { name: 'Diarize (Submit)', href: '/diarize-submit' }, { name: 'Diarize (Retrieve)', href: '/diarize-retrieve' }, @@ -18,15 +19,16 @@ drawerStore.close(); } - $: classesActive = (href: string) => - href === $page.url.pathname ? 'bg-primary-100 dark:bg-primary-700' : ''; + let classesActive = $derived((href: string) => + href === $page.url.pathname ? 'bg-primary-100 dark:bg-primary-700' : '' + );
diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 43201a8..8bb27ec 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,5 +1,5 @@ import { redirect } from '@sveltejs/kit'; export function load() { - redirect(308, '/gpt'); + redirect(307, '/gpt'); } diff --git a/src/routes/api/claude/single/+server.ts b/src/routes/api/claude/single/+server.ts index c6c7ae3..ed03020 100644 --- a/src/routes/api/claude/single/+server.ts +++ b/src/routes/api/claude/single/+server.ts @@ -1,5 +1,5 @@ import { AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY } from '$lib/server/secrets.js'; -import type { Message } from '$lib/chat'; +import type { Message } from '$lib/chat.svelte.ts'; import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime'; export async function POST({ request }) { diff --git a/src/routes/api/claude/stream/+server.ts b/src/routes/api/claude/stream/+server.ts index 2218640..5618fb1 100644 --- a/src/routes/api/claude/stream/+server.ts +++ b/src/routes/api/claude/stream/+server.ts @@ -1,6 +1,6 @@ import { AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY } from '$lib/server/secrets.js'; import { logger } from '$lib/server/utils'; -import type { Message } from '$lib/chat'; +import type { Message } from '$lib/types'; import { BedrockRuntimeClient, ConverseStreamCommand } from '@aws-sdk/client-bedrock-runtime'; export async function POST({ request }) { diff --git a/src/routes/api/gpt/+server.ts b/src/routes/api/gpt/+server.ts index 7b63004..ffca4da 100644 --- a/src/routes/api/gpt/+server.ts +++ b/src/routes/api/gpt/+server.ts @@ -1,7 +1,7 @@ import { getAzureOpenAiClient } from '$lib/server/azure'; -import type { Message } from '$lib/types'; import { logger } from '$lib/server/utils'; import { AZURE_OPENAI_GPT_DEPLOYMENT_NAME } from '$lib/server/secrets'; +import type { Message } from '$lib/chat.svelte.js'; export async function POST({ request, locals }) { const data = await request.json(); diff --git a/src/routes/api/markdown2docx/+server.ts b/src/routes/api/markdown2docx/+server.ts new file mode 100644 index 0000000..312f52c --- /dev/null +++ b/src/routes/api/markdown2docx/+server.ts @@ -0,0 +1,23 @@ +import { PANDOC_SERVER_ENDPOINT } from '$lib/server/secrets.js'; +import { logger } from '$lib/server/utils'; + +export const POST = async ({ request, fetch }) => { + logger.info('Pandoc API called'); + + const markdown = await request.text(); + const blob = new Blob([markdown], { type: 'text/markdown' }); + const form = new FormData(); + form.append('to', 'docx'); + form.append('from', 'md'); + form.append('file', blob); + + const response = await fetch(PANDOC_SERVER_ENDPOINT, { + method: 'POST', + body: form + }); + + if (!response.ok) { + return new Response(await response.text(), { status: 500 }); + } + return new Response(await response.blob()); +}; diff --git a/src/routes/dalle/+page.svelte b/src/routes/dalle/+page.svelte index b3b0d1b..c833113 100644 --- a/src/routes/dalle/+page.svelte +++ b/src/routes/dalle/+page.svelte @@ -15,46 +15,44 @@ - - - + + - - - - + + + + - - + {#if form?.urls} diff --git a/src/routes/dev/+page.svelte b/src/routes/dev/+page.svelte new file mode 100644 index 0000000..9dcdd21 --- /dev/null +++ b/src/routes/dev/+page.svelte @@ -0,0 +1,7 @@ + + + (files = f)} /> diff --git a/src/routes/diarize-submit/+page.svelte b/src/routes/diarize-submit/+page.svelte index fb57ee3..4fbd2f5 100644 --- a/src/routes/diarize-submit/+page.svelte +++ b/src/routes/diarize-submit/+page.svelte @@ -9,22 +9,16 @@ - - - - + + diff --git a/src/routes/document-generation/+page.svelte b/src/routes/document-generation/+page.svelte new file mode 100644 index 0000000..4497b4f --- /dev/null +++ b/src/routes/document-generation/+page.svelte @@ -0,0 +1,82 @@ + + +{#if isLoading} + +{:else} +
+ + {}} /> + +
+{/if} diff --git a/src/routes/document-generation/SectionNode.svelte b/src/routes/document-generation/SectionNode.svelte new file mode 100644 index 0000000..05b63c0 --- /dev/null +++ b/src/routes/document-generation/SectionNode.svelte @@ -0,0 +1,80 @@ + + +
+
+ {#if editable} + + {:else} + {section.title} + {/if} +
+ + + {#if !isRoot} + + {/if} +
+
+
+ {#if editable} + + {:else} + {#if (section.files?.length ?? 0) < section.n_required_files} + + {/if} + + {#if section.files} + {#each section.files as file} + + {/each} + {/if} +
+ {section.instructions} +
+ {/if} +
+
+ {#each section.children as child} + onChildDelete(child)} isRoot={false} /> + {/each} +
+
diff --git a/src/routes/document-generation/presets.ts b/src/routes/document-generation/presets.ts new file mode 100644 index 0000000..ee8c442 --- /dev/null +++ b/src/routes/document-generation/presets.ts @@ -0,0 +1,44 @@ +import { Section } from './section'; + +export const customPreset = new Section({ + title: 'Document Title', + instructions: 'Document instructions' +}); + +export const grantProposalPreset = new Section({ + title: 'Title (create one if the user does not modify this)', + instructions: + 'The user has provided a list of files containing information on the grant they are writing.', + n_required_files: 1, + children: [ + new Section({ + title: 'Aims', + instructions: `The goal is to construct a compelling argument that is very easy to understand and repeat. In practice, this is what will be read most closely, and what will be referred back to when describing the project to other panelists. An important point to remember is that unless a detail (e.g., piece of background, element of the approach) is directly tied to the argument you are making, it should not be included in your aims page. In order to build a compelling argument, you need to: +(Paragraph 1) Clearly state the domain you are thinking about. +(Paragraph 1) Make it crystal clear why this domain is important and impactful. +(Paragraph 1) Point out issues or gaps in the current state-of-the-art in this domain, and expand until you are one argument shy of properly discouraging the reader. Note that every issue or gap you point out should be directly addressed in your aims that come later on. +(Paragraph 1) In one sentence, summarize all of the problems you will solve in your project. +(Paragraph 2) Clearly restate the problem you will solve, with slightly more emphasis on the impact it will have, and how you will accomplish it. This is the guiding light of your grant, and what you are striving towards. +(Paragraph 2) Expand the proposal into components of the solution sequentially. You may include details pertaining to high-level approach (e.g., datasets, communities, or conceptual approaches leveraged), but no in-the-weeds methodological details unless they strengthen the argument for your approach. +(Paragraph 2) Summarize, in one or two strong sentences, the concrete outcomes of your funded and successfully executed project on the field, linking each example to the aims you are about to enumerate in greater detail. +(Paragraph 3) After the aims, tie this section up with an impact sentence that paints a picture of what the scientific landscape will look like for your domain once your project completes. + +The aims are the scaffolding of your project. They should complement one another, but be able to be tackled independently, and advanced in parallel to one another — if each aim is a resounding success, those downstream will be improved, not enabled; conversely, if an aim were to fail, it would not disable those downstream. You should have between 2–4 of them, but without numbers exceeding 3 (e.g., if you have 4 aims, at least two should be sub-aims of the same number). In general: +Each must have a title that stands alone as a simple, impactful, and easy to articulate sentence for what the aim will accomplish. The aim title does not need to include methodological details unless the point of innovation for the aim is the methodology. +The brief summary of each aim then restates the core gap being addressed, and how the proposed method solves this problem. +You should include precisely enough methodological details in this section that make it clear that you know how to accomplish the stated aim, but not so much that you invite deep scrutiny on how you will go about it — this is the abstract, not the methods section. +You should conclude each aim statement with a hypothesis and/or clear and measurable outcome. In a perfect world, if the aim is well constructed it should be impossible not to accomplish, i.e., a hypothesis that will surely be tested, or an approach that will be applied, rather than an improvement in baseline performance that may not be reached. This may not be possible for all sorts of projects, but is important to keep in mind when constructing the way that each aim will be evaluated. +As mentioned above, the aims should be related and interconnected, but without dependence upon one another. If two are inextricably linked and one depends upon another, they should be paired sub-aims. +` + }), + new Section({ + title: 'Significance and Innovation', + instructions: `The significance and innovation are where you get the opportunity to make it even more obvious why the problem you’ve chosen to tackle is important, and how your work is different from the rest. These sections should expand elements of your aims that deserve more attention, and should mirror one another closely. The relationships, purpose, and structure of each of these sections are: +Each aim states the work that will be performed and outcome that will be achieved. +The significance section allows you to expand on challenges that exist in each aim (approximately 1–2 per, totally ~5 significance points) and restate in concrete terms why these are impactful gaps, and the impact that your work will have by addressing them. In other words, the significance allows you to provide a deeper and more concretely evidence-backed take on various critical elements of your problem statement, and immediately follow them up with your proposed solutions. +The innovation section then reflects your significance — containing a perfect 1-1 mapping of points in the two, — with an emphasis on how your solution to this problem is novel and moved beyond prior attempts. You restate the solution that your work will produce, and highlight how it exceeds prior art. Importantly, presenting a positive spin on your work, as opposed to a negative spin on the prior work, is important here. You then get to restate the impact of your new solution, and, when possible, highlight other problems that will be unlocked by this innovation. +Put together, you can effectively consider each significance-innovation pair as a complete story arc for one particular element of your proposal. Similar to the aims themselves, the ~5 points that are decided upon to be called out and elaborated upon here should complement one another but not depend on one another. If all elements succeed, the interactions increase the relative strength of each, but if one fails, the others all remain standing. +` + }) + ] +}); diff --git a/src/routes/document-generation/section.ts b/src/routes/document-generation/section.ts new file mode 100644 index 0000000..a0d41c2 --- /dev/null +++ b/src/routes/document-generation/section.ts @@ -0,0 +1,66 @@ +type SectionOptions = { + title: string; + instructions: string; + files?: FileList | undefined; + n_required_files?: number; + children?: Section[]; +}; + +export class Section { + public title: string; + public instructions: string; + public files: FileList | undefined; + public children: Section[]; + public n_required_files: number; + + constructor({ + title, + instructions, + files = undefined, + children = [], + n_required_files = 0 + }: SectionOptions) { + if (n_required_files < 0 || !Number.isInteger(n_required_files)) { + throw 'n_required_files must be a non-negative integer.'; + } + this.title = title; + this.instructions = instructions; + this.files = files; + this.children = children; + this.n_required_files = n_required_files; + } + + public getPrompt(): string { + return JSON.stringify(this.getPromptObj()); + } + + private getPromptObj(): object { + return { + title: this.title, + instructions: this.instructions, + files: this.files + ? Array.from(this.files).map((file) => { + return { + fileName: file.name, + fileContent: file.text() + }; + }) + : undefined, + children: this.children.map((child) => { + return child.getPromptObj(); + }) + }; + } + + public clone() { + return new Section({ + title: this.title, + instructions: this.instructions, + files: this.files, + children: this.children.map((child): Section => { + return child.clone(); + }), + n_required_files: this.n_required_files + }); + } +} diff --git a/src/routes/document-intelligence/+page.svelte b/src/routes/document-intelligence/+page.svelte index c105d0c..341d18a 100644 --- a/src/routes/document-intelligence/+page.svelte +++ b/src/routes/document-intelligence/+page.svelte @@ -44,16 +44,14 @@ - - - + diff --git a/src/routes/embedding/+page.svelte b/src/routes/embedding/+page.svelte index 7841423..3b5a77b 100644 --- a/src/routes/embedding/+page.svelte +++ b/src/routes/embedding/+page.svelte @@ -20,18 +20,16 @@ text file like .txt.`; - - - - + + diff --git a/src/routes/gpt/+page.svelte b/src/routes/gpt/+page.svelte index 1c82b04..01e2dd5 100644 --- a/src/routes/gpt/+page.svelte +++ b/src/routes/gpt/+page.svelte @@ -1,29 +1,25 @@ - {#each Object.keys(prompts.system) as name} @@ -34,6 +33,5 @@ rows="8" placeholder="Lorem ipsum dolor sit amet consectetur adipisicing elit." bind:value={systemPrompt} - {disabled} - /> + > diff --git a/src/routes/text-to-speech/+page.svelte b/src/routes/text-to-speech/+page.svelte index 9021c07..63a97ec 100644 --- a/src/routes/text-to-speech/+page.svelte +++ b/src/routes/text-to-speech/+page.svelte @@ -41,39 +41,37 @@ - - - - - + + - - + + - - - + + diff --git a/src/routes/transcription/+page.server.ts b/src/routes/transcription/+page.server.ts index 00a34c6..1044d57 100644 --- a/src/routes/transcription/+page.server.ts +++ b/src/routes/transcription/+page.server.ts @@ -3,7 +3,7 @@ import ffmpeg from 'fluent-ffmpeg'; import fs from 'fs'; import path from 'node:path'; import { memoryFileToDiskFile, diskFileToMemoryFile } from '$lib/fileHandling'; -import type { whisperLanguagesTypes } from '$lib/types'; +import type { whisperLanguagesTypes } from './whisperLanguages'; import { logger } from '$lib/server/utils'; import { getAzureOpenAiClient } from '$lib/server/azure'; import { AZURE_OPENAI_WHISPER_DEPLOYMENT_NAME } from '$lib/server/secrets'; diff --git a/src/routes/transcription/+page.svelte b/src/routes/transcription/+page.svelte index 6fe64f5..8535eba 100644 --- a/src/routes/transcription/+page.svelte +++ b/src/routes/transcription/+page.svelte @@ -21,27 +21,25 @@ - - - - - - + + + + diff --git a/src/routes/transcription/whisperLanguages.ts b/src/routes/transcription/whisperLanguages.ts index 5c1be23..af2057d 100644 --- a/src/routes/transcription/whisperLanguages.ts +++ b/src/routes/transcription/whisperLanguages.ts @@ -1,4 +1,61 @@ -import type { whisperLanguagesTypes } from '$lib/types'; +export type whisperLanguagesTypes = + | 'af' + | 'ar' + | 'hy' + | 'az' + | 'be' + | 'bs' + | 'bg' + | 'ca' + | 'zh' + | 'hr' + | 'cs' + | 'da' + | 'nl' + | 'en' + | 'et' + | 'fi' + | 'fr' + | 'gl' + | 'de' + | 'el' + | 'he' + | 'hi' + | 'hu' + | 'is' + | 'id' + | 'it' + | 'ja' + | 'kn' + | 'kk' + | 'ko' + | 'lv' + | 'lt' + | 'mk' + | 'ms' + | 'mr' + | 'mi' + | 'ne' + | 'no' + | 'fa' + | 'pl' + | 'pt' + | 'ro' + | 'ru' + | 'sr' + | 'sk' + | 'sl' + | 'es' + | 'sw' + | 'sv' + | 'tl' + | 'ta' + | 'th' + | 'tr' + | 'uk' + | 'ur' + | 'vi' + | 'cy'; export const whisperLanguages: Record = { English: 'en', diff --git a/tests/navigation.test.ts b/tests/navigation.test.ts index 434b238..7931049 100644 --- a/tests/navigation.test.ts +++ b/tests/navigation.test.ts @@ -27,7 +27,7 @@ test('clicking on a link changes the route', async ({ page }) => { for (const link of links) { const href = await link.getAttribute('href'); await link.click(); - await page.waitForTimeout(500); + await page.waitForTimeout(1000); expect(page.url()).toBe('http://localhost:4173' + href); }