⚡ Auto-deploy: Otimização da latência de chat (detecção rápida com Groq e streaming nativo com MiniMax M3)
This commit is contained in:
@@ -2968,53 +2968,8 @@ app.post('/api/chat', requireAuth, async (req, res) => {
|
||||
let detectedText = null;
|
||||
let usingGroqForDetection = false;
|
||||
|
||||
// 1) Tentar MiniMax M3 como primário
|
||||
if (process.env.MINIMAX_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Router] Detectando intenção via MiniMax M3...');
|
||||
const r = await callMinimax({
|
||||
messages: [{ role: 'user', content: promptText }],
|
||||
system: systemDetector,
|
||||
temperature: 0.0,
|
||||
max_tokens: 20
|
||||
});
|
||||
detectedText = r.text;
|
||||
} catch (err) {
|
||||
console.error('[Smart Router] Falha na detecção via MiniMax, tentando OpenRouter...', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Fallback: OpenRouter
|
||||
if (!detectedText && process.env.OPENROUTER_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Router] Detectando intenção via OpenRouter...');
|
||||
const detectResponse = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: process.env.OPENROUTER_MODEL || 'openai/gpt-4.1-nano',
|
||||
messages: [
|
||||
{ role: 'system', content: systemDetector },
|
||||
{ role: 'user', content: promptText }
|
||||
],
|
||||
max_tokens: 20,
|
||||
temperature: 0.0
|
||||
})
|
||||
});
|
||||
if (detectResponse.ok) {
|
||||
const detectData = await detectResponse.json();
|
||||
detectedText = detectData.choices?.[0]?.message?.content?.toUpperCase() || null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Smart Router] Falha de detecção na OpenRouter, tentando Groq...', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Fallback final: Groq
|
||||
if (!detectedText && process.env.GROQ_API_KEY) {
|
||||
// 1) Tentar Groq como primário (ultrarrápido para classificação)
|
||||
if (process.env.GROQ_API_KEY) {
|
||||
console.log('[Smart Router] Detectando intenção via Groq (llama-3.1-8b-instant)...');
|
||||
try {
|
||||
const detectResponse = await fetch('https://api.groq.com/openai/v1/chat/completions', {
|
||||
@@ -3039,7 +2994,52 @@ app.post('/api/chat', requireAuth, async (req, res) => {
|
||||
usingGroqForDetection = !!detectedText;
|
||||
}
|
||||
} catch (groqErr) {
|
||||
console.error('[Smart Router] Falha de detecção na API da Groq:', groqErr.message);
|
||||
console.error('[Smart Router] Falha de detecção na API da Groq, tentando MiniMax...', groqErr.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Fallback: MiniMax M3
|
||||
if (!detectedText && process.env.MINIMAX_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Router] Detectando intenção via MiniMax M3...');
|
||||
const r = await callMinimax({
|
||||
messages: [{ role: 'user', content: promptText }],
|
||||
system: systemDetector,
|
||||
temperature: 0.0,
|
||||
max_tokens: 20
|
||||
});
|
||||
detectedText = r.text;
|
||||
} catch (err) {
|
||||
console.error('[Smart Router] Falha na detecção via MiniMax, tentando OpenRouter...', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Fallback final: OpenRouter
|
||||
if (!detectedText && process.env.OPENROUTER_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Router] Detectando intenção via OpenRouter...');
|
||||
const detectResponse = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: process.env.OPENROUTER_MODEL || 'openai/gpt-4.1-nano',
|
||||
messages: [
|
||||
{ role: 'system', content: systemDetector },
|
||||
{ role: 'user', content: promptText }
|
||||
],
|
||||
max_tokens: 20,
|
||||
temperature: 0.0
|
||||
})
|
||||
});
|
||||
if (detectResponse.ok) {
|
||||
const detectData = await detectResponse.json();
|
||||
detectedText = detectData.choices?.[0]?.message?.content?.toUpperCase() || null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Smart Router] Falha de detecção final na OpenRouter:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3445,54 +3445,37 @@ app.post('/api/chat', requireAuth, async (req, res) => {
|
||||
let chatResponse;
|
||||
let providerUsed = 'MiniMax-M3';
|
||||
|
||||
// 1) Tentar MiniMax M3 (NÃO-STREAMING para o M3 porque o M3 devolve thinking blocks
|
||||
// que não seguem o protocolo SSE do OpenAI; a UI consome o JSON final e faz o streaming
|
||||
// via o endpoint /v1/chat/completions que vamos montar localmente).
|
||||
let useMinimaxNonStream = false;
|
||||
// 1) Tentar MiniMax M3 (Streaming OpenAI-compatível) para velocidade instantânea
|
||||
let useMinimaxStream = false;
|
||||
try {
|
||||
console.log('[Smart Router] Chamando MiniMax M3 (não-streaming, JSON final)...');
|
||||
const minmBase = (process.env.MINIMAX_API_BASE || 'https://api.minimax.io/v1').replace(/\/v1\/?$/, '');
|
||||
const minmResp = await fetch(`${minmBase}/anthropic/v1/messages`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Api-Key': process.env.MINIMAX_API_KEY,
|
||||
'Content-Type': 'application/json',
|
||||
'anthropic-version': '2023-06-01'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: process.env.MINIMAX_MODEL || 'MiniMax-M3',
|
||||
max_tokens: 4096,
|
||||
temperature,
|
||||
system: enrichedMessages[0].content,
|
||||
messages: enrichedMessages.slice(1)
|
||||
})
|
||||
});
|
||||
if (minmResp.ok) {
|
||||
const data = await minmResp.json();
|
||||
const text = (data.content || []).filter(b => b.type === 'text').map(b => b.text).join('').trim();
|
||||
if (text) {
|
||||
// "Transformar" resposta JSON em um objeto compatível com o resto do fluxo:
|
||||
// devolvemos um Response falso com stream SSE
|
||||
const sseBody =
|
||||
`data: ${JSON.stringify({ choices: [{ delta: { content: text } }] })}\n\n` +
|
||||
`data: [DONE]\n\n`;
|
||||
chatResponse = new Response(sseBody, {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'text/event-stream' }
|
||||
});
|
||||
useMinimaxNonStream = true;
|
||||
if (process.env.MINIMAX_API_KEY) {
|
||||
console.log('[Smart Router] Chamando MiniMax M3 (streaming OpenAI-compat)...');
|
||||
const minmBase = (process.env.MINIMAX_API_BASE || 'https://api.minimax.io/v1').replace(/\/v1\/?$/, '');
|
||||
chatResponse = await fetch(`${minmBase}/v1/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.MINIMAX_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: process.env.MINIMAX_MODEL || 'MiniMax-M3',
|
||||
messages: enrichedMessages,
|
||||
stream: true,
|
||||
temperature
|
||||
})
|
||||
});
|
||||
if (chatResponse.ok) {
|
||||
useMinimaxStream = true;
|
||||
} else {
|
||||
console.warn('[Smart Router] M3 respondeu OK mas sem texto; caindo no OpenRouter.');
|
||||
console.warn('[Smart Router] M3 streaming status', chatResponse.status, '- caindo no OpenRouter.');
|
||||
}
|
||||
} else {
|
||||
console.warn('[Smart Router] M3 status', minmResp.status, '- caindo no OpenRouter.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Erro na conexão com MiniMax M3, tentando OpenRouter...', e.message);
|
||||
console.error('Erro na conexão streaming com MiniMax M3, tentando OpenRouter...', e.message);
|
||||
}
|
||||
|
||||
// 2) Fallback: OpenRouter (streaming SSE, igual ao original)
|
||||
if ((!chatResponse || !chatResponse.ok) && !useMinimaxNonStream && process.env.OPENROUTER_API_KEY) {
|
||||
if ((!chatResponse || !chatResponse.ok) && !useMinimaxStream && process.env.OPENROUTER_API_KEY) {
|
||||
console.log('[Smart Router] Usando OpenRouter como fallback de streaming de texto...');
|
||||
providerUsed = 'OpenRouter';
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user