/** * XFlow AI Utility — OpenRouter Integration (Stable Models) * * Поддерживаемые модели (наиболее стабильные и без жестких rate-limit): * * • poolside/laguna-m.1:free — быстрые инженерные задачи, Claude-based (default) * • nvidia/nemotron-3-super-120b-a12b:free — MoE 120B, тяжёлая аналитика, сложные рассуждения */ 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', } as const export type AiModelKey = keyof typeof AI_MODELS /** Дефолтная модель, если не указана */ const DEFAULT_MODEL: AiModelKey = 'laguna' export const generateAIResponse = async ( prompt: string, systemPrompt = 'You are a helpful assistant.', modelKey?: AiModelKey | string, ): Promise => { const apiKey = process.env.NUXT_OPEN_ROUTER_API_KEY || process.env.OPEN_ROUTER_API_KEY if (!apiKey) { throw new Error('OPEN_ROUTER_API_KEY is not configured') } // Резолвим модель: принимаем как ключ ('laguna') так и полное имя const resolvedModel: string = modelKey && modelKey in AI_MODELS ? AI_MODELS[modelKey as AiModelKey] : modelKey && modelKey.includes('/') ? modelKey : AI_MODELS[DEFAULT_MODEL] console.log(`[AI] Using model: ${resolvedModel}`) try { const response = await $fetch(OPENROUTER_BASE_URL, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, '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 AI model') } return content } catch (error: any) { console.error(`[AI] Error with model ${resolvedModel}:`, error?.data || error?.message) throw new Error(`AI 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 = { laguna: '🏊 Laguna M.1 — стабильная инженерная (Claude)', nemotron: '🔬 Nemotron Super 120B — тяжёлая аналитика (NVIDIA)', }