const { OpenRouterLLM, fetchOpenRouterModels, } = require("../AiProviders/openRouter"); const { perplexityModels } = require("../AiProviders/perplexity"); const { togetherAiModels } = require("../AiProviders/togetherAi"); const SUPPORT_CUSTOM_MODELS = [ "openai", "localai", "ollama", "native-llm", "togetherai", "mistral", "perplexity", "openrouter", "lmstudio", ]; async function getCustomModels(provider = "", apiKey = null, basePath = null) { if (!SUPPORT_CUSTOM_MODELS.includes(provider)) return { models: [], error: "Invalid provider for custom models" }; switch (provider) { case "openai": return await openAiModels(apiKey); case "localai": return await localAIModels(basePath, apiKey); case "ollama": return await ollamaAIModels(basePath); case "togetherai": return await getTogetherAiModels(); case "mistral": return await getMistralModels(apiKey); case "native-llm": return nativeLLMModels(); case "perplexity": return await getPerplexityModels(); case "openrouter": return await getOpenRouterModels(); case "lmstudio": return await getLMStudioModels(basePath); default: return { models: [], error: "Invalid provider for custom models" }; } } async function openAiModels(apiKey = null) { const { OpenAI: OpenAIApi } = require("openai"); const openai = new OpenAIApi({ apiKey: apiKey || process.env.OPEN_AI_KEY, }); const allModels = await openai.models .list() .then((results) => results.data) .catch((e) => { console.error(`OpenAI:listModels`, e.message); return [ { name: "gpt-3.5-turbo", id: "gpt-3.5-turbo", object: "model", created: 1677610602, owned_by: "openai", organization: "OpenAi", }, { name: "gpt-4", id: "gpt-4", object: "model", created: 1687882411, owned_by: "openai", organization: "OpenAi", }, { name: "gpt-4-turbo", id: "gpt-4-turbo", object: "model", created: 1712361441, owned_by: "system", organization: "OpenAi", }, { name: "gpt-4-32k", id: "gpt-4-32k", object: "model", created: 1687979321, owned_by: "openai", organization: "OpenAi", }, { name: "gpt-3.5-turbo-16k", id: "gpt-3.5-turbo-16k", object: "model", created: 1683758102, owned_by: "openai-internal", organization: "OpenAi", }, ]; }); const gpts = allModels .filter((model) => model.id.startsWith("gpt")) .filter( (model) => !model.id.includes("vision") && !model.id.includes("instruct") ) .map((model) => { return { ...model, name: model.id, organization: "OpenAi", }; }); const customModels = allModels .filter( (model) => !model.owned_by.includes("openai") && model.owned_by !== "system" ) .map((model) => { return { ...model, name: model.id, organization: "Your Fine-Tunes", }; }); // Api Key was successful so lets save it for future uses if ((gpts.length > 0 || customModels.length > 0) && !!apiKey) process.env.OPEN_AI_KEY = apiKey; return { models: [...gpts, ...customModels], error: null }; } async function localAIModels(basePath = null, apiKey = null) { const { OpenAI: OpenAIApi } = require("openai"); const openai = new OpenAIApi({ baseURL: basePath || process.env.LOCAL_AI_BASE_PATH, apiKey: apiKey || process.env.LOCAL_AI_API_KEY || null, }); const models = await openai.models .list() .then((results) => results.data) .catch((e) => { console.error(`LocalAI:listModels`, e.message); return []; }); // Api Key was successful so lets save it for future uses if (models.length > 0 && !!apiKey) process.env.LOCAL_AI_API_KEY = apiKey; return { models, error: null }; } async function getLMStudioModels(basePath = null) { try { const { OpenAI: OpenAIApi } = require("openai"); const openai = new OpenAIApi({ baseURL: basePath || process.env.LMSTUDIO_BASE_PATH, apiKey: null, }); const models = await openai.models .list() .then((results) => results.data) .catch((e) => { console.error(`LMStudio:listModels`, e.message); return []; }); return { models, error: null }; } catch (e) { console.error(`LMStudio:getLMStudioModels`, e.message); return { models: [], error: "Could not fetch LMStudio Models" }; } } async function ollamaAIModels(basePath = null) { let url; try { let urlPath = basePath ?? process.env.OLLAMA_BASE_PATH; new URL(urlPath); if (urlPath.split("").slice(-1)?.[0] === "/") throw new Error("BasePath Cannot end in /!"); url = urlPath; } catch { return { models: [], error: "Not a valid URL." }; } const models = await fetch(`${url}/api/tags`) .then((res) => { if (!res.ok) throw new Error(`Could not reach Ollama server! ${res.status}`); return res.json(); }) .then((data) => data?.models || []) .then((models) => models.map((model) => { return { id: model.name }; }) ) .catch((e) => { console.error(e); return []; }); return { models, error: null }; } async function getTogetherAiModels() { const knownModels = togetherAiModels(); if (!Object.keys(knownModels).length === 0) return { models: [], error: null }; const models = Object.values(knownModels).map((model) => { return { id: model.id, organization: model.organization, name: model.name, }; }); return { models, error: null }; } async function getPerplexityModels() { const knownModels = perplexityModels(); if (!Object.keys(knownModels).length === 0) return { models: [], error: null }; const models = Object.values(knownModels).map((model) => { return { id: model.id, name: model.name, }; }); return { models, error: null }; } async function getOpenRouterModels() { const knownModels = await fetchOpenRouterModels(); if (!Object.keys(knownModels).length === 0) return { models: [], error: null }; const models = Object.values(knownModels).map((model) => { return { id: model.id, organization: model.organization, name: model.name, }; }); return { models, error: null }; } async function getMistralModels(apiKey = null) { const { OpenAI: OpenAIApi } = require("openai"); const openai = new OpenAIApi({ apiKey: apiKey || process.env.MISTRAL_API_KEY || null, baseURL: "https://api.mistral.ai/v1", }); const models = await openai.models .list() .then((results) => results.data.filter((model) => !model.id.includes("embed")) ) .catch((e) => { console.error(`Mistral:listModels`, e.message); return []; }); // Api Key was successful so lets save it for future uses if (models.length > 0 && !!apiKey) process.env.MISTRAL_API_KEY = apiKey; return { models, error: null }; } function nativeLLMModels() { const fs = require("fs"); const path = require("path"); const storageDir = path.resolve( process.env.STORAGE_DIR ? path.resolve(process.env.STORAGE_DIR, "models", "downloaded") : path.resolve(__dirname, `../../storage/models/downloaded`) ); if (!fs.existsSync(storageDir)) return { models: [], error: "No model/downloaded storage folder found." }; const files = fs .readdirSync(storageDir) .filter((file) => file.toLowerCase().includes(".gguf")) .map((file) => { return { id: file, name: file }; }); return { models: files, error: null }; } module.exports = { getCustomModels, };