| | const OpenAI = require('openai'); |
| | const { ProxyAgent } = require('undici'); |
| | const { constructAzureURL, isUserProvided, resolveHeaders } = require('@librechat/api'); |
| | const { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } = require('librechat-data-provider'); |
| | const { |
| | checkUserKeyExpiry, |
| | getUserKeyValues, |
| | getUserKeyExpiry, |
| | } = require('~/server/services/UserService'); |
| | const OAIClient = require('~/app/clients/OpenAIClient'); |
| |
|
| | class Files { |
| | constructor(client) { |
| | this._client = client; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | create(assistantId, body, options) { |
| | return this._client.post(`/assistants/${assistantId}/files`, { |
| | body, |
| | ...options, |
| | headers: { 'OpenAI-Beta': 'assistants=v1', ...options?.headers }, |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | retrieve(assistantId, fileId, options) { |
| | return this._client.get(`/assistants/${assistantId}/files/${fileId}`, { |
| | ...options, |
| | headers: { 'OpenAI-Beta': 'assistants=v1', ...options?.headers }, |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | del(assistantId, fileId, options) { |
| | return this._client.delete(`/assistants/${assistantId}/files/${fileId}`, { |
| | ...options, |
| | headers: { 'OpenAI-Beta': 'assistants=v1', ...options?.headers }, |
| | }); |
| | } |
| | } |
| |
|
| | const initializeClient = async ({ req, res, version, endpointOption, initAppClient = false }) => { |
| | const appConfig = req.config; |
| | const { PROXY, OPENAI_ORGANIZATION, AZURE_ASSISTANTS_API_KEY, AZURE_ASSISTANTS_BASE_URL } = |
| | process.env; |
| |
|
| | const userProvidesKey = isUserProvided(AZURE_ASSISTANTS_API_KEY); |
| | const userProvidesURL = isUserProvided(AZURE_ASSISTANTS_BASE_URL); |
| |
|
| | let userValues = null; |
| | if (userProvidesKey || userProvidesURL) { |
| | const expiresAt = await getUserKeyExpiry({ |
| | userId: req.user.id, |
| | name: EModelEndpoint.azureAssistants, |
| | }); |
| | checkUserKeyExpiry(expiresAt, EModelEndpoint.azureAssistants); |
| | userValues = await getUserKeyValues({ |
| | userId: req.user.id, |
| | name: EModelEndpoint.azureAssistants, |
| | }); |
| | } |
| |
|
| | let apiKey = userProvidesKey ? userValues.apiKey : AZURE_ASSISTANTS_API_KEY; |
| | let baseURL = userProvidesURL ? userValues.baseURL : AZURE_ASSISTANTS_BASE_URL; |
| |
|
| | const opts = {}; |
| |
|
| | const clientOptions = { |
| | reverseProxyUrl: baseURL ?? null, |
| | proxy: PROXY ?? null, |
| | req, |
| | res, |
| | ...endpointOption, |
| | }; |
| |
|
| | |
| | const azureConfig = appConfig.endpoints?.[EModelEndpoint.azureOpenAI]; |
| |
|
| | |
| | let azureOptions; |
| |
|
| | if (azureConfig && azureConfig.assistants) { |
| | const { modelGroupMap, groupMap, assistantModels } = azureConfig; |
| | const modelName = req.body.model ?? req.query.model ?? assistantModels[0]; |
| | const { |
| | azureOptions: currentOptions, |
| | baseURL: azureBaseURL, |
| | headers = {}, |
| | serverless, |
| | } = mapModelToAzureConfig({ |
| | modelName, |
| | modelGroupMap, |
| | groupMap, |
| | }); |
| |
|
| | azureOptions = currentOptions; |
| |
|
| | baseURL = constructAzureURL({ |
| | baseURL: azureBaseURL ?? 'https://${INSTANCE_NAME}.openai.azure.com/openai', |
| | azureOptions, |
| | }); |
| |
|
| | apiKey = azureOptions.azureOpenAIApiKey; |
| | opts.defaultQuery = { 'api-version': azureOptions.azureOpenAIApiVersion }; |
| | opts.defaultHeaders = resolveHeaders({ |
| | headers: { |
| | ...headers, |
| | 'api-key': apiKey, |
| | 'OpenAI-Beta': `assistants=${version}`, |
| | }, |
| | user: req.user, |
| | }); |
| | opts.model = azureOptions.azureOpenAIApiDeploymentName; |
| |
|
| | if (initAppClient) { |
| | clientOptions.titleConvo = azureConfig.titleConvo; |
| | clientOptions.titleModel = azureConfig.titleModel; |
| | clientOptions.titleMethod = azureConfig.titleMethod ?? 'completion'; |
| |
|
| | const groupName = modelGroupMap[modelName].group; |
| | clientOptions.addParams = azureConfig.groupMap[groupName].addParams; |
| | clientOptions.dropParams = azureConfig.groupMap[groupName].dropParams; |
| | clientOptions.forcePrompt = azureConfig.groupMap[groupName].forcePrompt; |
| |
|
| | clientOptions.reverseProxyUrl = baseURL ?? clientOptions.reverseProxyUrl; |
| | clientOptions.headers = opts.defaultHeaders; |
| | clientOptions.azure = !serverless && azureOptions; |
| | if (serverless === true) { |
| | clientOptions.defaultQuery = azureOptions.azureOpenAIApiVersion |
| | ? { 'api-version': azureOptions.azureOpenAIApiVersion } |
| | : undefined; |
| | clientOptions.headers['api-key'] = apiKey; |
| | } |
| | } |
| | } |
| |
|
| | if (userProvidesKey & !apiKey) { |
| | throw new Error( |
| | JSON.stringify({ |
| | type: ErrorTypes.NO_USER_KEY, |
| | }), |
| | ); |
| | } |
| |
|
| | if (!apiKey) { |
| | throw new Error('Assistants API key not provided. Please provide it again.'); |
| | } |
| |
|
| | if (baseURL) { |
| | opts.baseURL = baseURL; |
| | } |
| |
|
| | if (PROXY) { |
| | const proxyAgent = new ProxyAgent(PROXY); |
| | opts.fetchOptions = { |
| | dispatcher: proxyAgent, |
| | }; |
| | } |
| |
|
| | if (OPENAI_ORGANIZATION) { |
| | opts.organization = OPENAI_ORGANIZATION; |
| | } |
| |
|
| | |
| | const openai = new OpenAI({ |
| | apiKey, |
| | ...opts, |
| | }); |
| |
|
| | openai.beta.assistants.files = new Files(openai); |
| |
|
| | openai.req = req; |
| | openai.res = res; |
| |
|
| | if (azureOptions) { |
| | openai.locals = { ...(openai.locals ?? {}), azureOptions }; |
| | } |
| |
|
| | if (endpointOption && initAppClient) { |
| | const client = new OAIClient(apiKey, clientOptions); |
| | return { |
| | client, |
| | openai, |
| | openAIApiKey: apiKey, |
| | }; |
| | } |
| |
|
| | return { |
| | openai, |
| | openAIApiKey: apiKey, |
| | }; |
| | }; |
| |
|
| | module.exports = initializeClient; |
| |
|