From fd4a48eb76ca6ac89c4b4d19544ec5c62aa10c85 Mon Sep 17 00:00:00 2001 From: Harald Schilly Date: Thu, 22 Feb 2024 14:02:21 +0100 Subject: [PATCH] server/llm: first steps towards supporting ollama --- .../components/language-model-icon.tsx | 4 + .../frontend/components/ollama-avatar.tsx | 33 ++ src/packages/frontend/components/ollama.png | Bin 0 -> 18226 bytes .../components/openai/vendor-status-check.tsx | 8 + src/packages/pnpm-lock.yaml | 423 +++++++++++++++++- src/packages/server/llm/client.ts | 35 +- src/packages/server/llm/embeddings.ts | 2 +- src/packages/server/llm/index.ts | 100 +++-- src/packages/server/llm/ollama.ts | 56 +++ src/packages/server/package.json | 1 + src/packages/util/db-schema/openai.ts | 12 +- src/packages/util/db-schema/site-defaults.ts | 8 + .../util/db-schema/site-settings-extras.ts | 13 +- 13 files changed, 641 insertions(+), 54 deletions(-) create mode 100644 src/packages/frontend/components/ollama-avatar.tsx create mode 100644 src/packages/frontend/components/ollama.png create mode 100644 src/packages/server/llm/ollama.ts diff --git a/src/packages/frontend/components/language-model-icon.tsx b/src/packages/frontend/components/language-model-icon.tsx index 1c84bbf196..bef2211d43 100644 --- a/src/packages/frontend/components/language-model-icon.tsx +++ b/src/packages/frontend/components/language-model-icon.tsx @@ -5,6 +5,7 @@ import { unreachable } from "@cocalc/util/misc"; import AIAvatar from "./ai-avatar"; import GoogleGeminiLogo from "./google-gemini-avatar"; import GooglePalmLogo from "./google-palm-avatar"; +import OllamaAvatar from "./ollama-avatar"; import OpenAIAvatar from "./openai-avatar"; export function LanguageModelVendorAvatar( @@ -40,6 +41,9 @@ export function LanguageModelVendorAvatar( return fallback(); } } + case "ollama": + return ; + default: unreachable(vendor); return fallback(); diff --git a/src/packages/frontend/components/ollama-avatar.tsx b/src/packages/frontend/components/ollama-avatar.tsx new file mode 100644 index 0000000000..c9c33f93c1 --- /dev/null +++ b/src/packages/frontend/components/ollama-avatar.tsx @@ -0,0 +1,33 @@ +import { CSS } from "../app-framework"; +import ollamaPng from "./ollama.png"; + +export default function OllamaAvatar({ + size = 64, + style, +}: { + size: number; + style?: CSS; +}) { + // render the ollamaPng (a square png image with transparent background) with the given size and background color + + return ( +
+ +
+ ); +} diff --git a/src/packages/frontend/components/ollama.png b/src/packages/frontend/components/ollama.png new file mode 100644 index 0000000000000000000000000000000000000000..1f142c8d534e0165096cd7ae1387be9bf0e83068 GIT binary patch literal 18226 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 ); + case "ollama": + return ( + <> + This Ollama based API endpoint does not have a status page. If you are + experiencing issues you have to check with the API service directly or + try again later. + + ); default: unreachable(vendor); } diff --git a/src/packages/pnpm-lock.yaml b/src/packages/pnpm-lock.yaml index c6a1b7496f..d975732d90 100644 --- a/src/packages/pnpm-lock.yaml +++ b/src/packages/pnpm-lock.yaml @@ -1339,6 +1339,9 @@ importers: '@isaacs/ttlcache': specifier: ^1.2.1 version: 1.2.1 + '@langchain/community': + specifier: ^0.0.32 + version: 0.0.32(@google-ai/generativelanguage@1.1.0)(encoding@0.1.13)(google-auth-library@9.4.1)(lodash@4.17.21) '@node-saml/passport-saml': specifier: ^4.0.4 version: 4.0.4 @@ -3979,6 +3982,307 @@ packages: - crypto dev: false + /@langchain/community@0.0.32(@google-ai/generativelanguage@1.1.0)(encoding@0.1.13)(google-auth-library@9.4.1)(lodash@4.17.21): + resolution: {integrity: sha512-jN4BxGKAmLbA87hqXH5Mx1IRMMVOgcn1TY1MLOVyBcBa12EvHFx8suogtXgA2ekfc8U8nIryVb1ftSupwUBv/A==} + engines: {node: '>=18'} + peerDependencies: + '@aws-crypto/sha256-js': ^5.0.0 + '@aws-sdk/client-bedrock-agent-runtime': ^3.485.0 + '@aws-sdk/client-bedrock-runtime': ^3.422.0 + '@aws-sdk/client-dynamodb': ^3.310.0 + '@aws-sdk/client-kendra': ^3.352.0 + '@aws-sdk/client-lambda': ^3.310.0 + '@aws-sdk/client-sagemaker-runtime': ^3.310.0 + '@aws-sdk/client-sfn': ^3.310.0 + '@aws-sdk/credential-provider-node': ^3.388.0 + '@azure/search-documents': ^12.0.0 + '@clickhouse/client': ^0.2.5 + '@cloudflare/ai': '*' + '@datastax/astra-db-ts': ^0.1.4 + '@elastic/elasticsearch': ^8.4.0 + '@getmetal/metal-sdk': '*' + '@getzep/zep-js': ^0.9.0 + '@gomomento/sdk': ^1.51.1 + '@gomomento/sdk-core': ^1.51.1 + '@google-ai/generativelanguage': ^0.2.1 + '@gradientai/nodejs-sdk': ^1.2.0 + '@huggingface/inference': ^2.6.4 + '@mozilla/readability': '*' + '@opensearch-project/opensearch': '*' + '@pinecone-database/pinecone': '*' + '@planetscale/database': ^1.8.0 + '@qdrant/js-client-rest': ^1.2.0 + '@raycast/api': ^1.55.2 + '@rockset/client': ^0.9.1 + '@smithy/eventstream-codec': ^2.0.5 + '@smithy/protocol-http': ^3.0.6 + '@smithy/signature-v4': ^2.0.10 + '@smithy/util-utf8': ^2.0.0 + '@supabase/postgrest-js': ^1.1.1 + '@supabase/supabase-js': ^2.10.0 + '@tensorflow-models/universal-sentence-encoder': '*' + '@tensorflow/tfjs-converter': '*' + '@tensorflow/tfjs-core': '*' + '@upstash/redis': ^1.20.6 + '@upstash/vector': ^1.0.2 + '@vercel/kv': ^0.2.3 + '@vercel/postgres': ^0.5.0 + '@writerai/writer-sdk': ^0.40.2 + '@xata.io/client': ^0.28.0 + '@xenova/transformers': ^2.5.4 + '@zilliz/milvus2-sdk-node': '>=2.2.7' + better-sqlite3: ^9.4.0 + cassandra-driver: ^4.7.2 + chromadb: '*' + closevector-common: 0.1.3 + closevector-node: 0.1.6 + closevector-web: 0.1.6 + cohere-ai: '*' + convex: ^1.3.1 + discord.js: ^14.14.1 + dria: ^0.0.3 + faiss-node: ^0.5.1 + firebase-admin: ^11.9.0 || ^12.0.0 + google-auth-library: ^8.9.0 + googleapis: ^126.0.1 + hnswlib-node: ^1.4.2 + html-to-text: ^9.0.5 + ioredis: ^5.3.2 + jsdom: '*' + llmonitor: ^0.5.9 + lodash: ^4.17.21 + lunary: ^0.6.11 + mongodb: '>=5.2.0' + mysql2: ^3.3.3 + neo4j-driver: '*' + node-llama-cpp: '*' + pg: ^8.11.0 + pg-copy-streams: ^6.0.5 + pickleparser: ^0.2.1 + portkey-ai: ^0.1.11 + redis: '*' + replicate: ^0.18.0 + typeorm: ^0.3.12 + typesense: ^1.5.3 + usearch: ^1.1.1 + vectordb: ^0.1.4 + voy-search: 0.6.2 + weaviate-ts-client: '*' + web-auth-library: ^1.0.3 + ws: ^8.14.2 + peerDependenciesMeta: + '@aws-crypto/sha256-js': + optional: true + '@aws-sdk/client-bedrock-agent-runtime': + optional: true + '@aws-sdk/client-bedrock-runtime': + optional: true + '@aws-sdk/client-dynamodb': + optional: true + '@aws-sdk/client-kendra': + optional: true + '@aws-sdk/client-lambda': + optional: true + '@aws-sdk/client-sagemaker-runtime': + optional: true + '@aws-sdk/client-sfn': + optional: true + '@aws-sdk/credential-provider-node': + optional: true + '@azure/search-documents': + optional: true + '@clickhouse/client': + optional: true + '@cloudflare/ai': + optional: true + '@datastax/astra-db-ts': + optional: true + '@elastic/elasticsearch': + optional: true + '@getmetal/metal-sdk': + optional: true + '@getzep/zep-js': + optional: true + '@gomomento/sdk': + optional: true + '@gomomento/sdk-core': + optional: true + '@google-ai/generativelanguage': + optional: true + '@gradientai/nodejs-sdk': + optional: true + '@huggingface/inference': + optional: true + '@mozilla/readability': + optional: true + '@opensearch-project/opensearch': + optional: true + '@pinecone-database/pinecone': + optional: true + '@planetscale/database': + optional: true + '@qdrant/js-client-rest': + optional: true + '@raycast/api': + optional: true + '@rockset/client': + optional: true + '@smithy/eventstream-codec': + optional: true + '@smithy/protocol-http': + optional: true + '@smithy/signature-v4': + optional: true + '@smithy/util-utf8': + optional: true + '@supabase/postgrest-js': + optional: true + '@supabase/supabase-js': + optional: true + '@tensorflow-models/universal-sentence-encoder': + optional: true + '@tensorflow/tfjs-converter': + optional: true + '@tensorflow/tfjs-core': + optional: true + '@upstash/redis': + optional: true + '@upstash/vector': + optional: true + '@vercel/kv': + optional: true + '@vercel/postgres': + optional: true + '@writerai/writer-sdk': + optional: true + '@xata.io/client': + optional: true + '@xenova/transformers': + optional: true + '@zilliz/milvus2-sdk-node': + optional: true + better-sqlite3: + optional: true + cassandra-driver: + optional: true + chromadb: + optional: true + closevector-common: + optional: true + closevector-node: + optional: true + closevector-web: + optional: true + cohere-ai: + optional: true + convex: + optional: true + discord.js: + optional: true + dria: + optional: true + faiss-node: + optional: true + firebase-admin: + optional: true + google-auth-library: + optional: true + googleapis: + optional: true + hnswlib-node: + optional: true + html-to-text: + optional: true + ioredis: + optional: true + jsdom: + optional: true + llmonitor: + optional: true + lodash: + optional: true + lunary: + optional: true + mongodb: + optional: true + mysql2: + optional: true + neo4j-driver: + optional: true + node-llama-cpp: + optional: true + pg: + optional: true + pg-copy-streams: + optional: true + pickleparser: + optional: true + portkey-ai: + optional: true + redis: + optional: true + replicate: + optional: true + typeorm: + optional: true + typesense: + optional: true + usearch: + optional: true + vectordb: + optional: true + voy-search: + optional: true + weaviate-ts-client: + optional: true + web-auth-library: + optional: true + ws: + optional: true + dependencies: + '@google-ai/generativelanguage': 1.1.0(encoding@0.1.13) + '@langchain/core': 0.1.32 + '@langchain/openai': 0.0.14(encoding@0.1.13) + flat: 5.0.2 + google-auth-library: 9.4.1(encoding@0.1.13) + langsmith: 0.1.3 + lodash: 4.17.21 + uuid: 9.0.1 + zod: 3.22.4 + transitivePeerDependencies: + - encoding + dev: false + + /@langchain/core@0.1.32: + resolution: {integrity: sha512-7b8wBQMej2QxaDDS0fCQa3/zrA2raTh1RBe2h1som7QxFpWJkHSxwVwdvGUotX9SopmsY99TK54sK0amfDvBBA==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 5.2.0 + camelcase: 6.3.0 + decamelize: 1.2.0 + js-tiktoken: 1.0.10 + langsmith: 0.1.3 + ml-distance: 4.0.1 + p-queue: 6.6.2 + p-retry: 4.6.2 + uuid: 9.0.1 + zod: 3.22.4 + zod-to-json-schema: 3.22.4(zod@3.22.4) + dev: false + + /@langchain/openai@0.0.14(encoding@0.1.13): + resolution: {integrity: sha512-co6nRylPrLGY/C3JYxhHt6cxLq07P086O7K3QaZH7SFFErIN9wSzJonpvhZR07DEUq6eK6wKgh2ORxA/NcjSRQ==} + engines: {node: '>=18'} + dependencies: + '@langchain/core': 0.1.32 + js-tiktoken: 1.0.10 + openai: 4.27.0(encoding@0.1.13) + zod: 3.22.4 + zod-to-json-schema: 3.22.4(zod@3.22.4) + transitivePeerDependencies: + - encoding + dev: false + /@lumino/algorithm@1.9.2: resolution: {integrity: sha512-Z06lp/yuhz8CtIir3PNTGnuk7909eXt4ukJsCzChsGuot2l5Fbs96RJ/FOHgwCedaX74CtxPjXHXoszFbUA+4A==} dev: false @@ -5498,6 +5802,10 @@ packages: '@types/node': 18.18.13 dev: false + /@types/retry@0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: false + /@types/sanitize-html@2.8.0: resolution: {integrity: sha512-Uih6caOm3DsBYnVGOYn0A9NoTNe1c4aPStmHC/YA2JrpP9kx//jzaRcIklFvSpvVQEcpl/ZCr4DgISSf/YxTvg==} dependencies: @@ -5552,6 +5860,10 @@ packages: /@types/uuid@8.3.4: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + /@types/uuid@9.0.8: + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + dev: false + /@types/xml-crypto@1.4.3: resolution: {integrity: sha512-pnvKYb7vUsUIMc+C6JM/j779YWQgOMcwjnqHJ9cdaWXwWEBE1hAqthzeszRx62V5RWMvS+XS9w9tXMOYyUc8zg==} dependencies: @@ -6143,7 +6455,6 @@ packages: /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} @@ -6751,6 +7062,10 @@ packages: resolution: {integrity: sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==} dev: false + /binary-search@1.3.6: + resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==} + dev: false + /bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} dependencies: @@ -7018,7 +7333,6 @@ packages: /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - dev: true /caniuse-lite@1.0.30001564: resolution: {integrity: sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==} @@ -7488,7 +7802,6 @@ packages: /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} - dev: true /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -7698,7 +8011,6 @@ packages: loose-envify: 1.4.0 object-assign: 4.1.1 dev: false - bundledDependencies: false /create-server@1.0.2: resolution: {integrity: sha512-hie+Kyero+jxt6dwKhLKtN23qSNiMn8mNIEjTjwzaZwH2y4tr4nYloeFrpadqV+ZqV9jQ15t3AKotaK8dOo45w==} @@ -9408,7 +9720,6 @@ packages: /flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - dev: true /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} @@ -10726,6 +11037,10 @@ packages: is-decimal: 2.0.1 dev: false + /is-any-array@2.0.1: + resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==} + dev: false + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -12238,6 +12553,12 @@ packages: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} dev: false + /js-tiktoken@1.0.10: + resolution: {integrity: sha512-ZoSxbGjvGyMT13x6ACo9ebhDha/0FHdKA+OsQcMOWcm1Zs7r90Rhk5lhERLzji+3rA7EKpXCgwXcM5fF3DMpdA==} + dependencies: + base64-js: 1.5.1 + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -12509,6 +12830,17 @@ packages: resolution: {integrity: sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA==} dev: false + /langsmith@0.1.3: + resolution: {integrity: sha512-kQMS3QySeU0Qt9A71d9trUXbeKn33HfxpRc7hRjSB967zcdTAngh66NcqYqBflD3nOL4FK6LKmvfb3vbNDEoPg==} + hasBin: true + dependencies: + '@types/uuid': 9.0.8 + commander: 10.0.1 + p-queue: 6.6.2 + p-retry: 4.6.2 + uuid: 9.0.1 + dev: false + /ldap-filter@0.3.3: resolution: {integrity: sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==} engines: {node: '>=0.8'} @@ -13186,6 +13518,37 @@ packages: resolution: {integrity: sha512-bauHShmaxVQiEvlrAPWxSPn8spSL8gDVRl11r8vLT4r/KdnknLqtqwQbToZ2Oa8sJkExYY1z6/d+X7pNiqo4yg==} dev: true + /ml-array-mean@1.1.6: + resolution: {integrity: sha512-MIdf7Zc8HznwIisyiJGRH9tRigg3Yf4FldW8DxKxpCCv/g5CafTw0RRu51nojVEOXuCQC7DRVVu5c7XXO/5joQ==} + dependencies: + ml-array-sum: 1.1.6 + dev: false + + /ml-array-sum@1.1.6: + resolution: {integrity: sha512-29mAh2GwH7ZmiRnup4UyibQZB9+ZLyMShvt4cH4eTK+cL2oEMIZFnSyB3SS8MlsTh6q/w/yh48KmqLxmovN4Dw==} + dependencies: + is-any-array: 2.0.1 + dev: false + + /ml-distance-euclidean@2.0.0: + resolution: {integrity: sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q==} + dev: false + + /ml-distance@4.0.1: + resolution: {integrity: sha512-feZ5ziXs01zhyFUUUeZV5hwc0f5JW0Sh0ckU1koZe/wdVkJdGxcP06KNQuF0WBTj8FttQUzcvQcpcrOp/XrlEw==} + dependencies: + ml-array-mean: 1.1.6 + ml-distance-euclidean: 2.0.0 + ml-tree-similarity: 1.0.0 + dev: false + + /ml-tree-similarity@1.0.0: + resolution: {integrity: sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==} + dependencies: + binary-search: 1.3.6 + num-sort: 2.1.0 + dev: false + /mocha@10.2.0: resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} engines: {node: '>= 14.0.0'} @@ -13693,6 +14056,11 @@ packages: dependencies: boolbase: 1.0.0 + /num-sort@2.1.0: + resolution: {integrity: sha512-1MQz1Ed8z2yckoBeSfkQHHO9K1yDRxxtotKSJ9yvcTUUxSvfvzEq5GwBrjjHEpMlq/k5gvXdmJ1SbYxWtpNoVg==} + engines: {node: '>=8'} + dev: false + /number-is-integer@1.0.1: resolution: {integrity: sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg==} engines: {node: '>=0.10.0'} @@ -13943,6 +14311,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + dev: false + /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -13980,6 +14353,29 @@ packages: dependencies: aggregate-error: 3.1.0 + /p-queue@6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + dev: false + + /p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + dev: false + + /p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + dependencies: + p-finally: 1.0.0 + dev: false + /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -16302,6 +16698,11 @@ packages: - supports-color dev: false + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: false + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -19079,10 +19480,22 @@ packages: resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} dev: false + /zod-to-json-schema@3.22.4(zod@3.22.4): + resolution: {integrity: sha512-2Ed5dJ+n/O3cU383xSY28cuVi0BCQhF8nYqWU5paEpl7fVdqdAmiLdqLyfblbNdfOFwFfi/mqU4O1pwc60iBhQ==} + peerDependencies: + zod: ^3.22.4 + dependencies: + zod: 3.22.4 + dev: false + /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: false + /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false diff --git a/src/packages/server/llm/client.ts b/src/packages/server/llm/client.ts index d6f2ba86c0..1f50dab0c0 100644 --- a/src/packages/server/llm/client.ts +++ b/src/packages/server/llm/client.ts @@ -11,12 +11,13 @@ import { getServerSettings } from "@cocalc/database/settings/server-settings"; import { LanguageModel, model2vendor } from "@cocalc/util/db-schema/openai"; import { unreachable } from "@cocalc/util/misc"; import { VertexAIClient } from "./vertex-ai-client"; +import { Ollama } from "@langchain/community/llms/ollama"; const log = getLogger("llm:client"); const clientCache: { [key: string]: OpenAI | VertexAIClient } = {}; -export default async function getClient( +export async function getClient( model?: LanguageModel, ): Promise { const vendor = model == null ? "openai" : model2vendor(model); @@ -56,8 +57,40 @@ export default async function getClient( clientCache[key] = vai; return vai; + case "ollama": + throw new Error("Use the getOllama function instead"); + default: unreachable(vendor); throw new Error(`unknown vendor: ${vendor}`); } } + +const ollamaCache: { [key: string]: Ollama } = {}; + +export async function getOllama(model: string) { + // model is the unique key in the ServerSettings.ollama_configuration mapping + if (ollamaCache[model]) { + return ollamaCache[model]; + } + + const settings = await getServerSettings(); + const config = settings.ollama_configuration?.[model]; + if (!config) { + throw new Error( + `Ollama model ${model} not configured – you have to create an entry {${model}: {url: "https://...", ...}} in the "Ollama Configuration" entry of the server settings`, + ); + } + + const baseUrl = config.url; + + if (!baseUrl) { + throw new Error(`The url of the Ollama model ${model} is not configured`); + } + + const keepAlive = config.keepAlive ?? -1; + + const client = new Ollama({ baseUrl, model, keepAlive }); + ollamaCache[model] = client; + return client; +} diff --git a/src/packages/server/llm/embeddings.ts b/src/packages/server/llm/embeddings.ts index 06ae65e3ac..0e805e4708 100644 --- a/src/packages/server/llm/embeddings.ts +++ b/src/packages/server/llm/embeddings.ts @@ -1,7 +1,7 @@ import { sha1, uuidsha1 } from "@cocalc/backend/sha1"; import { getClient as getDB } from "@cocalc/database/pool"; import * as qdrant from "@cocalc/database/qdrant"; -import getClient from "./client"; +import { getClient } from "./client"; import checkForAbuse from "./embeddings-abuse"; import { VertexAIClient } from "./vertex-ai-client"; diff --git a/src/packages/server/llm/index.ts b/src/packages/server/llm/index.ts index 6708288c99..8f2800d53e 100644 --- a/src/packages/server/llm/index.ts +++ b/src/packages/server/llm/index.ts @@ -31,9 +31,10 @@ import { import { ChatOptions, ChatOutput, History } from "@cocalc/util/types/llm"; import { checkForAbuse } from "./abuse"; import { callChatGPTAPI } from "./call-chatgpt"; -import getClient from "./client"; +import { getClient } from "./client"; import { saveResponse } from "./save-response"; import { VertexAIClient } from "./vertex-ai-client"; +import { evaluateOllama } from "./ollama"; const log = getLogger("llm"); @@ -59,38 +60,6 @@ export async function evaluate(opts: ChatOptions): Promise { } } -async function evaluteCall({ - system, - history, - input, - client, - model, - maxTokens, - stream, -}) { - if (client instanceof VertexAIClient) { - return await evaluateVertexAI({ - system, - history, - input, - client, - maxTokens, - model, - stream, - }); - } - - return await evaluateOpenAI({ - system, - history, - input, - client, - model, - maxTokens, - stream, - }); -} - async function evaluateImpl({ input, system, @@ -104,7 +73,7 @@ async function evaluateImpl({ stream, maxTokens, }: ChatOptions): Promise { - log.debug("evaluate", { + log.debug("evaluateImpl", { input, history, system, @@ -124,15 +93,28 @@ async function evaluateImpl({ const client = await getClient(model); const { output, total_tokens, prompt_tokens, completion_tokens } = - await evaluteCall({ - system, - history, - input, - client, - model, - maxTokens, - stream, - }); + await (async () => { + if (model.startsWith("ollama-")) { + return await evaluateOllama({ + system, + history, + input, + model, + maxTokens, + stream, + }); + } else { + return await evaluteCall({ + system, + history, + input, + client, + model, + maxTokens, + stream, + }); + } + })(); log.debug("response: ", { output, total_tokens, prompt_tokens }); const total_time_s = (Date.now() - start) / 1000; @@ -192,6 +174,38 @@ async function evaluateImpl({ return output; } +async function evaluteCall({ + system, + history, + input, + client, + model, + maxTokens, + stream, +}) { + if (client instanceof VertexAIClient) { + return await evaluateVertexAI({ + system, + history, + input, + client, + maxTokens, + model, + stream, + }); + } + + return await evaluateOpenAI({ + system, + history, + input, + client, + model, + maxTokens, + stream, + }); +} + interface EvalVertexAIProps { client: VertexAIClient; system?: string; diff --git a/src/packages/server/llm/ollama.ts b/src/packages/server/llm/ollama.ts new file mode 100644 index 0000000000..91ad6317f2 --- /dev/null +++ b/src/packages/server/llm/ollama.ts @@ -0,0 +1,56 @@ +import getLogger from "@cocalc/backend/logger"; +import { ChatOutput, History } from "@cocalc/util/types/llm"; +import { getOllama } from "./client"; + +const log = getLogger("llm:ollama"); + +// subset of ChatOptions, but model is a string +interface OllamaOpts { + input: string; // new input that user types + system?: string; // extra setup that we add for relevance and context + history?: History; + model: string; // this must be ollama-[model] + stream?: (output?: string) => void; + maxTokens?: number; +} + +export async function evaluateOllama( + opts: Readonly, +): Promise { + if (!opts.model.startsWith("ollama-")) { + throw new Error(`model ${opts.model} not supported`); + } + const model = opts.model.slice("ollama-".length); + const { system, history, input, maxTokens, stream } = opts; + log.debug("evaluateOllama", { + input, + history, + system, + model, + stream: stream != null, + maxTokens, + }); + + const ollama = await getOllama(model); + + const chunks = await ollama.stream(input); + + let output = ""; + for await (const chunk of chunks) { + output += chunk; + opts.stream?.(chunk); + } + + // and an empty call when done + opts.stream?.(); + + const prompt_tokens = 10; + const completion_tokens = 10; + + return { + output, + total_tokens: prompt_tokens + completion_tokens, + completion_tokens, + prompt_tokens, + }; +} diff --git a/src/packages/server/package.json b/src/packages/server/package.json index 9f8d42b723..a167fa941a 100644 --- a/src/packages/server/package.json +++ b/src/packages/server/package.json @@ -46,6 +46,7 @@ "@google-cloud/monitoring": "^4.0.0", "@google/generative-ai": "^0.1.3", "@isaacs/ttlcache": "^1.2.1", + "@langchain/community": "^0.0.32", "@node-saml/passport-saml": "^4.0.4", "@passport-js/passport-twitter": "^1.0.8", "@passport-next/passport-google-oauth2": "^1.0.0", diff --git a/src/packages/util/db-schema/openai.ts b/src/packages/util/db-schema/openai.ts index 83181e061a..372f47be07 100644 --- a/src/packages/util/db-schema/openai.ts +++ b/src/packages/util/db-schema/openai.ts @@ -72,7 +72,7 @@ export type LanguageService = | "google-embedding-gecko-001" | "google-gemini-pro"; -const LANGUAGE_MODEL_VENDORS = ["openai", "google"] as const; +const LANGUAGE_MODEL_VENDORS = ["openai", "google", "ollama"] as const; export type Vendor = (typeof LANGUAGE_MODEL_VENDORS)[number]; // used e.g. for checking "account-id={string}" and other things like that @@ -122,6 +122,8 @@ export const DEFAULT_MODEL: LanguageModel = "gpt-3.5-turbo"; export function model2vendor(model: LanguageModel): Vendor { if (model.startsWith("gpt-")) { return "openai"; + } else if (model.startsWith("ollama-")) { + return "ollama"; } else { return "google"; } @@ -193,6 +195,8 @@ export function getVendorStatusCheckMD(vendor: Vendor): string { return `OpenAI [status](https://status.openai.com) and [downdetector](https://downdetector.com/status/openai).`; case "google": return `Google [status](https://status.cloud.google.com) and [downdetector](https://downdetector.com/status/google-cloud).`; + case "ollama": + return `No status information for Ollama available – you have to check with the particular backend for the model.`; default: unreachable(vendor); } @@ -266,8 +270,10 @@ const LLM_COST: { [name in LanguageModel]: Cost } = { }, } as const; -export function isValidModel(model?: Model) { - return model != null && LLM_COST[model ?? ""] != null; +export function isValidModel(model?: string): boolean { + if (model == null) return false; + if (model.startsWith("ollama-")) return true; + return LLM_COST[model ?? ""] != null; } export function getMaxTokens(model?: Model): number { diff --git a/src/packages/util/db-schema/site-defaults.ts b/src/packages/util/db-schema/site-defaults.ts index 57a196bd73..b976ef9464 100644 --- a/src/packages/util/db-schema/site-defaults.ts +++ b/src/packages/util/db-schema/site-defaults.ts @@ -26,6 +26,7 @@ export type SiteSettingsKeys = | "policies" | "openai_enabled" | "google_vertexai_enabled" + | "ollama_enabled" | "neural_search_enabled" | "jupyter_api_enabled" | "organization_name" @@ -595,6 +596,13 @@ export const site_settings_conf: SiteSettings = { valid: only_booleans, to_val: to_bool, }, + ollama_enabled: { + name: "Ollama LLM UI", + desc: "Controls visibility of UI elements related to Ollama integration. To make this actually work, configure the list of API/model endpoints in the Ollama configuration.", + default: "no", + valid: only_booleans, + to_val: to_bool, + }, neural_search_enabled: { name: "OpenAI Neural Search UI", desc: "Controls visibility of UI elements related to Neural Search integration. You must **also set your OpenAI API key** below and fully configure the **Qdrant vector database** for neural search to work.", diff --git a/src/packages/util/db-schema/site-settings-extras.ts b/src/packages/util/db-schema/site-settings-extras.ts index 692c0942c1..b338ae5507 100644 --- a/src/packages/util/db-schema/site-settings-extras.ts +++ b/src/packages/util/db-schema/site-settings-extras.ts @@ -67,8 +67,9 @@ const pii_retention_display = (retention: string) => { const openai_enabled = (conf: SiteSettings) => to_bool(conf.openai_enabled); const vertexai_enabled = (conf: SiteSettings) => to_bool(conf.google_vertexai_enabled); +const ollama_enabled = (conf: SiteSettings) => to_bool(conf.ollama_enabled); const any_llm_enabled = (conf: SiteSettings) => - openai_enabled(conf) || vertexai_enabled(conf); + openai_enabled(conf) || vertexai_enabled(conf) || ollama_enabled(conf); const compute_servers_enabled = (conf: SiteSettings) => to_bool(conf.compute_servers_enabled); @@ -104,6 +105,7 @@ export type SiteSettingsExtrasKeys = | "openai_section" | "openai_api_key" | "google_vertexai_key" + | "ollama_configuration" | "qdrant_section" | "qdrant_api_key" | "qdrant_cluster_url" @@ -180,6 +182,15 @@ export const EXTRAS: SettingsExtras = { password: true, show: vertexai_enabled, }, + ollama_configuration: { + name: "Ollama Configuration", + desc: "This is the configuration for the Ollama LLM API endpoints.", + default: "", + multiline: 5, + show: ollama_enabled, + to_val: from_json, + valid: parsableJson, + }, qdrant_section: { name: "Qdrant Configuration", desc: "",