LibreChat/api/server/services/Endpoints/assistant/initializeClient.js
Danny Avila 2f92b54787
🔗 feat: User Provided Base URL for OpenAI endpoints (#1919)
* chore: bump browserslist-db@latest

* refactor(EndpointService): simplify with `generateConfig`, utilize optional baseURL for OpenAI-based endpoints, use `isUserProvided` helper fn wherever needed

* refactor(custom/initializeClient): use standardized naming for common variables

* feat: user provided baseURL for openAI-based endpoints

* refactor(custom/initializeClient): re-order operations

* fix: knownendpoints enum definition and add FetchTokenConfig, bump data-provider

* refactor(custom): use tokenKey dependent on userProvided conditions for caching and fetching endpointTokenConfig, anticipate token rates from custom config

* refactor(custom): assure endpointTokenConfig is only accessed from cache if qualifies for fetching

* fix(ci): update tests for initializeClient based on userProvideURL changes

* fix(EndpointService): correct baseURL env var for assistants: `ASSISTANTS_BASE_URL`

* fix: unnecessary run cancellation on res.close() when response.run is completed

* feat(assistants): user provided URL option

* ci: update tests and add test for `assistants` endpoint

* chore: leaner condition for request closing

* chore: more descriptive error message to provide keys again
2024-02-28 14:27:19 -05:00

90 lines
2.3 KiB
JavaScript

const OpenAI = require('openai');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { EModelEndpoint } = require('librechat-data-provider');
const {
getUserKey,
getUserKeyExpiry,
checkUserKeyExpiry,
} = require('~/server/services/UserService');
const OpenAIClient = require('~/app/clients/OpenAIClient');
const { isUserProvided } = require('~/server/utils');
const initializeClient = async ({ req, res, endpointOption, initAppClient = false }) => {
const { PROXY, OPENAI_ORGANIZATION, ASSISTANTS_API_KEY, ASSISTANTS_BASE_URL } = process.env;
const userProvidesKey = isUserProvided(ASSISTANTS_API_KEY);
const userProvidesURL = isUserProvided(ASSISTANTS_BASE_URL);
let userValues = null;
if (userProvidesKey || userProvidesURL) {
const expiresAt = await getUserKeyExpiry({
userId: req.user.id,
name: EModelEndpoint.assistants,
});
checkUserKeyExpiry(
expiresAt,
'Your Assistants API key has expired. Please provide your API key again.',
);
userValues = await getUserKey({ userId: req.user.id, name: EModelEndpoint.assistants });
try {
userValues = JSON.parse(userValues);
} catch (e) {
throw new Error(
'Invalid JSON provided for Assistants API user values. Please provide them again.',
);
}
}
let apiKey = userProvidesKey ? userValues.apiKey : ASSISTANTS_API_KEY;
let baseURL = userProvidesURL ? userValues.baseURL : ASSISTANTS_BASE_URL;
if (!apiKey) {
throw new Error('Assistants API key not provided. Please provide it again.');
}
const opts = {};
if (baseURL) {
opts.baseURL = baseURL;
}
if (PROXY) {
opts.httpAgent = new HttpsProxyAgent(PROXY);
}
if (OPENAI_ORGANIZATION) {
opts.organization = OPENAI_ORGANIZATION;
}
/** @type {OpenAIClient} */
const openai = new OpenAI({
apiKey,
...opts,
});
openai.req = req;
openai.res = res;
if (endpointOption && initAppClient) {
const clientOptions = {
reverseProxyUrl: baseURL,
proxy: PROXY ?? null,
req,
res,
...endpointOption,
};
const client = new OpenAIClient(apiKey, clientOptions);
return {
client,
openai,
openAIApiKey: apiKey,
};
}
return {
openai,
openAIApiKey: apiKey,
};
};
module.exports = initializeClient;