| import { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } from 'librechat-data-provider'; |
| import type { |
| InitializeOpenAIOptionsParams, |
| OpenAIConfigOptions, |
| LLMConfigResult, |
| UserKeyValues, |
| } from '~/types'; |
| import { getAzureCredentials } from '~/utils/azure'; |
| import { isUserProvided } from '~/utils/common'; |
| import { resolveHeaders } from '~/utils/env'; |
| import { getOpenAIConfig } from './config'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export const initializeOpenAI = async ({ |
| req, |
| appConfig, |
| overrideModel, |
| endpointOption, |
| overrideEndpoint, |
| getUserKeyValues, |
| checkUserKeyExpiry, |
| }: InitializeOpenAIOptionsParams): Promise<LLMConfigResult> => { |
| const { PROXY, OPENAI_API_KEY, AZURE_API_KEY, OPENAI_REVERSE_PROXY, AZURE_OPENAI_BASEURL } = |
| process.env; |
|
|
| const { key: expiresAt } = req.body; |
| const modelName = overrideModel ?? req.body.model; |
| const endpoint = overrideEndpoint ?? req.body.endpoint; |
|
|
| if (!endpoint) { |
| throw new Error('Endpoint is required'); |
| } |
|
|
| const credentials = { |
| [EModelEndpoint.openAI]: OPENAI_API_KEY, |
| [EModelEndpoint.azureOpenAI]: AZURE_API_KEY, |
| }; |
|
|
| const baseURLOptions = { |
| [EModelEndpoint.openAI]: OPENAI_REVERSE_PROXY, |
| [EModelEndpoint.azureOpenAI]: AZURE_OPENAI_BASEURL, |
| }; |
|
|
| const userProvidesKey = isUserProvided(credentials[endpoint as keyof typeof credentials]); |
| const userProvidesURL = isUserProvided(baseURLOptions[endpoint as keyof typeof baseURLOptions]); |
|
|
| let userValues: UserKeyValues | null = null; |
| if (expiresAt && (userProvidesKey || userProvidesURL)) { |
| checkUserKeyExpiry(expiresAt, endpoint); |
| userValues = await getUserKeyValues({ userId: req.user.id, name: endpoint }); |
| } |
|
|
| let apiKey = userProvidesKey |
| ? userValues?.apiKey |
| : credentials[endpoint as keyof typeof credentials]; |
| const baseURL = userProvidesURL |
| ? userValues?.baseURL |
| : baseURLOptions[endpoint as keyof typeof baseURLOptions]; |
|
|
| const clientOptions: OpenAIConfigOptions = { |
| proxy: PROXY ?? undefined, |
| reverseProxyUrl: baseURL || undefined, |
| streaming: true, |
| }; |
|
|
| const isAzureOpenAI = endpoint === EModelEndpoint.azureOpenAI; |
| const azureConfig = isAzureOpenAI && appConfig.endpoints?.[EModelEndpoint.azureOpenAI]; |
|
|
| if (isAzureOpenAI && azureConfig) { |
| const { modelGroupMap, groupMap } = azureConfig; |
| const { |
| azureOptions, |
| baseURL: configBaseURL, |
| headers = {}, |
| serverless, |
| } = mapModelToAzureConfig({ |
| modelName: modelName || '', |
| modelGroupMap, |
| groupMap, |
| }); |
|
|
| clientOptions.reverseProxyUrl = configBaseURL ?? clientOptions.reverseProxyUrl; |
| clientOptions.headers = resolveHeaders({ |
| headers: { ...headers, ...(clientOptions.headers ?? {}) }, |
| user: req.user, |
| }); |
|
|
| const groupName = modelGroupMap[modelName || '']?.group; |
| if (groupName && groupMap[groupName]) { |
| clientOptions.addParams = groupMap[groupName]?.addParams; |
| clientOptions.dropParams = groupMap[groupName]?.dropParams; |
| } |
|
|
| apiKey = azureOptions.azureOpenAIApiKey; |
| clientOptions.azure = !serverless ? azureOptions : undefined; |
|
|
| if (serverless === true) { |
| clientOptions.defaultQuery = azureOptions.azureOpenAIApiVersion |
| ? { 'api-version': azureOptions.azureOpenAIApiVersion } |
| : undefined; |
|
|
| if (!clientOptions.headers) { |
| clientOptions.headers = {}; |
| } |
| clientOptions.headers['api-key'] = apiKey; |
| } |
| } else if (isAzureOpenAI) { |
| clientOptions.azure = |
| userProvidesKey && userValues?.apiKey ? JSON.parse(userValues.apiKey) : getAzureCredentials(); |
| apiKey = clientOptions.azure ? clientOptions.azure.azureOpenAIApiKey : undefined; |
| } |
|
|
| if (userProvidesKey && !apiKey) { |
| throw new Error( |
| JSON.stringify({ |
| type: ErrorTypes.NO_USER_KEY, |
| }), |
| ); |
| } |
|
|
| if (!apiKey) { |
| throw new Error(`${endpoint} API Key not provided.`); |
| } |
|
|
| const modelOptions = { |
| ...endpointOption.model_parameters, |
| model: modelName, |
| user: req.user.id, |
| }; |
|
|
| const finalClientOptions: OpenAIConfigOptions = { |
| ...clientOptions, |
| modelOptions, |
| }; |
|
|
| const options = getOpenAIConfig(apiKey, finalClientOptions, endpoint); |
|
|
| const openAIConfig = appConfig.endpoints?.[EModelEndpoint.openAI]; |
| const allConfig = appConfig.endpoints?.all; |
| const azureRate = modelName?.includes('gpt-4') ? 30 : 17; |
|
|
| let streamRate: number | undefined; |
|
|
| if (isAzureOpenAI && azureConfig) { |
| streamRate = azureConfig.streamRate ?? azureRate; |
| } else if (!isAzureOpenAI && openAIConfig) { |
| streamRate = openAIConfig.streamRate; |
| } |
|
|
| if (allConfig?.streamRate) { |
| streamRate = allConfig.streamRate; |
| } |
|
|
| if (streamRate) { |
| options.llmConfig._lc_stream_delay = streamRate; |
| } |
|
|
| return options; |
| }; |
|
|