Add Groq Implementation (#441)

Co-authored-by: Ray Song <raysong@rayx.local>
This commit is contained in:
Ray Song 2024-07-21 16:14:43 -07:00 committed by GitHub
parent e6e7a508e5
commit 283ff122c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 204 additions and 27 deletions

149
package-lock.json generated
View file

@ -15,6 +15,7 @@
"@langchain/cohere": "^0.0.2",
"@langchain/community": "^0.0.16",
"@langchain/google-genai": "^0.0.7",
"@langchain/groq": "^0.0.9",
"@tabler/icons-react": "^2.14.0",
"@types/pouchdb": "^6.4.0",
"axios": "^1.3.4",
@ -2249,20 +2250,22 @@
}
},
"node_modules/@langchain/core": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.1.10.tgz",
"integrity": "sha512-vSFPtTkpQ9NT3qqvRh9FN4A16m89npj9KhzZgIh976bseMfI87jS+GK6Rih3qVcB8wsStqp80E5A36ce2egl8Q==",
"version": "0.1.62",
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.1.62.tgz",
"integrity": "sha512-PsBM/x0wxVvVPawKak2MFjxEneogipf212yO+rLf+2M3RDepCpYCdn1NBWgfmC+AWpmBYx/8zM7Y4QW7Kg2Wjw==",
"dependencies": {
"ansi-styles": "^5.0.0",
"camelcase": "6",
"decamelize": "1.2.0",
"js-tiktoken": "^1.0.8",
"langsmith": "~0.0.48",
"langsmith": "~0.1.7",
"ml-distance": "^4.0.0",
"mustache": "^4.2.0",
"p-queue": "^6.6.2",
"p-retry": "4",
"uuid": "^9.0.0",
"zod": "^3.22.3"
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.3"
},
"engines": {
"node": ">=18"
@ -2290,6 +2293,42 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@langchain/core/node_modules/commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"engines": {
"node": ">=14"
}
},
"node_modules/@langchain/core/node_modules/langsmith": {
"version": "0.1.23",
"resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.23.tgz",
"integrity": "sha512-lc6BpC82zpHNDW5qNO/+eQrN9YNK7ElZIU0GIHZrdKTclaqAXYkJB2C3hM2sxdkdp0HbFYOLa0PxxZLzNkMloQ==",
"dependencies": {
"@types/uuid": "^9.0.1",
"commander": "^10.0.1",
"p-queue": "^6.6.2",
"p-retry": "4",
"uuid": "^9.0.0"
},
"peerDependencies": {
"openai": "*"
},
"peerDependenciesMeta": {
"openai": {
"optional": true
}
}
},
"node_modules/@langchain/core/node_modules/zod-to-json-schema": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz",
"integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==",
"peerDependencies": {
"zod": "^3.23.3"
}
},
"node_modules/@langchain/google-genai": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-0.0.7.tgz",
@ -2302,21 +2341,52 @@
"node": ">=18"
}
},
"node_modules/@langchain/openai": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.0.10.tgz",
"integrity": "sha512-74BBDsuLHT+jNlDviHPUemqiG2nm1AF8i9ta0zfkwjE9JtNITL5ZVhoCSczklipx5LzO+6etVuhjdhXcwNOfBA==",
"node_modules/@langchain/groq": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/@langchain/groq/-/groq-0.0.9.tgz",
"integrity": "sha512-/QGGgazYdxlN8FCmPfEVDO9Hg55POvQdnoou+b3lsugmwP1TYPRtqLW6JY7Atb36X4vjEJwiMCnntDXdT7vgaw==",
"dependencies": {
"@langchain/core": "~0.1.9",
"js-tiktoken": "^1.0.7",
"openai": "^4.19.0",
"zod": "^3.22.3",
"zod-to-json-schema": "3.20.3"
"@langchain/core": "~0.1.56",
"@langchain/openai": "~0.0.28",
"groq-sdk": "^0.3.2",
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.5"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@langchain/groq/node_modules/zod-to-json-schema": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz",
"integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==",
"peerDependencies": {
"zod": "^3.23.3"
}
},
"node_modules/@langchain/openai": {
"version": "0.0.28",
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.0.28.tgz",
"integrity": "sha512-2s1RA3/eAnz4ahdzsMPBna9hfAqpFNlWdHiPxVGZ5yrhXsbLWWoPcF+22LCk9t0HJKtazi2GCIWc0HVXH9Abig==",
"dependencies": {
"@langchain/core": "~0.1.56",
"js-tiktoken": "^1.0.7",
"openai": "^4.32.1",
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.3"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@langchain/openai/node_modules/zod-to-json-schema": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz",
"integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==",
"peerDependencies": {
"zod": "^3.23.3"
}
},
"node_modules/@next/env": {
"version": "14.0.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz",
@ -6164,6 +6234,30 @@
"dev": true,
"peer": true
},
"node_modules/groq-sdk": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/groq-sdk/-/groq-sdk-0.3.3.tgz",
"integrity": "sha512-wdOeZ2QymPjjP3tmFpUAnfMisoLbt7xF2MfpROeFAngcqWbfTyB9j9pMWSEAMF/E4gZx8f2Y+5zswO0q92CSxA==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"digest-fetch": "^1.3.0",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7",
"web-streams-polyfill": "^3.2.1"
}
},
"node_modules/groq-sdk/node_modules/@types/node": {
"version": "18.19.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz",
"integrity": "sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -9713,6 +9807,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/mustache": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
"bin": {
"mustache": "bin/mustache"
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@ -10085,15 +10187,14 @@
"integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ=="
},
"node_modules/openai": {
"version": "4.24.1",
"resolved": "https://registry.npmjs.org/openai/-/openai-4.24.1.tgz",
"integrity": "sha512-ezm/O3eiZMnyBqirUnWm9N6INJU1WhNtz+nK/Zj/2oyKvRz9pgpViDxa5wYOtyGYXPn1sIKBV0I/S4BDhtydqw==",
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/openai/-/openai-4.43.0.tgz",
"integrity": "sha512-4SMUB/XiqnO5IrEcdzEGGTcHoeXq7D/k82v36zoqSitrMUjenZXGH5JysIH7aF7Wr+gjvq0dT2mV6wLVKA7Seg==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"digest-fetch": "^1.3.0",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7",
@ -10104,9 +10205,9 @@
}
},
"node_modules/openai/node_modules/@types/node": {
"version": "18.19.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz",
"integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==",
"version": "18.19.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz",
"integrity": "sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==",
"dependencies": {
"undici-types": "~5.26.4"
}
@ -12500,9 +12601,9 @@
}
},
"node_modules/zod": {
"version": "3.22.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}

View file

@ -44,6 +44,7 @@
"@langchain/cohere": "^0.0.2",
"@langchain/community": "^0.0.16",
"@langchain/google-genai": "^0.0.7",
"@langchain/groq": "^0.0.9",
"@tabler/icons-react": "^2.14.0",
"@types/pouchdb": "^6.4.0",
"axios": "^1.3.4",

View file

@ -9,6 +9,7 @@ import {
OPENAI_MODELS,
OPENROUTERAI_MODELS,
PROXY_SERVER_PORT,
GROQ_MODELS,
} from '@/constants';
import EncryptionService from '@/encryptionService';
import { ProxyChatOpenAI } from '@/langchainWrappers';
@ -18,6 +19,7 @@ import { ChatOllama } from "@langchain/community/chat_models/ollama";
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { BaseChatModel } from 'langchain/chat_models/base';
import { ChatOpenAI } from 'langchain/chat_models/openai';
import { ChatGroq } from "@langchain/groq";
import { Notice } from 'obsidian';
export default class ChatModelManager {
@ -100,6 +102,10 @@ export default class ChatModelManager {
...(params.ollamaBaseUrl ? { baseUrl: params.ollamaBaseUrl } : {}),
modelName: params.ollamaModel,
},
[ModelProviders.GROQ]: {
apiKey: decrypt(params.groqApiKey),
modelName: params.groqModel,
},
};
return { ...baseConfig, ...(providerConfig[chatModelProvider as keyof typeof providerConfig] || {}) };
@ -156,6 +162,12 @@ export default class ChatModelManager {
constructor: ProxyChatOpenAI,
vendor: ModelProviders.LM_STUDIO,
},
{
models: GROQ_MODELS,
apiKey: this.langChainParams.groqApiKey,
constructor: ChatGroq,
vendor: ModelProviders.GROQ,
},
];
modelConfigurations.forEach(({ models, apiKey, constructor, vendor }) => {
@ -175,7 +187,7 @@ export default class ChatModelManager {
setChatModel(modelDisplayName: string): void {
if (!ChatModelManager.modelMap.hasOwnProperty(modelDisplayName)) {
throw new Error(`No model found for: ${modelDisplayName}`);
throw new Error(`No model found for: ${modelDisplayName}`);
}
// MUST update it since chatModelManager is a singleton.
this.langChainParams.model = getModelName(modelDisplayName);
@ -190,12 +202,11 @@ export default class ChatModelManager {
}
const modelConfig = this.getModelConfig(selectedModel.vendor);
new Notice(`Setting model: ${modelDisplayName}`);
try {
const newModelInstance = new selectedModel.AIConstructor({
...modelConfig,
});
// Set the new model
ChatModelManager.chatModel = newModelInstance;
} catch (error) {

View file

@ -25,6 +25,8 @@ export interface ModelConfig {
baseUrl?: string;
openRouterModel?: string;
lmStudioBaseUrl?: string;
groqApiKey?: string;
groqModel?: string;
}
export interface LangChainParams {
@ -58,6 +60,8 @@ export interface LangChainParams {
openAIProxyModelName?: string;
openAIEmbeddingProxyBaseUrl?: string;
openAIEmbeddingProxyModelName?: string;
groqApiKey: string;
groqModel: string;
}
export interface SetChainOptions {

View file

@ -195,6 +195,9 @@ const ChatIcons: React.FC<ChatIconsProps> = ({
<option value={ChatModelDisplayNames.OLLAMA}>
{ChatModelDisplayNames.OLLAMA}
</option>
<option value={ChatModelDisplayNames.GROQ}>
{ChatModelDisplayNames.GROQ}
</option>
</select>
<span className="tooltip-text">Model Selection</span>
</div>

View file

@ -15,6 +15,7 @@ export enum ChatModels {
GPT_4_32K = "gpt-4-32k",
GEMINI_PRO = "gemini-pro",
OLLAMA = "ollama",
Groq = "llama3-70b-8192",
}
export enum ChatModelDisplayNames {
@ -30,6 +31,7 @@ export enum ChatModelDisplayNames {
OPENROUTERAI = "OPENROUTER.AI",
OLLAMA = "OLLAMA (LOCAL)",
LM_STUDIO = "LM STUDIO (LOCAL)",
GROQ = "Groq",
}
export const OPENAI_MODELS = new Set([
@ -67,6 +69,8 @@ export const DISPLAY_NAME_TO_MODEL: Record<string, string> = {
[ChatModelDisplayNames.GEMINI_PRO]: ChatModels.GEMINI_PRO,
};
export const GROQ_MODELS = new Set([ChatModelDisplayNames.GROQ]);
// Model Providers
export enum ModelProviders {
OPENAI = "openai",
@ -78,6 +82,7 @@ export enum ModelProviders {
OPENROUTERAI = "openrouterai",
LM_STUDIO = "lm_studio",
OLLAMA = "ollama",
GROQ = "groq",
}
export const VENDOR_MODELS: Record<string, Set<string>> = {
@ -88,6 +93,7 @@ export const VENDOR_MODELS: Record<string, Set<string>> = {
[ModelProviders.OPENROUTERAI]: OPENROUTERAI_MODELS,
[ModelProviders.OLLAMA]: OLLAMA_MODELS,
[ModelProviders.LM_STUDIO]: LM_STUDIO_MODELS,
[ModelProviders.GROQ]: GROQ_MODELS,
};
export const EMBEDDING_PROVIDERS = [
@ -174,4 +180,6 @@ export const DEFAULT_SETTINGS: CopilotSettings = {
debug: false,
enableEncryption: false,
maxSourceChunks: 3,
groqModel: "llama3-70b-8192",
groqApiKey: "",
};

View file

@ -749,6 +749,8 @@ export default class CopilotPlugin extends Plugin {
ollamaModel,
ollamaBaseUrl,
lmStudioBaseUrl,
groqApiKey,
groqModel,
} = sanitizeSettings(this.settings);
return {
openAIApiKey,
@ -757,6 +759,8 @@ export default class CopilotPlugin extends Plugin {
cohereApiKey,
anthropicApiKey,
anthropicModel: anthropicModel || DEFAULT_SETTINGS.anthropicModel,
groqApiKey,
groqModel,
azureOpenAIApiKey,
azureOpenAIApiInstanceName,
azureOpenAIApiDeploymentName,

View file

@ -42,6 +42,8 @@ export interface CopilotSettings {
enableEncryption: boolean;
maxSourceChunks: number;
qaExclusionPaths: string;
groqModel: string;
groqApiKey: string;
}
export class CopilotSettingTab extends PluginSettingTab {

View file

@ -28,6 +28,10 @@ interface ApiSettingsProps {
setAzureOpenAIApiVersion: (value: string) => void;
azureOpenAIApiEmbeddingDeploymentName: string;
setAzureOpenAIApiEmbeddingDeploymentName: (value: string) => void;
groqApiKey: string;
setGroqApiKey: (value: string) => void;
groqModel: string;
setGroqModel: (value: string) => void;
}
const ApiSettings: React.FC<ApiSettingsProps> = ({
@ -55,6 +59,10 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
setAzureOpenAIApiVersion,
azureOpenAIApiEmbeddingDeploymentName,
setAzureOpenAIApiEmbeddingDeploymentName,
groqApiKey,
setGroqApiKey,
groqModel,
setGroqModel,
}) => {
return (
<div>
@ -214,6 +222,32 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
/>
</div>
</Collapsible>
<Collapsible title="Groq API Settings">
<div>
<ApiSetting
title="Groq API Key"
value={groqApiKey}
setValue={setGroqApiKey}
placeholder="Enter Groq API Key"
/>
<ApiSetting
title="Groq Model"
value={groqModel}
setValue={setGroqModel}
placeholder="Enter Groq Model"
type="text"
/>
<p>
If you have Groq API access, you can get the API key {' '}
<a href="https://console.groq.com/keys" target="_blank" rel="noopener noreferrer">
here
</a>.
<br />
Your API key is stored locally and is only used to make requests to Groq's services.
</p>
</div>
</Collapsible>
</div>
);
};

View file

@ -37,6 +37,9 @@ export default function SettingsMain({ plugin, reloadPlugin }: SettingsMainProps
const [azureOpenAIApiVersion, setAzureOpenAIApiVersion] = useState(plugin.settings.azureOpenAIApiVersion);
const [azureOpenAIApiEmbeddingDeploymentName, setAzureOpenAIApiEmbeddingDeploymentName] = useState(plugin.settings.azureOpenAIApiEmbeddingDeploymentName);
const [groqApiKey, setGroqApiKey] = useState(plugin.settings.groqApiKey);
const [groqModel, setGroqModel] = useState(plugin.settings.groqModel);
// QA settings
const [embeddingModel, setEmbeddingModel] = useState(plugin.settings.embeddingModel);
const [cohereApiKey, setCohereApiKey] = useState(plugin.settings.cohereApiKey);
@ -78,6 +81,8 @@ export default function SettingsMain({ plugin, reloadPlugin }: SettingsMainProps
plugin.settings.azureOpenAIApiDeploymentName = azureOpenAIApiDeploymentName;
plugin.settings.azureOpenAIApiVersion = azureOpenAIApiVersion;
plugin.settings.azureOpenAIApiEmbeddingDeploymentName = azureOpenAIApiEmbeddingDeploymentName;
plugin.settings.groqApiKey = groqApiKey;
plugin.settings.groqModel = groqModel;
// QA settings
plugin.settings.embeddingModel = embeddingModel;
@ -207,6 +212,10 @@ export default function SettingsMain({ plugin, reloadPlugin }: SettingsMainProps
setAzureOpenAIApiVersion={setAzureOpenAIApiVersion}
azureOpenAIApiEmbeddingDeploymentName={azureOpenAIApiEmbeddingDeploymentName}
setAzureOpenAIApiEmbeddingDeploymentName={setAzureOpenAIApiEmbeddingDeploymentName}
groqApiKey={groqApiKey}
setGroqApiKey={setGroqApiKey}
groqModel={groqModel}
setGroqModel={setGroqModel}
/>
<QASettings
embeddingModel={embeddingModel}