diff --git a/package-lock.json b/package-lock.json index c733a5a..86325a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@dimforge/rapier3d-compat": "^0.11.2", "@langchain/anthropic": "^0.3.1", "@langchain/community": "^0.3.1", + "@langchain/core": "^0.2.34", "@langchain/openai": "^0.3.0", "@langchain/textsplitters": "^0.1.0", "@tensorflow-models/universal-sentence-encoder": "^1.3.3", @@ -18,7 +19,9 @@ "@threlte/core": "^7.3.1", "@threlte/extras": "^8.11.5", "@threlte/rapier": "^2.0.1", + "epub2": "^3.0.2", "fuse.js": "^7.0.0", + "html-to-text": "^9.0.5", "marked": "^12.0.2", "mdsvex": "^0.11.2", "three": "^0.159.0" @@ -1239,16 +1242,15 @@ } }, "node_modules/@langchain/core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.3.tgz", - "integrity": "sha512-WAtkmhbdl2T41qzimTzhb3pXCHQxO4onqxzPxgdf3KftQdTwLq0YYBDhozRMZLNAd/+cfH0ymZGaZSsnc9Ogsg==", - "peer": true, + "version": "0.2.34", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.2.34.tgz", + "integrity": "sha512-Hkveq1UcOjUj1DVn5erbqElyRj1t04NORSuSIZAJCtPO7EDkIqomjAarJ5+I5NUpQeIONgbOdnY9TkJ6cKUSVA==", "dependencies": { "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", - "langsmith": "^0.1.56", + "langsmith": "^0.1.56-rc.1", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", @@ -1264,7 +1266,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "peer": true, "engines": { "node": ">=10" }, @@ -1751,6 +1752,18 @@ "win32" ] }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "dependencies": { + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2722,6 +2735,26 @@ "node": ">= 0.4" } }, + "node_modules/array-hyper-unique": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/array-hyper-unique/-/array-hyper-unique-2.1.6.tgz", + "integrity": "sha512-BdlHRqjKSYs88WFaVNVEc6Kv8ln/FdzCKPbcDPuWs4/EXkQFhnjc8TyR7hnPxRjcjo5LKOhUMGUWpAqRgeJvpA==", + "dependencies": { + "deep-eql": "= 4.0.0", + "lodash": "^4.17.21" + } + }, + "node_modules/array-hyper-unique/node_modules/deep-eql": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.0.0.tgz", + "integrity": "sha512-GxJC5MOg2KyQlv6WiUF/VAnMj4MWnYiXo4oLgeptOELVoknyErb4Z8+5F/IM/K4g9/80YzzatxmWcyRwUseH0A==", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2855,6 +2888,11 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -2976,7 +3014,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "peer": true, "engines": { "node": ">=10" }, @@ -3251,6 +3288,14 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/crlf-normalize": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/crlf-normalize/-/crlf-normalize-1.0.20.tgz", + "integrity": "sha512-h/rBerTd3YHQGfv7tNT25mfhWvRq2BBLCZZ80GFarFxf6HQGbpW6iqDL3N+HBLpjLfAdcBXfWAzVlLfHkRUQBQ==", + "dependencies": { + "ts-type": ">=2" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3347,7 +3392,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3400,7 +3444,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3491,6 +3534,57 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/earcut": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", @@ -3524,6 +3618,30 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/epub2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/epub2/-/epub2-3.0.2.tgz", + "integrity": "sha512-rhvpt27CV5MZfRetfNtdNwi3XcNg1Am0TwfveJkK8YWeHItHepQ8Js9J06v8XRIjuTrCW/NSGYMTy55Of7BfNQ==", + "dependencies": { + "adm-zip": "^0.5.10", + "array-hyper-unique": "^2.1.4", + "bluebird": "^3.7.2", + "crlf-normalize": "^1.0.19", + "tslib": "^2.6.2", + "xml2js": "^0.6.2" + } + }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -4471,6 +4589,39 @@ "node": ">= 0.4" } }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "dependencies": { + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", @@ -4952,6 +5103,14 @@ "node": ">=14" } }, + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5016,6 +5175,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", @@ -5334,7 +5498,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "peer": true, "bin": { "mustache": "bin/mustache" } @@ -5709,6 +5872,18 @@ "node": ">=6" } }, + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "dependencies": { + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5781,6 +5956,14 @@ "node": "*" } }, + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/periscopic": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", @@ -6490,11 +6673,27 @@ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", "dev": true }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, + "node_modules/selderee": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", + "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "dependencies": { + "parseley": "^0.12.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -7398,11 +7597,29 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "peer": true + }, + "node_modules/ts-type": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ts-type/-/ts-type-3.0.1.tgz", + "integrity": "sha512-cleRydCkBGBFQ4KAvLH0ARIkciduS745prkGVVxPGvcRGhMMoSJUB7gNR1ByKhFTEYrYRg2CsMRGYnqp+6op+g==", + "dependencies": { + "@types/node": "*", + "tslib": ">=2", + "typedarray-dts": "^1.0.0" + }, + "peerDependencies": { + "ts-toolbelt": "^9.6.0" + } + }, "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -7441,7 +7658,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, "engines": { "node": ">=4" } @@ -7458,6 +7674,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedarray-dts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typedarray-dts/-/typedarray-dts-1.0.0.tgz", + "integrity": "sha512-Ka0DBegjuV9IPYFT1h0Qqk5U4pccebNIJCGl8C5uU7xtOs+jpJvKGAY4fHGK25hTmXZOEUl9Cnsg5cS6K/b5DA==" + }, "node_modules/typescript": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", @@ -7924,6 +8145,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 9d530e0..f5b0755 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@dimforge/rapier3d-compat": "^0.11.2", "@langchain/anthropic": "^0.3.1", "@langchain/community": "^0.3.1", + "@langchain/core": "^0.2.34", "@langchain/openai": "^0.3.0", "@langchain/textsplitters": "^0.1.0", "@tensorflow-models/universal-sentence-encoder": "^1.3.3", @@ -57,7 +58,9 @@ "@threlte/core": "^7.3.1", "@threlte/extras": "^8.11.5", "@threlte/rapier": "^2.0.1", + "epub2": "^3.0.2", "fuse.js": "^7.0.0", + "html-to-text": "^9.0.5", "marked": "^12.0.2", "mdsvex": "^0.11.2", "three": "^0.159.0" diff --git a/src/app.d.ts b/src/app.d.ts index 743f07b..f18e24f 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -3,11 +3,13 @@ declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + sessionId: string; + } // interface PageData {} // interface PageState {} // interface Platform {} } } -export {}; +export { }; diff --git a/src/lib/store.ts b/src/lib/store.ts index 6bcdf3c..b2db69d 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -1,5 +1,26 @@ import { writable } from 'svelte/store'; import type { SearchResult } from './utils/search'; +import type { HumanMessage, AIMessage, SystemMessage } from '@langchain/core/messages'; const initArray: SearchResult[] = []; export const searchResults = writable(initArray); + +export type ChatHistory = (HumanMessage | AIMessage | SystemMessage)[]; + +const chatHistories: Record = {}; + +export const chatStore = writable(chatHistories); + +export function getChatHistory(sessionId: string): ChatHistory { + return chatHistories[sessionId] || []; +} + +export function setChatHistory(sessionId: string, history: ChatHistory): void { + chatHistories[sessionId] = history; + chatStore.set(chatHistories); +} + +export function clearChatHistory(sessionId: string): void { + chatHistories[sessionId] = []; + chatStore.set(chatHistories); +} diff --git a/src/routes/ai/+page.svelte b/src/routes/ai/+page.svelte index 11f4a73..5051882 100644 --- a/src/routes/ai/+page.svelte +++ b/src/routes/ai/+page.svelte @@ -1,11 +1,10 @@ @@ -93,13 +108,29 @@ {#if searchResultsValue.length === 0} -
+
+
+
+
+ Portrait of an orange tabby cat reading a book +
+
+ + This lil guy just finished reading + A History of Tea + , so ask 'em anything about the book. + +
{#each chatHistory as message} {@const { role, content } = getRoleAndContent(message)} {#if role === 'human'}
-
+
{@html renderMarkdown(content)}
@@ -112,30 +143,29 @@
{#if loading} -
+
+ This may take a minute; streaming is still a work in progress.
{/if}
- +
{/if} diff --git a/src/routes/api/ai/+server.ts b/src/routes/api/ai/+server.ts index d41199d..0369890 100644 --- a/src/routes/api/ai/+server.ts +++ b/src/routes/api/ai/+server.ts @@ -1,47 +1,34 @@ import { json } from '@sveltejs/kit'; -import { FaissStore } from '@langchain/community/vectorstores/faiss'; -import { OpenAIEmbeddings } from '@langchain/openai'; import { ChatAnthropic } from '@langchain/anthropic'; import { RunnableSequence, RunnablePassthrough } from '@langchain/core/runnables'; import { StringOutputParser } from '@langchain/core/output_parsers'; import { ChatPromptTemplate } from '@langchain/core/prompts'; -import { join } from 'path'; -import { HumanMessage, AIMessage, SystemMessage } from '@langchain/core/messages'; +import { HumanMessage, AIMessage } from '@langchain/core/messages'; import type { RequestEvent } from '@sveltejs/kit'; - -const chatHistories: Record = {}; - -type VectorDocument = { - pageContent: string; -}; - -const formatDocumentsAsString = (documents: VectorDocument[]) => { - return documents.map((doc) => doc.pageContent).join('\n\n'); -}; - -export type ChatHistory = HumanMessage[] | AIMessage[] | SystemMessage[]; +import { EPubLoader } from "@langchain/community/document_loaders/fs/epub"; +import { join } from 'path'; +import { getChatHistory, setChatHistory } from '$lib/store'; export async function POST({ request, locals }: RequestEvent): Promise { const { query } = await request.json(); const sessionId = locals.sessionId; - if (!chatHistories[sessionId]) { - chatHistories[sessionId] = []; - } - const chatHistory = chatHistories[sessionId]; + const chatHistory = getChatHistory(sessionId); - const directory = join(process.cwd(), 'vectorstore'); - const embeddings = new OpenAIEmbeddings(); - const vectorStore = await FaissStore.load(directory, embeddings); - const vectorStoreRetriever = vectorStore.asRetriever(); + const directory = join(process.cwd(), 'static/book.epub'); + const loader = new EPubLoader(directory); + const docs = await loader.load(); + + const context = docs.map(doc => doc.pageContent).join('\n\n'); const model = new ChatAnthropic({ modelName: 'claude-3-5-sonnet-20240620', - anthropicApiKey: process.env.ANTHROPIC_API_KEY + anthropicApiKey: process.env.ANTHROPIC_API_KEY, }); const SYSTEM_TEMPLATE = `Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. +Always format your response in markdown. ---------------- @@ -59,7 +46,7 @@ Question: const chain = RunnableSequence.from([ { - context: vectorStoreRetriever.pipe(formatDocumentsAsString), + context: () => context, question: new RunnablePassthrough(), }, prompt, @@ -72,11 +59,13 @@ Question: chatHistory.push(new HumanMessage({ content: query })); chatHistory.push(new AIMessage({ content: answer })); + setChatHistory(sessionId, chatHistory); + return json({ response: answer, chatHistory }); } export async function GET({ locals }): Promise { const sessionId = locals.sessionId; - const chatHistory = chatHistories[sessionId] || []; + const chatHistory = getChatHistory(sessionId); return json({ chatHistory }); } diff --git a/src/routes/api/ai/new-session/+server.ts b/src/routes/api/ai/new-session/+server.ts new file mode 100644 index 0000000..b9880a3 --- /dev/null +++ b/src/routes/api/ai/new-session/+server.ts @@ -0,0 +1,8 @@ +import type { RequestEvent } from '@sveltejs/kit'; +import { clearChatHistory } from '$lib/store'; + +export async function POST({ locals }: RequestEvent) { + const sessionId = locals.sessionId; + clearChatHistory(sessionId); + return new Response(null, { status: 204 }); +} diff --git a/src/routes/projects/+page.svelte b/src/routes/projects/+page.svelte index b0556f7..8540ab8 100644 --- a/src/routes/projects/+page.svelte +++ b/src/routes/projects/+page.svelte @@ -34,13 +34,12 @@ 'An experiment with 3D vector math for a rudimentary simulation of gravity. You can change the strength of the gravity in the Controls menu.' }, { - title: 'Animation Editor', - path: '/editor', - source: - 'https://git.silentsilas.com/silentsilas/playground/src/branch/main/src/routes/editor', + title: 'Tea Guru', + path: '/ai', + source: 'https://git.silentsilas.com/silentsilas/playground/src/branch/main/src/routes/ai', position: [4, -2, -4], description: - 'A 3D animation editor via Theatre.js. This is used internally by me for other ThreeJS projects.' + 'A chatbot trained on an in-depth book about tea. Ask it about anything related to tea!' }, { title: 'Headbang', diff --git a/static/book.epub b/static/book.epub new file mode 100644 index 0000000..a49f4bf Binary files /dev/null and b/static/book.epub differ diff --git a/static/imgs/ai/profile.jpg b/static/imgs/ai/profile.jpg new file mode 100644 index 0000000..ac56abe Binary files /dev/null and b/static/imgs/ai/profile.jpg differ