diff --git a/components/ApiKeySetup.tsx b/components/ApiKeySetup.tsx index e74fe32..295ca75 100644 --- a/components/ApiKeySetup.tsx +++ b/components/ApiKeySetup.tsx @@ -67,6 +67,7 @@ export const ApiKeySetup: React.FC = ({ onKeySave }) => { case 'azure': return 'https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps'; case 'ollama': return 'https://ollama.com/download'; case 'openrouter': return 'https://openrouter.ai/keys'; + case 'minimax': return 'https://platform.minimaxi.com/user-center/basic-information/interface-key'; default: return '#'; } }; @@ -79,6 +80,7 @@ export const ApiKeySetup: React.FC = ({ onKeySave }) => { case 'azure': return 'Azure OpenAI'; case 'ollama': return 'Ollama (Local)'; case 'openrouter': return 'OpenRouter'; + case 'minimax': return 'MiniMax'; default: return 'API'; } }; diff --git a/services/aiService.ts b/services/aiService.ts index 70c83e2..efab224 100644 --- a/services/aiService.ts +++ b/services/aiService.ts @@ -351,6 +351,8 @@ export const analyzeCertificate = async (options: AnalyzeOptions): Promise => { + if (!apiKey) { + throw new Error("A chave de API do MiniMax não foi fornecida."); + } + + const base64Data = await new Promise((resolve) => { + const reader = new FileReader(); + reader.onloadend = () => resolve((reader.result as string).split(',')[1]); + reader.readAsDataURL(file); + }); + + const response = await fetch('https://api.minimax.chat/v1/chat/completions', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model, + messages: [ + { + role: 'user', + content: [ + { type: 'text', text: PROMPT_BASE + "\n\nRetorne apenas JSON válido sem formatação markdown." }, + { + type: 'image_url', + image_url: { url: `data:${file.type};base64,${base64Data}` } + } + ] + } + ], + temperature: 0.1, + response_format: { type: 'json_object' } + }) + }); + + if (!response.ok) { + const error = await response.json().catch(() => ({})); + throw new Error(`Erro do MiniMax: ${error.error?.message || 'Erro desconhecido'}`); + } + + const data = await response.json(); + const content = data.choices[0]?.message?.content; + + if (!content) { + throw new Error("Resposta vazia do MiniMax"); + } + return cleanAndParseJson(content) as ReportData; }; \ No newline at end of file diff --git a/services/apiTestService.ts b/services/apiTestService.ts index e2a4b6a..9adb26d 100644 --- a/services/apiTestService.ts +++ b/services/apiTestService.ts @@ -28,6 +28,8 @@ export const testApiKey = async (provider: AIProvider, apiKey: string, endpoint? return await testOllama(endpoint); case 'openrouter': return await testOpenRouter(apiKey); + case 'minimax': + return await testMinimax(apiKey); default: return { success: false, error: 'Provedor não suportado' }; } @@ -250,4 +252,27 @@ const testOpenRouter = async (apiKey: string): Promise => { } catch (error: any) { return { success: false, error: error.message || 'Erro ao conectar com OpenRouter' }; } +}; + +const testMinimax = async (apiKey: string): Promise => { + try { + const response = await fetch('https://api.minimax.chat/v1/models', { + headers: { 'Authorization': `Bearer ${apiKey}` } + }); + + if (!response.ok) { + const error = await response.json().catch(() => ({})); + return { success: false, error: error.message || 'Chave de API inválida' }; + } + + return { + success: true, + models: [ + { id: 'minimax-2.7', name: 'MiniMax 2.7' }, + { id: 'minimax-3.0', name: 'MiniMax 3.0' } + ] + }; + } catch (error: any) { + return { success: false, error: error.message || 'Erro ao conectar com MiniMax' }; + } }; \ No newline at end of file diff --git a/types/providers.ts b/types/providers.ts index b7feb6f..d20bfbc 100644 --- a/types/providers.ts +++ b/types/providers.ts @@ -1,6 +1,6 @@ import { AIProvider } from './providers'; -export type AIProvider = 'gemini' | 'openai' | 'anthropic' | 'azure' | 'ollama' | 'openrouter'; +export type AIProvider = 'gemini' | 'openai' | 'anthropic' | 'azure' | 'ollama' | 'openrouter' | 'minimax'; export const OLLAMA_AUTO_DETECT_URLS = [ 'http://localhost:11434', @@ -65,5 +65,12 @@ export const PROVIDERS: ProviderConfig[] = [ description: 'Acesso a múltiplos modelos através do OpenRouter', models: ['google/gemini-2.5-flash', 'google/gemini-2.5-pro', 'anthropic/claude-3.5-sonnet', 'openai/gpt-4o', 'meta-llama/llama-3.1-70b-instruct'], defaultModel: 'google/gemini-2.5-flash' + }, + { + id: 'minimax', + name: 'MiniMax', + description: 'Modelos MiniMax (2.7 e 3.0)', + models: ['minimax-2.7', 'minimax-3.0'], + defaultModel: 'minimax-2.7' } ]; \ No newline at end of file