diff --git a/src/app/api/config/route.ts b/src/app/api/config/route.ts index 39c1f84..c1e5bbd 100644 --- a/src/app/api/config/route.ts +++ b/src/app/api/config/route.ts @@ -8,6 +8,7 @@ import { getOllamaApiEndpoint, getOpenaiApiKey, getDeepseekApiKey, + getLMStudioApiEndpoint, updateConfig, } from '@/lib/config'; import { @@ -51,6 +52,7 @@ export const GET = async (req: Request) => { config['openaiApiKey'] = getOpenaiApiKey(); config['ollamaApiUrl'] = getOllamaApiEndpoint(); + config['lmStudioApiUrl'] = getLMStudioApiEndpoint(); config['anthropicApiKey'] = getAnthropicApiKey(); config['groqApiKey'] = getGroqApiKey(); config['geminiApiKey'] = getGeminiApiKey(); @@ -93,6 +95,9 @@ export const POST = async (req: Request) => { DEEPSEEK: { API_KEY: config.deepseekApiKey, }, + LM_STUDIO: { + API_URL: config.lmStudioApiUrl, + }, CUSTOM_OPENAI: { API_URL: config.customOpenaiApiUrl, API_KEY: config.customOpenaiApiKey, diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 919304b..0385944 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -21,6 +21,7 @@ interface SettingsType { anthropicApiKey: string; geminiApiKey: string; ollamaApiUrl: string; + lmStudioApiUrl: string; deepseekApiKey: string; customOpenaiApiKey: string; customOpenaiApiUrl: string; @@ -548,8 +549,10 @@ const Page = () => { options={Object.keys(config.chatModelProviders).map( (provider) => ({ value: provider, - label: (PROVIDER_METADATA as any)[provider]?.displayName || - provider.charAt(0).toUpperCase() + provider.slice(1), + label: + (PROVIDER_METADATA as any)[provider]?.displayName || + provider.charAt(0).toUpperCase() + + provider.slice(1), }), )} /> @@ -689,8 +692,10 @@ const Page = () => { options={Object.keys(config.embeddingModelProviders).map( (provider) => ({ value: provider, - label: (PROVIDER_METADATA as any)[provider]?.displayName || - provider.charAt(0).toUpperCase() + provider.slice(1), + label: + (PROVIDER_METADATA as any)[provider]?.displayName || + provider.charAt(0).toUpperCase() + + provider.slice(1), }), )} /> diff --git a/src/lib/config.ts b/src/lib/config.ts index e3f2680..78ad09c 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -60,7 +60,7 @@ const loadConfig = () => { fs.readFileSync(path.join(process.cwd(), `${configFileName}`), 'utf-8'), ) as any as Config; } - + // Client-side fallback - settings will be loaded via API return {} as Config; }; @@ -94,7 +94,8 @@ export const getCustomOpenaiApiUrl = () => export const getCustomOpenaiModelName = () => loadConfig().MODELS.CUSTOM_OPENAI.MODEL_NAME; -export const getLMStudioApiEndpoint = () => loadConfig().MODELS.LM_STUDIO.API_URL; +export const getLMStudioApiEndpoint = () => + loadConfig().MODELS.LM_STUDIO.API_URL; const mergeConfigs = (current: any, update: any): any => { if (update === null || update === undefined) { diff --git a/src/lib/providers/anthropic.ts b/src/lib/providers/anthropic.ts index e434b32..2b0f2cc 100644 --- a/src/lib/providers/anthropic.ts +++ b/src/lib/providers/anthropic.ts @@ -4,7 +4,7 @@ import { getAnthropicApiKey } from '../config'; export const PROVIDER_INFO = { key: 'anthropic', - displayName: 'Anthropic' + displayName: 'Anthropic', }; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; diff --git a/src/lib/providers/deepseek.ts b/src/lib/providers/deepseek.ts index b272801..46f2398 100644 --- a/src/lib/providers/deepseek.ts +++ b/src/lib/providers/deepseek.ts @@ -5,7 +5,7 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models'; export const PROVIDER_INFO = { key: 'deepseek', - displayName: 'Deepseek AI' + displayName: 'Deepseek AI', }; const deepseekChatModels: Record[] = [ diff --git a/src/lib/providers/gemini.ts b/src/lib/providers/gemini.ts index 6af9fb2..6cf2243 100644 --- a/src/lib/providers/gemini.ts +++ b/src/lib/providers/gemini.ts @@ -7,7 +7,7 @@ import { ChatModel, EmbeddingModel } from '.'; export const PROVIDER_INFO = { key: 'gemini', - displayName: 'Google Gemini' + displayName: 'Google Gemini', }; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { Embeddings } from '@langchain/core/embeddings'; diff --git a/src/lib/providers/groq.ts b/src/lib/providers/groq.ts index 62481d4..4b0ca92 100644 --- a/src/lib/providers/groq.ts +++ b/src/lib/providers/groq.ts @@ -4,7 +4,7 @@ import { ChatModel } from '.'; export const PROVIDER_INFO = { key: 'groq', - displayName: 'Groq' + displayName: 'Groq', }; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; diff --git a/src/lib/providers/index.ts b/src/lib/providers/index.ts index 073bd61..e536431 100644 --- a/src/lib/providers/index.ts +++ b/src/lib/providers/index.ts @@ -1,19 +1,45 @@ import { Embeddings } from '@langchain/core/embeddings'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; -import { loadOpenAIChatModels, loadOpenAIEmbeddingModels, PROVIDER_INFO as OpenAIInfo, PROVIDER_INFO } from './openai'; +import { + loadOpenAIChatModels, + loadOpenAIEmbeddingModels, + PROVIDER_INFO as OpenAIInfo, + PROVIDER_INFO, +} from './openai'; import { getCustomOpenaiApiKey, getCustomOpenaiApiUrl, getCustomOpenaiModelName, } from '../config'; import { ChatOpenAI } from '@langchain/openai'; -import { loadOllamaChatModels, loadOllamaEmbeddingModels, PROVIDER_INFO as OllamaInfo } from './ollama'; +import { + loadOllamaChatModels, + loadOllamaEmbeddingModels, + PROVIDER_INFO as OllamaInfo, +} from './ollama'; import { loadGroqChatModels, PROVIDER_INFO as GroqInfo } from './groq'; -import { loadAnthropicChatModels, PROVIDER_INFO as AnthropicInfo } from './anthropic'; -import { loadGeminiChatModels, loadGeminiEmbeddingModels, PROVIDER_INFO as GeminiInfo } from './gemini'; -import { loadTransformersEmbeddingsModels, PROVIDER_INFO as TransformersInfo } from './transformers'; -import { loadDeepseekChatModels, PROVIDER_INFO as DeepseekInfo } from './deepseek'; -import { loadLMStudioChatModels, loadLMStudioEmbeddingsModels, PROVIDER_INFO as LMStudioInfo } from './lmstudio'; +import { + loadAnthropicChatModels, + PROVIDER_INFO as AnthropicInfo, +} from './anthropic'; +import { + loadGeminiChatModels, + loadGeminiEmbeddingModels, + PROVIDER_INFO as GeminiInfo, +} from './gemini'; +import { + loadTransformersEmbeddingsModels, + PROVIDER_INFO as TransformersInfo, +} from './transformers'; +import { + loadDeepseekChatModels, + PROVIDER_INFO as DeepseekInfo, +} from './deepseek'; +import { + loadLMStudioChatModels, + loadLMStudioEmbeddingsModels, + PROVIDER_INFO as LMStudioInfo, +} from './lmstudio'; export const PROVIDER_METADATA = { openai: OpenAIInfo, @@ -26,8 +52,8 @@ export const PROVIDER_METADATA = { lmstudio: LMStudioInfo, custom_openai: { key: 'custom_openai', - displayName: 'Custom OpenAI' - } + displayName: 'Custom OpenAI', + }, }; export interface ChatModel { diff --git a/src/lib/providers/lmstudio.ts b/src/lib/providers/lmstudio.ts index f7be638..811208f 100644 --- a/src/lib/providers/lmstudio.ts +++ b/src/lib/providers/lmstudio.ts @@ -4,7 +4,7 @@ import { ChatModel, EmbeddingModel } from '.'; export const PROVIDER_INFO = { key: 'lmstudio', - displayName: 'LM Studio' + displayName: 'LM Studio', }; import { ChatOpenAI } from '@langchain/openai'; import { OpenAIEmbeddings } from '@langchain/openai'; @@ -16,14 +16,12 @@ interface LMStudioModel { name?: string; } -const ensureV1Endpoint = (endpoint: string): string => +const ensureV1Endpoint = (endpoint: string): string => endpoint.endsWith('/v1') ? endpoint : `${endpoint}/v1`; const checkServerAvailability = async (endpoint: string): Promise => { try { - const keepAlive = getKeepAlive(); await axios.get(`${ensureV1Endpoint(endpoint)}/models`, { - timeout: parseInt(keepAlive) * 1000 || 5000, headers: { 'Content-Type': 'application/json' }, }); return true; @@ -34,14 +32,12 @@ const checkServerAvailability = async (endpoint: string): Promise => { export const loadLMStudioChatModels = async () => { const endpoint = getLMStudioApiEndpoint(); - const keepAlive = getKeepAlive(); - + if (!endpoint) return {}; - if (!await checkServerAvailability(endpoint)) return {}; + if (!(await checkServerAvailability(endpoint))) return {}; try { const response = await axios.get(`${ensureV1Endpoint(endpoint)}/models`, { - timeout: parseInt(keepAlive) * 1000 || 5000, headers: { 'Content-Type': 'application/json' }, }); @@ -58,7 +54,7 @@ export const loadLMStudioChatModels = async () => { modelName: model.id, temperature: 0.7, streaming: true, - maxRetries: 3 + maxRetries: 3, }) as unknown as BaseChatModel, }; }); @@ -72,14 +68,12 @@ export const loadLMStudioChatModels = async () => { export const loadLMStudioEmbeddingsModels = async () => { const endpoint = getLMStudioApiEndpoint(); - const keepAlive = getKeepAlive(); - + if (!endpoint) return {}; - if (!await checkServerAvailability(endpoint)) return {}; + if (!(await checkServerAvailability(endpoint))) return {}; try { const response = await axios.get(`${ensureV1Endpoint(endpoint)}/models`, { - timeout: parseInt(keepAlive) * 1000 || 5000, headers: { 'Content-Type': 'application/json' }, }); diff --git a/src/lib/providers/ollama.ts b/src/lib/providers/ollama.ts index beab58f..cca2142 100644 --- a/src/lib/providers/ollama.ts +++ b/src/lib/providers/ollama.ts @@ -4,7 +4,7 @@ import { ChatModel, EmbeddingModel } from '.'; export const PROVIDER_INFO = { key: 'ollama', - displayName: 'Ollama' + displayName: 'Ollama', }; import { ChatOllama } from '@langchain/community/chat_models/ollama'; import { OllamaEmbeddings } from '@langchain/community/embeddings/ollama'; diff --git a/src/lib/providers/openai.ts b/src/lib/providers/openai.ts index 36f7e29..61621c3 100644 --- a/src/lib/providers/openai.ts +++ b/src/lib/providers/openai.ts @@ -4,7 +4,7 @@ import { ChatModel, EmbeddingModel } from '.'; export const PROVIDER_INFO = { key: 'openai', - displayName: 'OpenAI' + displayName: 'OpenAI', }; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { Embeddings } from '@langchain/core/embeddings'; diff --git a/src/lib/providers/transformers.ts b/src/lib/providers/transformers.ts index fd7cb9e..3098d9f 100644 --- a/src/lib/providers/transformers.ts +++ b/src/lib/providers/transformers.ts @@ -2,7 +2,7 @@ import { HuggingFaceTransformersEmbeddings } from '../huggingfaceTransformer'; export const PROVIDER_INFO = { key: 'transformers', - displayName: 'Hugging Face' + displayName: 'Hugging Face', }; export const loadTransformersEmbeddingsModels = async () => {