🔧 Auto-deploy: Modo de inferência inteligente e fallback para o VideoMind quando legendas falharem
This commit is contained in:
@@ -735,29 +735,37 @@ app.post('/api/videomind/analyze', requireAuth, async (req, res) => {
|
||||
console.error('Erro ao buscar metadados do oEmbed:', metaErr);
|
||||
}
|
||||
|
||||
let transcriptText = '';
|
||||
let isFallbackMode = false;
|
||||
let systemNotice = '';
|
||||
|
||||
try {
|
||||
// Tenta obter legenda
|
||||
const transcriptObj = await YoutubeTranscript.fetchTranscript(videoId);
|
||||
transcriptText = transcriptObj.map(t => t.text).join(' ');
|
||||
} catch (transcErr) {
|
||||
console.error('Erro ao obter transcrição:', transcErr);
|
||||
console.warn(`[VideoMind] Não foi possível obter legenda direta para o vídeo ${videoId}. Ativando modo de inferência inteligente pelo título/autor. Detalhe do erro:`, transcErr.message);
|
||||
isFallbackMode = true;
|
||||
}
|
||||
|
||||
if (!transcriptText) {
|
||||
return res.status(400).json({
|
||||
error: 'Não foi possível extrair as legendas/transcrição automática deste vídeo. Certifique-se de que o vídeo possui legendas ou transcrição automática disponíveis no YouTube e tente novamente.'
|
||||
});
|
||||
isFallbackMode = true;
|
||||
transcriptText = `[Aviso: Devido a restrições e bloqueio de IP do YouTube, a legenda crua de áudio não pôde ser lida diretamente pelo servidor. Por favor, analise e descreva os objetivos pedagógicos com base estritamente no título do vídeo, canal do autor e no seu vasto conhecimento pedagógico sobre o tema indicado no título]`;
|
||||
systemNotice = `> ⚠️ **Nota do Sistema**: Devido a restrições de conexão do YouTube (bloqueio de IP por excesso de requisições na VPS), a transcrição de áudio automática foi bloqueada temporariamente. A análise e o resumo abaixo foram elaborados a partir do título do vídeo, canal do autor e fundamentação psicopedagógica correspondente.\n\n`;
|
||||
}
|
||||
|
||||
try {
|
||||
const prompt = `Analise a transcrição deste vídeo intitulado "${metadata.title}" (Canal: ${metadata.author}):
|
||||
Transcrição do vídeo:
|
||||
const prompt = `Analise este vídeo do YouTube intitulado "${metadata.title}" (Canal: ${metadata.author}):
|
||||
ID do Vídeo no YouTube: ${videoId}
|
||||
Link do vídeo: https://www.youtube.com/watch?v=${videoId}
|
||||
|
||||
Conteúdo ou descrição da transcrição:
|
||||
"""
|
||||
${transcriptText}
|
||||
"""
|
||||
|
||||
Instruções para o conteúdo de saída:
|
||||
1. Escreva um RESUMO detalhado do vídeo. Esse resumo precisa ter EXATAMENTE ou APROXIMADAMENTE ${numLines} linhas de texto. Seja extremamente fiel aos fatos relatados.
|
||||
1. Escreva um RESUMO detalhado do vídeo. Esse resumo precisa ter EXATAMENTE ou APROXIMADAMENTE ${numLines} linhas de texto. Se a transcrição direta não estiver disponível, faça um resumo conceitual com base no título e no tema geral do vídeo com a mesma quantidade de linhas.
|
||||
2. Faça uma ANÁLISE PEDAGÓGICA COMPLEMENTAR detalhando:
|
||||
- Relevância do conteúdo para fins educacionais.
|
||||
- Indicação de faixa etária/segmento dos alunos recomendado.
|
||||
@@ -771,17 +779,50 @@ Retorne a resposta estruturada estritamente em Markdown. Separe as seções usan
|
||||
# Análise Pedagógica e Sugestões Práticas
|
||||
[Insira a análise pedagógica, os pontos da BNCC e as sugestões de atividades práticas aqui]`;
|
||||
|
||||
const aiResponse = await callMinimax({
|
||||
system: "Você é um pedagogo experiente e especialista em planejamento de aulas no Brasil, alinhado à Base Nacional Comum Curricular (BNCC).",
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 3000
|
||||
});
|
||||
let reportText = '';
|
||||
const systemInstruction = "Você é um pedagogo experiente e especialista em planejamento de aulas no Brasil, alinhado à Base Nacional Comum Curricular (BNCC).";
|
||||
|
||||
// Se estiver em fallback, damos preferência ao Gemini pela capacidade de grounding e busca
|
||||
if (isFallbackMode && process.env.GOOGLE_AI_API_KEY) {
|
||||
try {
|
||||
console.log('[VideoMind] Usando fallback com Google Gemini...');
|
||||
const geminiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${process.env.GOOGLE_AI_MODEL || 'gemini-2.5-flash'}:generateContent?key=${process.env.GOOGLE_AI_API_KEY}`;
|
||||
const response = await fetch(geminiUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
contents: [{ parts: [{ text: `${systemInstruction}\n\nTarefa:\n${prompt}` }] }],
|
||||
generationConfig: { temperature: 0.5, maxOutputTokens: 4000 }
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
reportText = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
||||
} else {
|
||||
const errTxt = await response.text();
|
||||
console.warn('[VideoMind] Fallback do Gemini respondeu com erro:', errTxt);
|
||||
}
|
||||
} catch (geminiErr) {
|
||||
console.error('[VideoMind] Erro no fallback do Gemini:', geminiErr.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Se o Gemini não foi usado ou falhou, usamos o callMinimax padrão
|
||||
if (!reportText) {
|
||||
const aiResponse = await callMinimax({
|
||||
system: systemInstruction,
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 3000
|
||||
});
|
||||
reportText = aiResponse.text || '';
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
metadata,
|
||||
report: aiResponse.text || ''
|
||||
report: systemNotice + reportText
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Erro ao processar análise do VideoMind:', err);
|
||||
|
||||
Reference in New Issue
Block a user