diff --git a/package.json b/package.json index db3d773..f10d018 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "dependencies": { "@iarna/toml": "^2.2.5", "@langchain/anthropic": "^0.2.3", + "@langchain/azure-openai": "^0.0.4", "@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 f6c6943..3bbb2a0 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -6,7 +6,21 @@ SIMILARITY_MEASURE = "cosine" # "cosine" or "dot" OPENAI = "" # OpenAI API key - sk-1234567890abcdef1234567890abcdef GROQ = "" # Groq API key - gsk_1234567890abcdef1234567890abcdef ANTHROPIC = "" # Anthropic API key - sk-ant-1234567890abcdef1234567890abcdef +AZURE = "" # Azure OpenAI API key [API_ENDPOINTS] SEARXNG = "http://localhost:32768" # SearxNG API URL -OLLAMA = "" # Ollama API URL - http://host.docker.internal:11434 \ No newline at end of file +OLLAMA = "" # Ollama API URL - http://host.docker.internal:11434 +AZURE = "" # Azure OpenAI Endpoint URL - https://endpointhere.openai.azure.com/ + +[AZURE_OPENAI] +DEPLOYMENT_NAME_GPT35_TURBO = "gpt-35-turbo" # Deployment name for GPT-3.5 turbo +DEPLOYMENT_NAME_GPT35_TURBO_16K = "gpt-35-turbo-16k" # Deployment name for GPT-3.5-turbo 16k +DEPLOYMENT_NAME_GPT35_TURBO_INSTRUCT = "gpt-35-turbo-instruct" # Deployment name for GPT-3.5 turbo instruct +DEPLOYMENT_NAME_GPT4 = "gpt4" # Deployment name for GPT-4 +DEPLOYMENT_NAME_GPT4_32K = "gpt432k" # Deployment name for GPT-4 32K +DEPLOYMENT_NAME_GPT4_OMNI = "gpt-4o" # Deployment name for GPT-4 omni +DEPLOYMENT_NAME_GPT4_OMNI_MINI = "gpt-4o-mini" # Deployment name for GPT-4 omni mini +DEPLOYMENT_NAME_EMBEDDINGS_ADA = "text-embeddings-ada-002" # Deployment name for text embeddings ada 002 +DEPLOYMENT_NAME_EMBEDDINGS_SMALL = "text-embedding-3-small" # Deployment name for text embedding 3 small +DEPLOYMENT_NAME_EMBEDDINGS_LARGE = "text-embedding-3-large" # Deployment name for text embedding 3 large \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 9ebc182..e608051 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,10 +13,24 @@ interface Config { OPENAI: string; GROQ: string; ANTHROPIC: string; + AZURE: string; }; API_ENDPOINTS: { SEARXNG: string; OLLAMA: string; + AZURE: string; + }; + AZURE_OPENAI: { + DEPLOYMENT_NAME_GPT35_TURBO: string; + DEPLOYMENT_NAME_GPT35_TURBO_16K: string; + DEPLOYMENT_NAME_GPT35_TURBO_INSTRUCT: string; + DEPLOYMENT_NAME_GPT4: string; + DEPLOYMENT_NAME_GPT4_32K: string; + DEPLOYMENT_NAME_GPT4_OMNI: string; + DEPLOYMENT_NAME_GPT4_OMNI_MINI: string; + DEPLOYMENT_NAME_EMBEDDINGS_ADA: string; + DEPLOYMENT_NAME_EMBEDDINGS_SMALL: string; + DEPLOYMENT_NAME_EMBEDDINGS_LARGE: string; }; } @@ -44,6 +58,40 @@ export const getSearxngApiEndpoint = () => loadConfig().API_ENDPOINTS.SEARXNG; export const getOllamaApiEndpoint = () => loadConfig().API_ENDPOINTS.OLLAMA; +export const getAzureOpenaiApiKey = () => loadConfig().API_KEYS.AZURE; + +export const getAzureOpenaiEndpoint = () => loadConfig().API_ENDPOINTS.AZURE; + +export const getAzureOpenaiDeploymentNameGpt35 = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT35_TURBO; + +export const getAzureOpenaiDeploymentNameGpt35_16K = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT35_TURBO_16K; + +export const getAzureOpenaiDeploymentNameGpt35TurboInstruct = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT35_TURBO_INSTRUCT; + +export const getAzureOpenaiDeploymentNameGpt4 = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT4; + +export const getAzureOpenaiDeploymentNameGpt4_32K = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT4_32K; + +export const getAzureOpenaiDeploymentNameGpt4o = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT4_OMNI; + +export const getAzureOpenaiDeploymentNameGpt4oMini = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_GPT4_OMNI_MINI; + +export const getAzureOpenaiDeploymentNameEmbeddingsAda = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_EMBEDDINGS_ADA; + +export const getAzureOpenaiDeploymentNameEmbeddingsSmall = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_EMBEDDINGS_SMALL; + +export const getAzureOpenaiDeploymentNameEmbeddingsLarge = () => + loadConfig().AZURE_OPENAI.DEPLOYMENT_NAME_EMBEDDINGS_LARGE; + export const updateConfig = (config: RecursivePartial) => { const currentConfig = loadConfig(); diff --git a/src/lib/providers/azure.ts b/src/lib/providers/azure.ts new file mode 100644 index 0000000..711ad56 --- /dev/null +++ b/src/lib/providers/azure.ts @@ -0,0 +1,113 @@ +import { + AzureChatOpenAI, + AzureOpenAIEmbeddings, +} from '@langchain/azure-openai'; +import { getAzureOpenaiApiKey, getAzureOpenaiEndpoint } from '../../config'; +import { + getAzureOpenaiDeploymentNameGpt35, + getAzureOpenaiDeploymentNameGpt35_16K, + getAzureOpenaiDeploymentNameGpt35TurboInstruct, + getAzureOpenaiDeploymentNameGpt4, + getAzureOpenaiDeploymentNameGpt4_32K, + getAzureOpenaiDeploymentNameGpt4o, + getAzureOpenaiDeploymentNameGpt4oMini, + getAzureOpenaiDeploymentNameEmbeddingsAda, + getAzureOpenaiDeploymentNameEmbeddingsSmall, + getAzureOpenaiDeploymentNameEmbeddingsLarge, +} from '../../config'; +import logger from '../../utils/logger'; + +export const loadAzureOpenAIChatModels = async () => { + const azureApiKey = getAzureOpenaiApiKey(); + const azureEndpoint = getAzureOpenaiEndpoint(); + + if (!azureApiKey || !azureEndpoint) { + logger.error('Azure OpenAI API key or endpoint is missing'); + return {}; + } + + const chatModels = {}; + + try { + const deploymentNames = { + 'GPT-3.5 turbo': getAzureOpenaiDeploymentNameGpt35(), + 'GPT-3.5 turbo 16K': getAzureOpenaiDeploymentNameGpt35_16K(), + 'GPT-3.5 turbo instruct': + getAzureOpenaiDeploymentNameGpt35TurboInstruct(), + 'GPT-4': getAzureOpenaiDeploymentNameGpt4(), + 'GPT-4 32K': getAzureOpenaiDeploymentNameGpt4_32K(), + 'GPT-4 omni': getAzureOpenaiDeploymentNameGpt4o(), + 'GPT-4 omni mini': getAzureOpenaiDeploymentNameGpt4oMini(), + }; + + let atLeastOneModelLoaded = false; + + for (const [modelName, deploymentName] of Object.entries(deploymentNames)) { + try { + if (deploymentName) { + chatModels[modelName] = new AzureChatOpenAI({ + azureOpenAIEndpoint: azureEndpoint, + azureOpenAIApiKey: azureApiKey, + azureOpenAIApiDeploymentName: deploymentName, + temperature: 0.7, + }); + atLeastOneModelLoaded = true; + } + } catch (error) { + logger.warn( + `Deployment for ${modelName} is missing or failed to load:`, + error, + ); + // Continue the loop even if a specific model fails + } + } + + // Check if at least one model is loaded, log error if not + if (!atLeastOneModelLoaded) { + logger.error( + 'No chat models for Azure OpenAI could be loaded. At least one model is required.', + ); + return {}; + } + + return chatModels; + } catch (error) { + logger.error('Failed to load Azure OpenAI chat models', error); + return {}; + } +}; + +export const loadAzureOpenAIEmbeddings = async () => { + const azureApiKey = getAzureOpenaiApiKey(); + const azureEndpoint = getAzureOpenaiEndpoint(); + + if (!azureApiKey || !azureEndpoint) return {}; + + try { + const embeddings = { + 'Text embedding Ada 002': new AzureOpenAIEmbeddings({ + azureOpenAIEndpoint: azureEndpoint, + azureOpenAIApiKey: azureApiKey, + azureOpenAIApiDeploymentName: + getAzureOpenaiDeploymentNameEmbeddingsAda(), + }), + 'Text embedding 3 small': new AzureOpenAIEmbeddings({ + azureOpenAIEndpoint: azureEndpoint, + azureOpenAIApiKey: azureApiKey, + azureOpenAIApiDeploymentName: + getAzureOpenaiDeploymentNameEmbeddingsSmall(), + }), + 'Text embedding 3 large': new AzureOpenAIEmbeddings({ + azureOpenAIEndpoint: azureEndpoint, + azureOpenAIApiKey: azureApiKey, + azureOpenAIApiDeploymentName: + getAzureOpenaiDeploymentNameEmbeddingsLarge(), + }), + }; + + return embeddings; + } catch (error) { + logger.error('Failed to load Azure OpenAI embeddings', error); + return {}; + } +}; diff --git a/src/lib/providers/index.ts b/src/lib/providers/index.ts index d919fd4..4c44673 100644 --- a/src/lib/providers/index.ts +++ b/src/lib/providers/index.ts @@ -1,11 +1,13 @@ import { loadGroqChatModels } from './groq'; import { loadOllamaChatModels, loadOllamaEmbeddingsModels } from './ollama'; import { loadOpenAIChatModels, loadOpenAIEmbeddingsModels } from './openai'; +import { loadAzureOpenAIChatModels, loadAzureOpenAIEmbeddings } from './azure'; import { loadAnthropicChatModels } from './anthropic'; import { loadTransformersEmbeddingsModels } from './transformers'; const chatModelProviders = { openai: loadOpenAIChatModels, + azure: loadAzureOpenAIChatModels, groq: loadGroqChatModels, ollama: loadOllamaChatModels, anthropic: loadAnthropicChatModels, @@ -13,6 +15,7 @@ const chatModelProviders = { const embeddingModelProviders = { openai: loadOpenAIEmbeddingsModels, + azure: loadAzureOpenAIEmbeddings, local: loadTransformersEmbeddingsModels, ollama: loadOllamaEmbeddingsModels, };