Files
Avtex/app/server/utils/ai.ts
T

139 lines
5.2 KiB
TypeScript

/**
* XFlow AI Utility — OpenRouter & Google Gemini Integration (Updated for May 2026 Models)
*/
const OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1/chat/completions'
/** Доступные модели с описанием для выбора в UI */
export const AI_MODELS = {
/** Сложные инженерные и архитектурные задачи, высокая стабильность */
laguna: 'poolside/laguna-m.1:free',
/** MoE 120B тяжёлая аналитика, архитектурный анализ, сложные рассуждения */
nemotron: 'nvidia/nemotron-3-super-120b-a12b:free',
/** Прямой вызов Gemini 3.5 Flash */
geminiFlash: 'gemini-3.5-flash',
/** Прямой вызов Gemini 3.1 Pro Preview */
geminiPro: 'gemini-3.1-pro-preview',
/** Прямой вызов Gemini 3.1 Flash Lite */
geminiLite: 'gemini-3.1-flash-lite'
} as const
export type AiModelKey = keyof typeof AI_MODELS
/** Дефолтная модель, если не указана (мыслящая Gemini 3.1 Pro) */
const DEFAULT_MODEL: AiModelKey = 'geminiPro'
export const generateAIResponse = async (
prompt: string,
systemPrompt = 'You are a helpful assistant.',
modelKey?: AiModelKey | string,
): Promise<string> => {
// Получаем ключи из окружения
const openRouterKey = process.env.NUXT_OPEN_ROUTER_API_KEY || process.env.OPEN_ROUTER_API_KEY
const geminiKey = process.env.GEMINI_API_KEY || process.env.NUXT_GEMINI_API_KEY || process.env.GOOGLE_API_KEY
// Резолвим модель: принимаем как ключ ('laguna') так и полное имя
const resolvedModel: string =
modelKey && modelKey in AI_MODELS
? AI_MODELS[modelKey as AiModelKey]
: modelKey && (modelKey.includes('/') || modelKey.startsWith('gemini'))
? modelKey
: AI_MODELS[DEFAULT_MODEL]
// Определяем, использовать ли Gemini напрямую
const useGeminiDirect = resolvedModel.startsWith('gemini') || (!openRouterKey && geminiKey)
if (useGeminiDirect) {
if (!geminiKey) {
throw new Error('Gemini API key (GEMINI_API_KEY or GOOGLE_API_KEY) is not configured')
}
const geminiModel = resolvedModel.startsWith('gemini') ? resolvedModel : 'gemini-3.5-flash'
console.log(`[AI] Direct Google Gemini call: ${geminiModel}`)
try {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${geminiModel}:generateContent?key=${geminiKey}`
const response = await $fetch<any>(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
contents: [
{
role: 'user',
parts: [{ text: prompt }]
}
],
systemInstruction: {
parts: [{ text: systemPrompt }]
},
generationConfig: {
temperature: 0.3
}
}
})
const content = response?.candidates?.[0]?.content?.parts?.[0]?.text
if (!content) {
throw new Error('Empty response from Gemini API')
}
return content
} catch (error: any) {
console.error(`[AI] Gemini direct error:`, error?.data || error?.message)
throw new Error(`Gemini direct generation failed: ${error?.message || error?.toString()}`)
}
}
// Иначе используем OpenRouter
if (!openRouterKey) {
throw new Error('Neither OPEN_ROUTER_API_KEY nor GEMINI_API_KEY is configured')
}
console.log(`[AI] OpenRouter call: ${resolvedModel}`)
try {
const response = await $fetch<any>(OPENROUTER_BASE_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${openRouterKey}`,
'Content-Type': 'application/json',
'HTTP-Referer': 'https://a-crm.controlsystem.kz',
'X-Title': 'XFlow AI Node',
},
body: {
model: resolvedModel,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: prompt },
],
stream: false,
},
})
const content = response?.choices?.[0]?.message?.content
if (!content) {
throw new Error('Empty response from OpenRouter model')
}
return content
} catch (error: any) {
console.error(`[AI] OpenRouter error with model ${resolvedModel}:`, error?.data || error?.message)
throw new Error(`OpenRouter generation failed (${resolvedModel}): ${error?.message}`)
}
}
/** Хелпер: список моделей для фронтенда */
export const getAvailableModels = () =>
Object.entries(AI_MODELS).map(([key, modelId]) => ({
key,
modelId,
label: modelLabels[key as AiModelKey],
}))
const modelLabels: Record<AiModelKey, string> = {
laguna: '🏊 Laguna M.1 — стабильная инженерная (Claude via OpenRouter)',
nemotron: '🔬 Nemotron Super 120B — тяжёлая аналитика (NVIDIA via OpenRouter)',
geminiFlash: '⚡ Gemini 3.5 Flash — быстрая и стабильная (Google Direct)',
geminiPro: '🧠 Gemini 3.1 Pro — продвинутая аналитика (Google Direct)',
geminiLite: '🍃 Gemini 3.1 Flash Lite — экономичная (Google Direct)'
}