🔗 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
This commit is contained in:
Danny Avila 2024-02-28 14:27:19 -05:00 committed by GitHub
parent 53ae2d7bfb
commit 2f92b54787
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 762 additions and 226 deletions

View file

@ -7,12 +7,42 @@ const {
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 = {};
const baseURL = ASSISTANTS_BASE_URL ?? null;
if (baseURL) {
opts.baseURL = baseURL;
@ -26,29 +56,6 @@ const initializeClient = async ({ req, res, endpointOption, initAppClient = fals
opts.organization = OPENAI_ORGANIZATION;
}
const credentials = ASSISTANTS_API_KEY;
const isUserProvided = credentials === 'user_provided';
let userKey = null;
if (isUserProvided) {
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.',
);
userKey = await getUserKey({ userId: req.user.id, name: EModelEndpoint.assistants });
}
let apiKey = isUserProvided ? userKey : credentials;
if (!apiKey) {
throw new Error(`${EModelEndpoint.assistants} API key not provided.`);
}
/** @type {OpenAIClient} */
const openai = new OpenAI({
apiKey,