1 line
15 KiB
JSON
1 line
15 KiB
JSON
{"repo": "2236914/studio-360", "files": {"backend/services/llmClient.js": {"7463fb613d2a78c913cc7c1a75e87ecb81350e53": {"t": 1785746706.1797972, "n": 3474, "h": "785062c12b4e9a03", "c": "/**\n * Minimal LLM client shim to keep AI routes functional without a real LLM.\n * If LLM_API_KEY is not provided, chatComplete returns a concise fallback.\n */\n\nfunction getConfig() {\n return {\n apiKey: process.env.LLM_API_KEY || '',\n provider: process.env.LLM_PROVIDER || 'openai',\n baseUrl: process.env.LLM_BASE_URL || '',\n };\n}\n\n/**\n * Trivial chat completion stub. Replace with real provider integration when ready.\n * @param {{system?: string, messages: Array<{role: string, content: string}>, temperature?: number, maxTokens?: number}} opts\n * @returns {Promise<string>}\n */\nasync function chatComplete(opts = {}) {\n const cfg = getConfig();\n const userMsg = Array.isArray(opts.messages)\n ? opts.messages.filter(m => m && m.role === 'user').slice(-1)[0]?.content || ''\n : '';\n\n if (!cfg.apiKey) {\n return 'LLM is not configured on the server. You can still upload files in Upload Process, and I\\'ll help with categorization and posting to your books.';\n }\n\n // Placeholder echo-style response to avoid external dependency\n const trimmed = String(userMsg).trim();\n if (!trimmed) return 'How can I help with your bookkeeping today?';\n return `I read: \"${trimmed.slice(0, 240)}\". (LLM integration placeholder)`;\n}\n\nmodule.exports = { getConfig, chatComplete };\n\n/**\n * Minimal OpenAI-compatible LLM client using native fetch (Node >= 18)\n * Supports providers that expose an OpenAI-compatible Chat Completions API.\n * Configure via env:\n * LLM_API_KEY - required to enable fallback\n * LLM_MODEL - e.g., 'gpt-4o-mini', 'gpt-3.5-turbo', 'deepseek-chat', etc.\n * LLM_BASE_URL - override base URL (default https://api.openai.com/v1)\n * LLM_PROVIDER - optional label (openai, openrouter, groq, together, deepseek)\n */\n\nconst BASES = {\n openai: 'https://api.openai.com/v1',\n openrouter: 'https://openrouter.ai/api/v1',\n groq: 'https://api.groq.com/openai/v1',\n together: 'https://api.together.xyz/v1',\n deepseek: 'https://api.deepseek.com/v1',\n};\n\nfunction getConfig() {\n const apiKey = process.env.LLM_API_KEY;\n const model = process.env.LLM_MODEL || 'gpt-3.5-turbo';\n const provider = (process.env.LLM_PROVIDER || 'openai').toLowerCase();\n const baseUrl = process.env.LLM_BASE_URL || BASES[provider] || BASES.openai;\n return { apiKey, model, baseUrl, provider };\n}\n\nasync function chatComplete({ messages, temperature = 0.2, maxTokens = 512, system }) {\n const { apiKey, model, baseUrl, provider } = getConfig();\n if (!apiKey) throw new Error('LLM_API_KEY not set');\n\n const body = {\n model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n ...(messages || []),\n ],\n temperature,\n max_tokens: maxTokens,\n stream: false,\n };\n\n const headers = {\n 'content-type': 'application/json',\n 'authorization': `Bearer ${apiKey}`,\n };\n // OpenRouter recommends Referer + Title but they are optional; keep minimal.\n const url = `${baseUrl.replace(/\\/$/, '')}/chat/completions`;\n\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });\n const text = await res.text();\n if (!res.ok) throw new Error(`LLM error ${res.status}: ${text.slice(0, 300)}`);\n let data; try { data = JSON.parse(text); } catch { data = null; }\n const content = data?.choices?.[0]?.message?.content || '';\n if (!content) throw new Error('LLM returned empty content');\n return content;\n}\n\nmodule.exports = {\n chatComplete,\n getConfig,\n};\n"}, "d21bbd39f704cd1199b62d9397d54b448db3f6a1": {"t": 1785767120.9756858, "n": 3474, "h": "785062c12b4e9a03", "c": "/**\n * Minimal LLM client shim to keep AI routes functional without a real LLM.\n * If LLM_API_KEY is not provided, chatComplete returns a concise fallback.\n */\n\nfunction getConfig() {\n return {\n apiKey: process.env.LLM_API_KEY || '',\n provider: process.env.LLM_PROVIDER || 'openai',\n baseUrl: process.env.LLM_BASE_URL || '',\n };\n}\n\n/**\n * Trivial chat completion stub. Replace with real provider integration when ready.\n * @param {{system?: string, messages: Array<{role: string, content: string}>, temperature?: number, maxTokens?: number}} opts\n * @returns {Promise<string>}\n */\nasync function chatComplete(opts = {}) {\n const cfg = getConfig();\n const userMsg = Array.isArray(opts.messages)\n ? opts.messages.filter(m => m && m.role === 'user').slice(-1)[0]?.content || ''\n : '';\n\n if (!cfg.apiKey) {\n return 'LLM is not configured on the server. You can still upload files in Upload Process, and I\\'ll help with categorization and posting to your books.';\n }\n\n // Placeholder echo-style response to avoid external dependency\n const trimmed = String(userMsg).trim();\n if (!trimmed) return 'How can I help with your bookkeeping today?';\n return `I read: \"${trimmed.slice(0, 240)}\". (LLM integration placeholder)`;\n}\n\nmodule.exports = { getConfig, chatComplete };\n\n/**\n * Minimal OpenAI-compatible LLM client using native fetch (Node >= 18)\n * Supports providers that expose an OpenAI-compatible Chat Completions API.\n * Configure via env:\n * LLM_API_KEY - required to enable fallback\n * LLM_MODEL - e.g., 'gpt-4o-mini', 'gpt-3.5-turbo', 'deepseek-chat', etc.\n * LLM_BASE_URL - override base URL (default https://api.openai.com/v1)\n * LLM_PROVIDER - optional label (openai, openrouter, groq, together, deepseek)\n */\n\nconst BASES = {\n openai: 'https://api.openai.com/v1',\n openrouter: 'https://openrouter.ai/api/v1',\n groq: 'https://api.groq.com/openai/v1',\n together: 'https://api.together.xyz/v1',\n deepseek: 'https://api.deepseek.com/v1',\n};\n\nfunction getConfig() {\n const apiKey = process.env.LLM_API_KEY;\n const model = process.env.LLM_MODEL || 'gpt-3.5-turbo';\n const provider = (process.env.LLM_PROVIDER || 'openai').toLowerCase();\n const baseUrl = process.env.LLM_BASE_URL || BASES[provider] || BASES.openai;\n return { apiKey, model, baseUrl, provider };\n}\n\nasync function chatComplete({ messages, temperature = 0.2, maxTokens = 512, system }) {\n const { apiKey, model, baseUrl, provider } = getConfig();\n if (!apiKey) throw new Error('LLM_API_KEY not set');\n\n const body = {\n model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n ...(messages || []),\n ],\n temperature,\n max_tokens: maxTokens,\n stream: false,\n };\n\n const headers = {\n 'content-type': 'application/json',\n 'authorization': `Bearer ${apiKey}`,\n };\n // OpenRouter recommends Referer + Title but they are optional; keep minimal.\n const url = `${baseUrl.replace(/\\/$/, '')}/chat/completions`;\n\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });\n const text = await res.text();\n if (!res.ok) throw new Error(`LLM error ${res.status}: ${text.slice(0, 300)}`);\n let data; try { data = JSON.parse(text); } catch { data = null; }\n const content = data?.choices?.[0]?.message?.content || '';\n if (!content) throw new Error('LLM returned empty content');\n return content;\n}\n\nmodule.exports = {\n chatComplete,\n getConfig,\n};\n"}, "390c9a1bfdb7d85f6ded09b69cbf1ee7288370ee": {"t": 1785767122.8869956, "n": 2181, "h": "ace8241d8254b774", "c": "/**\n * Minimal OpenAI-compatible LLM client using native fetch (Node >= 18)\n * Supports providers that expose an OpenAI-compatible Chat Completions API.\n * Configure via env:\n * LLM_API_KEY - required to enable fallback\n * LLM_MODEL - e.g., 'gpt-4o-mini', 'gpt-3.5-turbo', 'deepseek-chat', etc.\n * LLM_BASE_URL - override base URL (default https://api.openai.com/v1)\n * LLM_PROVIDER - optional label (openai, openrouter, groq, together, deepseek)\n */\n\nconst BASES = {\n openai: 'https://api.openai.com/v1',\n openrouter: 'https://openrouter.ai/api/v1',\n groq: 'https://api.groq.com/openai/v1',\n together: 'https://api.together.xyz/v1',\n deepseek: 'https://api.deepseek.com/v1',\n};\n\nfunction getConfig() {\n const apiKey = process.env.LLM_API_KEY;\n const model = process.env.LLM_MODEL || 'gpt-3.5-turbo';\n const provider = (process.env.LLM_PROVIDER || 'openai').toLowerCase();\n const baseUrl = process.env.LLM_BASE_URL || BASES[provider] || BASES.openai;\n return { apiKey, model, baseUrl, provider };\n}\n\nasync function chatComplete({ messages, temperature = 0.2, maxTokens = 512, system }) {\n const { apiKey, model, baseUrl, provider } = getConfig();\n if (!apiKey) throw new Error('LLM_API_KEY not set');\n\n const body = {\n model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n ...(messages || []),\n ],\n temperature,\n max_tokens: maxTokens,\n stream: false,\n };\n\n const headers = {\n 'content-type': 'application/json',\n 'authorization': `Bearer ${apiKey}`,\n };\n // OpenRouter recommends Referer + Title but they are optional; keep minimal.\n const url = `${baseUrl.replace(/\\/$/, '')}/chat/completions`;\n\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });\n const text = await res.text();\n if (!res.ok) throw new Error(`LLM error ${res.status}: ${text.slice(0, 300)}`);\n let data; try { data = JSON.parse(text); } catch { data = null; }\n const content = data?.choices?.[0]?.message?.content || '';\n if (!content) throw new Error('LLM returned empty content');\n return content;\n}\n\nmodule.exports = {\n chatComplete,\n getConfig,\n};\n"}, "e06598808325b68feb5fb30f150ec361a8a6513a": {"t": 1785767124.0403273, "n": 2632, "h": "02a8875076b9af42", "c": "// Minimal LLM client stub\n\nfunction getConfig() {\n return { apiKey: process.env.LLM_API_KEY || '' };\n}\n\nasync function chatComplete({ system, messages, temperature = 0.3, maxTokens = 400 }) {\n // Deterministic stub reply for tests\n const last = (messages || []).slice(-1)[0];\n const content = (last && last.content) ? String(last.content) : '';\n return `Stub LLM reply: ${content.slice(0, 80)}`;\n}\n\nmodule.exports = { getConfig, chatComplete };\n/**\n * Minimal OpenAI-compatible LLM client using native fetch (Node >= 18)\n * Supports providers that expose an OpenAI-compatible Chat Completions API.\n * Configure via env:\n * LLM_API_KEY - required to enable fallback\n * LLM_MODEL - e.g., 'gpt-4o-mini', 'gpt-3.5-turbo', 'deepseek-chat', etc.\n * LLM_BASE_URL - override base URL (default https://api.openai.com/v1)\n * LLM_PROVIDER - optional label (openai, openrouter, groq, together, deepseek)\n */\n\nconst BASES = {\n openai: 'https://api.openai.com/v1',\n openrouter: 'https://openrouter.ai/api/v1',\n groq: 'https://api.groq.com/openai/v1',\n together: 'https://api.together.xyz/v1',\n deepseek: 'https://api.deepseek.com/v1',\n};\n\nfunction getConfig() {\n const apiKey = process.env.LLM_API_KEY;\n const model = process.env.LLM_MODEL || 'gpt-3.5-turbo';\n const provider = (process.env.LLM_PROVIDER || 'openai').toLowerCase();\n const baseUrl = process.env.LLM_BASE_URL || BASES[provider] || BASES.openai;\n return { apiKey, model, baseUrl, provider };\n}\n\nasync function chatComplete({ messages, temperature = 0.2, maxTokens = 512, system }) {\n const { apiKey, model, baseUrl, provider } = getConfig();\n if (!apiKey) throw new Error('LLM_API_KEY not set');\n\n const body = {\n model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n ...(messages || []),\n ],\n temperature,\n max_tokens: maxTokens,\n stream: false,\n };\n\n const headers = {\n 'content-type': 'application/json',\n 'authorization': `Bearer ${apiKey}`,\n };\n // OpenRouter recommends Referer + Title but they are optional; keep minimal.\n const url = `${baseUrl.replace(/\\/$/, '')}/chat/completions`;\n\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });\n const text = await res.text();\n if (!res.ok) throw new Error(`LLM error ${res.status}: ${text.slice(0, 300)}`);\n let data; try { data = JSON.parse(text); } catch { data = null; }\n const content = data?.choices?.[0]?.message?.content || '';\n if (!content) throw new Error('LLM returned empty content');\n return content;\n}\n\nmodule.exports = {\n chatComplete,\n getConfig,\n};\n"}, "fecc8ef859f335bb5c5be3fef9f0c5fcca805c2d": {"t": 1785767125.6225615, "n": 2181, "h": "ace8241d8254b774", "c": "/**\n * Minimal OpenAI-compatible LLM client using native fetch (Node >= 18)\n * Supports providers that expose an OpenAI-compatible Chat Completions API.\n * Configure via env:\n * LLM_API_KEY - required to enable fallback\n * LLM_MODEL - e.g., 'gpt-4o-mini', 'gpt-3.5-turbo', 'deepseek-chat', etc.\n * LLM_BASE_URL - override base URL (default https://api.openai.com/v1)\n * LLM_PROVIDER - optional label (openai, openrouter, groq, together, deepseek)\n */\n\nconst BASES = {\n openai: 'https://api.openai.com/v1',\n openrouter: 'https://openrouter.ai/api/v1',\n groq: 'https://api.groq.com/openai/v1',\n together: 'https://api.together.xyz/v1',\n deepseek: 'https://api.deepseek.com/v1',\n};\n\nfunction getConfig() {\n const apiKey = process.env.LLM_API_KEY;\n const model = process.env.LLM_MODEL || 'gpt-3.5-turbo';\n const provider = (process.env.LLM_PROVIDER || 'openai').toLowerCase();\n const baseUrl = process.env.LLM_BASE_URL || BASES[provider] || BASES.openai;\n return { apiKey, model, baseUrl, provider };\n}\n\nasync function chatComplete({ messages, temperature = 0.2, maxTokens = 512, system }) {\n const { apiKey, model, baseUrl, provider } = getConfig();\n if (!apiKey) throw new Error('LLM_API_KEY not set');\n\n const body = {\n model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n ...(messages || []),\n ],\n temperature,\n max_tokens: maxTokens,\n stream: false,\n };\n\n const headers = {\n 'content-type': 'application/json',\n 'authorization': `Bearer ${apiKey}`,\n };\n // OpenRouter recommends Referer + Title but they are optional; keep minimal.\n const url = `${baseUrl.replace(/\\/$/, '')}/chat/completions`;\n\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });\n const text = await res.text();\n if (!res.ok) throw new Error(`LLM error ${res.status}: ${text.slice(0, 300)}`);\n let data; try { data = JSON.parse(text); } catch { data = null; }\n const content = data?.choices?.[0]?.message?.content || '';\n if (!content) throw new Error('LLM returned empty content');\n return content;\n}\n\nmodule.exports = {\n chatComplete,\n getConfig,\n};\n"}}}} |