import { PROVIDERS, type AIProvider } from '../types/providers'; import { OLLAMA_AUTO_DETECT_URLS } from '../types/providers'; export interface ModelInfo { id: string; name: string; } interface TestResult { success: boolean; models?: ModelInfo[]; error?: string; endpoint?: string; } export const testApiKey = async (provider: AIProvider, apiKey: string, endpoint?: string): Promise => { try { switch (provider) { case 'gemini': return await testGemini(apiKey); case 'openai': return await testOpenAI(apiKey); case 'anthropic': return await testAnthropic(apiKey); case 'azure': return await testAzure(apiKey, endpoint); case 'ollama': return await testOllama(endpoint); default: return { success: false, error: 'Provedor não suportado' }; } } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Erro desconhecido ao testar API' }; } }; const findOllamaEndpoint = async (): Promise => { for (const url of OLLAMA_AUTO_DETECT_URLS) { try { const response = await fetch(`${url}/api/tags`, { method: 'GET', signal: AbortSignal.timeout(3000) }); if (response.ok) { return url; } } catch { continue; } } return null; }; const testOllama = async (endpoint?: string): Promise => { let ollamaEndpoint = endpoint; if (!ollamaEndpoint) { const foundEndpoint = await findOllamaEndpoint(); if (foundEndpoint) { ollamaEndpoint = foundEndpoint; } else { return { success: false, error: 'Ollama não encontrado. Configure o endereço manualmente.' }; } } // Normalize endpoint - add /api for OpenWebUI const useOpenWebUI = ollamaEndpoint.includes('llm.reifonas.cloud'); const apiEndpoint = useOpenWebUI ? `${ollamaEndpoint}/api` : ollamaEndpoint; try { const response = await fetch(`${apiEndpoint}/tags`); if (!response.ok) { return { success: false, error: 'Não foi possível conectar ao Ollama. Verifique o endereço.' }; } const data = await response.json(); const models = data.models?.map((m: any) => ({ id: m.name, name: m.name })) || []; const visionModels = models.filter((m: ModelInfo) => m.id.includes('vision') || m.id.includes('llama3') || m.id.includes('qwen2') || m.id.includes('moondream') ); if (visionModels.length > 0) { return { success: true, models: visionModels, endpoint: ollamaEndpoint }; } return { success: true, models: models.length > 0 ? models : [{ id: 'llama3.2', name: 'Llama 3.2 (Padrão)' }], endpoint: ollamaEndpoint }; } catch (error: any) { return { success: false, error: 'Não foi possível conectar ao Ollama. Verifique o endereço e certifique-se que o Ollama está rodando.' }; } }; const testGemini = async (apiKey: string): Promise => { const { GoogleGenAI } = await import('@google/genai'); try { const ai = new GoogleGenAI({ apiKey }); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Respond with exactly: {"status": "ok"}', config: { temperature: 0 } }); if (response.text && response.text.includes('ok')) { return { success: true, models: [ { id: 'gemini-2.0-flash', name: 'Gemini 2.0 Flash (Rápido)' }, { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash (Equilibrado)' }, { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro (Mais potente)' } ] }; } return { success: false, error: 'Resposta inválida do Gemini' }; } catch (error: any) { if (error.message?.includes('API key')) { return { success: false, error: 'Chave de API inválida' }; } throw error; } }; const testOpenAI = async (apiKey: string): Promise => { try { const response = await fetch('https://api.openai.com/v1/models', { headers: { 'Authorization': `Bearer ${apiKey}` } }); if (!response.ok) { const error = await response.json(); return { success: false, error: error.error?.message || 'Chave de API inválida' }; } const data = await response.json(); const visionModels = data.data .filter((m: any) => m.id.includes('gpt-4o') || m.id.includes('gpt-4') || m.id.includes('gpt-4-turbo')) .map((m: any) => ({ id: m.id, name: m.id })); if (visionModels.length === 0) { return { success: true, models: [{ id: 'gpt-4o', name: 'GPT-4o (Padrão)' }] }; } return { success: true, models: visionModels }; } catch (error: any) { return { success: false, error: error.message || 'Erro ao conectar com OpenAI' }; } }; const testAnthropic = async (apiKey: string): Promise => { try { const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'claude-3-haiku-20240307', max_tokens: 10, messages: [{ role: 'user', content: 'Hi' }] }) }); if (!response.ok) { const error = await response.json(); return { success: false, error: error.error?.message || 'Chave de API inválida' }; } return { success: true, models: [ { id: 'claude-3-opus-20240229', name: 'Claude 3 Opus (Mais potente)' }, { id: 'claude-3-sonnet-20240229', name: 'Claude 3 Sonnet (Equilibrado)' }, { id: 'claude-3-haiku-20240307', name: 'Claude 3 Haiku (Rápido)' } ] }; } catch (error: any) { return { success: false, error: error.message || 'Erro ao conectar com Anthropic' }; } }; const testAzure = async (apiKey: string, endpoint: string): Promise => { if (!endpoint) { return { success: false, error: 'Endpoint do Azure é obrigatório' }; } try { const url = `${endpoint}/openai/deployments?api-version=2024-02-15-preview`; const response = await fetch(url, { headers: { 'api-key': apiKey } }); if (!response.ok) { return { success: false, error: 'Endpoint ou chave inválidos' }; } const data = await response.json(); const deployments = data.data?.map((d: any) => ({ id: d.id, name: d.id })) || []; if (deployments.length === 0) { return { success: true, models: [{ id: 'gpt-4', name: 'GPT-4 (Padrão)' }] }; } return { success: true, models: deployments }; } catch (error: any) { return { success: false, error: error.message || 'Erro ao conectar com Azure' }; } };