diff --git a/api/app/clients/OpenAIClient.js b/api/app/clients/OpenAIClient.js index c7c973e482..115cb26432 100644 --- a/api/app/clients/OpenAIClient.js +++ b/api/app/clients/OpenAIClient.js @@ -145,10 +145,6 @@ class OpenAIClient extends BaseClient { if (reverseProxy) { this.completionsUrl = reverseProxy; this.langchainProxy = extractBaseURL(reverseProxy); - !this.langchainProxy && - console.warn(`The reverse proxy URL ${reverseProxy} is not valid for Plugins. -The url must follow OpenAI specs, for example: https://localhost:8080/v1/chat/completions -If your reverse proxy is compatible to OpenAI specs in every other way, it may still work without plugins enabled.`); } else if (isChatGptModel) { this.completionsUrl = 'https://api.openai.com/v1/chat/completions'; } else { diff --git a/api/app/clients/PluginsClient.js b/api/app/clients/PluginsClient.js index 801219c842..585cf05742 100644 --- a/api/app/clients/PluginsClient.js +++ b/api/app/clients/PluginsClient.js @@ -36,10 +36,6 @@ class PluginsClient extends OpenAIClient { if (this.options.reverseProxyUrl) { this.langchainProxy = extractBaseURL(this.options.reverseProxyUrl); - !this.langchainProxy && - console.warn(`The reverse proxy URL ${this.options.reverseProxyUrl} is not valid for Plugins. -The url must follow OpenAI specs, for example: https://localhost:8080/v1/chat/completions -If your reverse proxy is compatible to OpenAI specs in every other way, it may still work without plugins enabled.`); } } diff --git a/api/app/clients/specs/OpenAIClient.test.js b/api/app/clients/specs/OpenAIClient.test.js index ff7ab2f6de..3fbf75f574 100644 --- a/api/app/clients/specs/OpenAIClient.test.js +++ b/api/app/clients/specs/OpenAIClient.test.js @@ -94,7 +94,7 @@ describe('OpenAIClient', () => { client.setOptions({ reverseProxyUrl: 'https://example.com/completions' }); expect(client.completionsUrl).toBe('https://example.com/completions'); - expect(client.langchainProxy).toBe(null); + expect(client.langchainProxy).toBe('https://example.com/completions'); }); }); diff --git a/api/server/services/ModelService.js b/api/server/services/ModelService.js index 4dbc780693..7a2917832a 100644 --- a/api/server/services/ModelService.js +++ b/api/server/services/ModelService.js @@ -1,5 +1,6 @@ -const Keyv = require('keyv'); +const HttpsProxyAgent = require('https-proxy-agent'); const axios = require('axios'); +const Keyv = require('keyv'); const { isEnabled } = require('../utils'); const { extractBaseURL } = require('../../utils'); const keyvRedis = require('../../cache/keyvRedis'); @@ -10,7 +11,7 @@ const modelsCache = isEnabled(process.env.USE_REDIS) ? new Keyv({ store: keyvRedis }) : new Keyv({ namespace: 'models' }); -const { OPENROUTER_API_KEY, OPENAI_REVERSE_PROXY, CHATGPT_MODELS, ANTHROPIC_MODELS } = +const { OPENROUTER_API_KEY, OPENAI_REVERSE_PROXY, CHATGPT_MODELS, ANTHROPIC_MODELS, PROXY } = process.env ?? {}; const fetchOpenAIModels = async (opts = { azure: false, plugins: false }, _models = []) => { @@ -39,13 +40,18 @@ const fetchOpenAIModels = async (opts = { azure: false, plugins: false }, _model return cachedModels; } - if (basePath?.includes('v1') || opts.azure) { + if (basePath || opts.azure) { try { - const res = await axios.get(`${basePath}${opts.azure ? '' : '/models'}`, { + const payload = { headers: { Authorization: `Bearer ${apiKey}`, }, - }); + }; + + if (PROXY) { + payload.httpsAgent = new HttpsProxyAgent(PROXY); + } + const res = await axios.get(`${basePath}${opts.azure ? '' : '/models'}`, payload); models = res.data.data.map((item) => item.id); // console.log(`Fetched ${models.length} models from ${opts.azure ? 'Azure ' : ''}OpenAI API`); diff --git a/api/utils/extractBaseURL.js b/api/utils/extractBaseURL.js index 83565a4caf..cc95f4481d 100644 --- a/api/utils/extractBaseURL.js +++ b/api/utils/extractBaseURL.js @@ -1,6 +1,7 @@ /** * Extracts a valid OpenAI baseURL from a given string, matching "url/v1," also an added suffix, * ending with "/openai" (to allow the Cloudflare, LiteLLM pattern). + * Returns the original URL if no match is found. * * Examples: * - `https://open.ai/v1/chat` -> `https://open.ai/v1` @@ -9,12 +10,11 @@ * - `https://open.ai/v1/hi/openai` -> `https://open.ai/v1/hi/openai` * * @param {string} url - The URL to be processed. - * @returns {string|null} The matched pattern or null if no match is found. + * @returns {string} The matched pattern or input if no match is found. */ function extractBaseURL(url) { - // First, let's make sure the URL contains '/v1'. if (!url.includes('/v1')) { - return null; + return url; } // Find the index of '/v1' to use it as a reference point. diff --git a/api/utils/extractBaseURL.spec.js b/api/utils/extractBaseURL.spec.js index 1403ac9968..299b9c1397 100644 --- a/api/utils/extractBaseURL.spec.js +++ b/api/utils/extractBaseURL.spec.js @@ -28,9 +28,9 @@ describe('extractBaseURL', () => { ); }); - test('should return null if the URL does not match the expected pattern', () => { + test('should return input if the URL does not match the expected pattern', () => { const url = 'https://someotherdomain.com/notv1'; - expect(extractBaseURL(url)).toBeNull(); + expect(extractBaseURL(url)).toBe(url); }); // Test our JSDoc examples.