diff --git a/README.md b/README.md index d1388b0..884fad6 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker. - `OPENAI`: Your OpenAI API key. **You only need to fill this if you wish to use OpenAI's models**. - `OLLAMA`: Your Ollama API URL. You should enter it as `http://host.docker.internal:PORT_NUMBER`. If you installed Ollama on port 11434, use `http://host.docker.internal:11434`. For other ports, adjust accordingly. **You need to fill this if you wish to use Ollama's models instead of OpenAI's**. - - `GROQ`: Your Groq API key. **You only need to fill this if you wish to use Groq's hosted models** + - `GROQ`: Your Groq API key. **You only need to fill this if you wish to use Groq's hosted models**. + - `ANTHROPIC`: Your Anthropic API key. **You only need to fill this if you wish to use Anthropic models**. **Note**: You can change these after starting Perplexica from the settings dialog. diff --git a/package.json b/package.json index bc2f6ff..572675f 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@iarna/toml": "^2.2.5", + "@langchain/anthropic": "^0.2.3", "@langchain/community": "^0.2.16", "@langchain/openai": "^0.0.25", "@xenova/transformers": "^2.17.1", diff --git a/sample.config.toml b/sample.config.toml index 8d35666..f6c6943 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -5,6 +5,7 @@ SIMILARITY_MEASURE = "cosine" # "cosine" or "dot" [API_KEYS] OPENAI = "" # OpenAI API key - sk-1234567890abcdef1234567890abcdef GROQ = "" # Groq API key - gsk_1234567890abcdef1234567890abcdef +ANTHROPIC = "" # Anthropic API key - sk-ant-1234567890abcdef1234567890abcdef [API_ENDPOINTS] SEARXNG = "http://localhost:32768" # SearxNG API URL diff --git a/src/config.ts b/src/config.ts index 2dfff77..28c84f7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,6 +12,7 @@ interface Config { API_KEYS: { OPENAI: string; GROQ: string; + ANTHROPIC: string; }; API_ENDPOINTS: { SEARXNG: string; @@ -38,6 +39,8 @@ export const getOpenaiApiKey = () => loadConfig().API_KEYS.OPENAI; export const getGroqApiKey = () => loadConfig().API_KEYS.GROQ; +export const getAnthropicApiKey = () => loadConfig().API_KEYS.ANTHROPIC; + export const getSearxngApiEndpoint = () => loadConfig().API_ENDPOINTS.SEARXNG; export const getOllamaApiEndpoint = () => loadConfig().API_ENDPOINTS.OLLAMA; diff --git a/src/lib/providers/anthropic.ts b/src/lib/providers/anthropic.ts new file mode 100644 index 0000000..58cd164 --- /dev/null +++ b/src/lib/providers/anthropic.ts @@ -0,0 +1,39 @@ +import { ChatAnthropic } from '@langchain/anthropic'; +import { getAnthropicApiKey } from '../../config'; +import logger from '../../utils/logger'; + +export const loadAnthropicChatModels = async () => { + const anthropicApiKey = getAnthropicApiKey(); + + if (!anthropicApiKey) return {}; + + try { + const chatModels = { + 'Claude 3.5 Sonnet': new ChatAnthropic({ + temperature: 0.7, + anthropicApiKey: anthropicApiKey, + model: 'claude-3-5-sonnet-20240620', + }), + 'Claude 3 Opus': new ChatAnthropic({ + temperature: 0.7, + anthropicApiKey: anthropicApiKey, + model: 'claude-3-opus-20240229', + }), + 'Claude 3 Sonnet': new ChatAnthropic({ + temperature: 0.7, + anthropicApiKey: anthropicApiKey, + model: 'claude-3-sonnet-20240229', + }), + 'Claude 3 Haiku': new ChatAnthropic({ + temperature: 0.7, + anthropicApiKey: anthropicApiKey, + model: 'claude-3-haiku-20240307', + }), + }; + + return chatModels; + } catch (err) { + logger.error(`Error loading Anthropic models: ${err}`); + return {}; + } +}; diff --git a/src/lib/providers/groq.ts b/src/lib/providers/groq.ts index 35bd125..ac5dc3b 100644 --- a/src/lib/providers/groq.ts +++ b/src/lib/providers/groq.ts @@ -49,6 +49,16 @@ export const loadGroqChatModels = async () => { baseURL: 'https://api.groq.com/openai/v1', }, ), + 'Gemma2 9b': new ChatOpenAI( + { + openAIApiKey: groqApiKey, + modelName: 'gemma2-9b-it', + temperature: 0.7, + }, + { + baseURL: 'https://api.groq.com/openai/v1', + }, + ), }; return chatModels; diff --git a/src/lib/providers/index.ts b/src/lib/providers/index.ts index b1d4502..d919fd4 100644 --- a/src/lib/providers/index.ts +++ b/src/lib/providers/index.ts @@ -1,12 +1,14 @@ import { loadGroqChatModels } from './groq'; import { loadOllamaChatModels, loadOllamaEmbeddingsModels } from './ollama'; import { loadOpenAIChatModels, loadOpenAIEmbeddingsModels } from './openai'; +import { loadAnthropicChatModels } from './anthropic'; import { loadTransformersEmbeddingsModels } from './transformers'; const chatModelProviders = { openai: loadOpenAIChatModels, groq: loadGroqChatModels, ollama: loadOllamaChatModels, + anthropic: loadAnthropicChatModels, }; const embeddingModelProviders = { @@ -21,11 +23,11 @@ export const getAvailableChatModelProviders = async () => { for (const provider in chatModelProviders) { const providerModels = await chatModelProviders[provider](); if (Object.keys(providerModels).length > 0) { - models[provider] = providerModels + models[provider] = providerModels; } } - models['custom_openai'] = {} + models['custom_openai'] = {}; return models; }; @@ -36,7 +38,7 @@ export const getAvailableEmbeddingModelProviders = async () => { for (const provider in embeddingModelProviders) { const providerModels = await embeddingModelProviders[provider](); if (Object.keys(providerModels).length > 0) { - models[provider] = providerModels + models[provider] = providerModels; } } diff --git a/src/routes/config.ts b/src/routes/config.ts index bf13b63..f255560 100644 --- a/src/routes/config.ts +++ b/src/routes/config.ts @@ -6,6 +6,7 @@ import { import { getGroqApiKey, getOllamaApiEndpoint, + getAnthropicApiKey, getOpenaiApiKey, updateConfig, } from '../config'; @@ -37,6 +38,7 @@ router.get('/', async (_, res) => { config['openaiApiKey'] = getOpenaiApiKey(); config['ollamaApiUrl'] = getOllamaApiEndpoint(); + config['anthropicApiKey'] = getAnthropicApiKey(); config['groqApiKey'] = getGroqApiKey(); res.status(200).json(config); @@ -49,6 +51,7 @@ router.post('/', async (req, res) => { API_KEYS: { OPENAI: config.openaiApiKey, GROQ: config.groqApiKey, + ANTHROPIC: config.anthropicApiKey, }, API_ENDPOINTS: { OLLAMA: config.ollamaApiUrl, diff --git a/ui/components/ChatWindow.tsx b/ui/components/ChatWindow.tsx index b1a87a2..f2c89a3 100644 --- a/ui/components/ChatWindow.tsx +++ b/ui/components/ChatWindow.tsx @@ -194,8 +194,10 @@ const useSocket = ( } return () => { - ws?.close(); - console.log('[DEBUG] closed'); + if (ws?.readyState === 1) { + ws?.close(); + console.log('[DEBUG] closed'); + } }; }, [ws, url, setIsWSReady, setError]); diff --git a/ui/components/SettingsDialog.tsx b/ui/components/SettingsDialog.tsx index d6ee18d..788469b 100644 --- a/ui/components/SettingsDialog.tsx +++ b/ui/components/SettingsDialog.tsx @@ -56,6 +56,7 @@ interface SettingsType { }; openaiApiKey: string; groqApiKey: string; + anthropicApiKey: string; ollamaApiUrl: string; } @@ -439,6 +440,22 @@ const SettingsDialog = ({ } /> +
+

