/** * Copyright (c) 2024-2025 Тарабанов Александр Викторович * All rights reserved. * * This software is proprietary and confidential. * Unauthorized copying, modification, or distribution is prohibited. * * For licensing inquiries: info@hb3-accelerator.com * Website: https://hb3-accelerator.com * GitHub: https://github.com/HB3-ACCELERATOR */ const encryptedDb = require('./encryptedDatabaseService'); const OpenAI = require('openai'); const Anthropic = require('@anthropic-ai/sdk'); const TABLE = 'ai_providers_settings'; async function getProviderSettings(provider) { const settings = await encryptedDb.getData(TABLE, { provider: provider }, 1); return settings[0] || null; } async function upsertProviderSettings({ provider, api_key, base_url, selected_model, embedding_model }) { const data = { provider: provider, api_key: api_key, base_url: base_url, selected_model: selected_model, embedding_model: embedding_model, updated_at: new Date() }; // Проверяем, существует ли запись const existing = await encryptedDb.getData(TABLE, { provider: provider }, 1); if (existing.length > 0) { // Обновляем существующую запись по ID return await encryptedDb.saveData(TABLE, data, { id: existing[0].id }); } else { // Создаем новую запись return await encryptedDb.saveData(TABLE, data); } } async function deleteProviderSettings(provider) { await encryptedDb.deleteData(TABLE, { provider: provider }); } async function getProviderModels(provider, { api_key, base_url } = {}) { try { if (provider === 'openai') { const client = new OpenAI({ apiKey: api_key, baseURL: base_url }); const res = await client.models.list(); return res.data ? res.data.map(m => ({ id: m.id, ...m })) : []; } if (provider === 'anthropic') { const client = new Anthropic({ apiKey: api_key, baseURL: base_url }); const res = await client.models.list(); return res.data ? res.data.map(m => ({ id: m.id, ...m })) : []; } if (provider === 'google') { const { GoogleGenAI } = await import('@google/genai'); const ai = new GoogleGenAI({ apiKey: api_key, baseUrl: base_url }); const pager = await ai.models.list(); const models = []; for await (const model of pager) { models.push(model); } return models; } if (provider === 'ollama') { // Для Ollama — через ai-assistant.js return []; } return []; } catch (error) { return []; } } async function verifyProviderKey(provider, { api_key, base_url } = {}) { try { if (provider === 'openai') { const client = new OpenAI({ apiKey: api_key, baseURL: base_url }); await client.models.list(); return { success: true }; } if (provider === 'anthropic') { const client = new Anthropic({ apiKey: api_key, baseURL: base_url }); await client.models.list(); return { success: true }; } if (provider === 'google') { const { GoogleGenAI } = await import('@google/genai'); const ai = new GoogleGenAI({ apiKey: api_key, baseUrl: base_url }); const pager = await ai.models.list(); for await (const _ of pager) { break; } return { success: true }; } if (provider === 'ollama') { // Для Ollama — всегда true (локальный) return { success: true }; } return { success: false, error: 'Unknown provider' }; } catch (error) { return { success: false, error: error.message }; } } async function getAllLLMModels() { try { // Получаем все настройки провайдеров const providers = await encryptedDb.getData(TABLE, {}); // Собираем все модели из всех провайдеров const allModels = []; for (const provider of providers) { if (provider.selected_model) { // Фильтруем embedding модели - они не должны быть в списке LLM const modelName = provider.selected_model.toLowerCase(); const isEmbeddingModel = modelName.includes('embed') || modelName.includes('embedding') || modelName.includes('bge') || modelName.includes('nomic') || modelName.includes('text-embedding') || modelName.includes('mxbai') || modelName.includes('sentence') || modelName.includes('ada-002') || modelName.includes('text-embedding-ada') || modelName.includes('text-embedding-3'); if (!isEmbeddingModel) { allModels.push({ id: provider.selected_model, provider: provider.provider }); } } } // Для Ollama проверяем реально установленные модели через HTTP API try { const axios = require('axios'); const ollamaConfig = require('./ollamaConfig'); const ollamaUrl = ollamaConfig.getBaseUrl(); const response = await axios.get(`${ollamaUrl}/api/tags`, { timeout: 5000 }); const models = response.data.models || []; for (const model of models) { // Фильтруем embedding модели из Ollama const modelName = model.name.toLowerCase(); const isEmbeddingModel = modelName.includes('embed') || modelName.includes('embedding') || modelName.includes('bge') || modelName.includes('nomic') || modelName.includes('mxbai') || modelName.includes('sentence'); if (!isEmbeddingModel) { allModels.push({ id: model.name, provider: 'ollama' }); } } } catch (ollamaError) { // console.error('Error checking Ollama models:', ollamaError); // Если не удалось проверить Ollama, добавляем базовые модели allModels.push({ id: 'qwen2.5:7b', provider: 'ollama' }); } // Убираем дубликаты const uniqueModels = []; const seen = new Set(); for (const model of allModels) { const key = `${model.id}-${model.provider}`; if (!seen.has(key)) { seen.add(key); uniqueModels.push(model); } } return uniqueModels; } catch (error) { // console.error('Error getting LLM models:', error); return []; } } async function getAllEmbeddingModels() { try { // Получаем все настройки провайдеров const providers = await encryptedDb.getData(TABLE, {}); // Собираем все embedding модели из всех провайдеров const allModels = []; for (const provider of providers) { if (provider.embedding_model) { allModels.push({ id: provider.embedding_model, provider: provider.provider }); } } // Для Ollama проверяем реально установленные embedding модели через HTTP API try { const axios = require('axios'); const ollamaConfig = require('./ollamaConfig'); const ollamaUrl = ollamaConfig.getBaseUrl(); const response = await axios.get(`${ollamaUrl}/api/tags`, { timeout: 5000 }); const models = response.data.models || []; for (const model of models) { // Проверяем, что это embedding модель if (model.name.includes('embed') || model.name.includes('bge') || model.name.includes('nomic')) { allModels.push({ id: model.name, provider: 'ollama' }); } } } catch (ollamaError) { // console.error('Error checking Ollama embedding models:', ollamaError); // Если не удалось проверить Ollama, добавляем базовые embedding модели allModels.push({ id: 'mxbai-embed-large:latest', provider: 'ollama' }); } // Убираем дубликаты const uniqueModels = []; const seen = new Set(); for (const model of allModels) { const key = `${model.id}-${model.provider}`; if (!seen.has(key)) { seen.add(key); uniqueModels.push(model); } } return uniqueModels; } catch (error) { // console.error('Error getting embedding models:', error); return []; } } module.exports = { getProviderSettings, upsertProviderSettings, deleteProviderSettings, getProviderModels, verifyProviderKey, getAllLLMModels, getAllEmbeddingModels, };