+ Anthropic API Key +

+ + setConfig({ + ...config, + anthropicApiKey: e.target.value, + }) + } + /> +
)} {isLoading && ( diff --git a/yarn.lock b/yarn.lock index dceddbd..1a25c1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,20 @@ # yarn lockfile v1 +"@anthropic-ai/sdk@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.22.0.tgz#548e4218d9810fd494e595d4e57cb2d46d301a1a" + integrity sha512-dv4BCC6FZJw3w66WNLsHlUFjhu19fS1L/5jMPApwhZLa/Oy1j0A2i3RypmDtHEPp4Wwg3aZkSHksp7VzYWjzmw== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" + "@anthropic-ai/sdk@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.9.1.tgz#b2d2b7bf05c90dce502c9a2e869066870f69ba88" @@ -307,6 +321,17 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@langchain/anthropic@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@langchain/anthropic/-/anthropic-0.2.3.tgz#1505da939f47c90e53dfede0407c497b8177bdf0" + integrity sha512-f2fqzLGcvsXXUyZ1vl8cgwkKDGLshOGrPuR9hkhGuBG5m91eq755OqPBxWJuS1TFtNU813cXft3xh0MQbxavwg== + dependencies: + "@anthropic-ai/sdk" "^0.22.0" + "@langchain/core" ">=0.2.9 <0.3.0" + fast-xml-parser "^4.3.5" + zod "^3.22.4" + zod-to-json-schema "^3.22.4" + "@langchain/community@^0.2.16": version "0.2.16" resolved "https://registry.yarnpkg.com/@langchain/community/-/community-0.2.16.tgz#5888baf7fc7ea272c5f91aaa0e71bc444167262d" @@ -355,6 +380,24 @@ zod "^3.22.4" zod-to-json-schema "^3.22.3" +"@langchain/core@>=0.2.9 <0.3.0": + version "0.2.15" + resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.2.15.tgz#1bb99ac4fffe935c7ba37edcaa91abfba3c82219" + integrity sha512-L096itIBQ5XNsy5BCCPqIQEk/x4rzI+U4BhYT+fDBYtljESshIi/WzXdmiGfY/6MpVjB76jNuaRgMDmo1m9NeQ== + dependencies: + ansi-styles "^5.0.0" + camelcase "6" + decamelize "1.2.0" + js-tiktoken "^1.0.12" + langsmith "~0.1.30" + ml-distance "^4.0.0" + mustache "^4.2.0" + p-queue "^6.6.2" + p-retry "4" + uuid "^10.0.0" + zod "^3.22.4" + zod-to-json-schema "^3.22.3" + "@langchain/core@~0.1.44", "@langchain/core@~0.1.45": version "0.1.52" resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.1.52.tgz#7619310b83ffa841628efe2e1eda873ca714d068" @@ -1311,6 +1354,13 @@ fast-fifo@^1.1.0, fast-fifo@^1.2.0: resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== +fast-xml-parser@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz#341cc98de71e9ba9e651a67f41f1752d1441a501" + integrity sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg== + dependencies: + strnum "^1.0.5" + fecha@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" @@ -2342,6 +2392,11 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -2488,6 +2543,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + uuid@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -2592,7 +2652,7 @@ zod-to-json-schema@^3.22.3: resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz#3646e81cfc318dbad2a22519e5ce661615418673" integrity sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q== -zod-to-json-schema@^3.22.5: +zod-to-json-schema@^3.22.4, zod-to-json-schema@^3.22.5: version "3.23.1" resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.23.1.tgz#5225925b8ed5fa20096bd99be076c4b29b53d309" integrity sha512-oT9INvydob1XV0v1d2IadrR74rLtDInLvDFfAa1CG0Pmg/vxATk7I2gSelfj271mbzeM4Da0uuDQE/Nkj3DWNw==