🔧 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);
|
console.error('Erro ao buscar metadados do oEmbed:', metaErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let transcriptText = '';
|
||||||
|
let isFallbackMode = false;
|
||||||
|
let systemNotice = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Tenta obter legenda
|
// Tenta obter legenda
|
||||||
const transcriptObj = await YoutubeTranscript.fetchTranscript(videoId);
|
const transcriptObj = await YoutubeTranscript.fetchTranscript(videoId);
|
||||||
transcriptText = transcriptObj.map(t => t.text).join(' ');
|
transcriptText = transcriptObj.map(t => t.text).join(' ');
|
||||||
} catch (transcErr) {
|
} 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) {
|
if (!transcriptText) {
|
||||||
return res.status(400).json({
|
isFallbackMode = true;
|
||||||
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.'
|
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 {
|
try {
|
||||||
const prompt = `Analise a transcrição deste vídeo intitulado "${metadata.title}" (Canal: ${metadata.author}):
|
const prompt = `Analise este vídeo do YouTube intitulado "${metadata.title}" (Canal: ${metadata.author}):
|
||||||
Transcrição do vídeo:
|
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}
|
${transcriptText}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Instruções para o conteúdo de saída:
|
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:
|
2. Faça uma ANÁLISE PEDAGÓGICA COMPLEMENTAR detalhando:
|
||||||
- Relevância do conteúdo para fins educacionais.
|
- Relevância do conteúdo para fins educacionais.
|
||||||
- Indicação de faixa etária/segmento dos alunos recomendado.
|
- 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
|
# 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]`;
|
[Insira a análise pedagógica, os pontos da BNCC e as sugestões de atividades práticas aqui]`;
|
||||||
|
|
||||||
const aiResponse = await callMinimax({
|
let reportText = '';
|
||||||
system: "Você é um pedagogo experiente e especialista em planejamento de aulas no Brasil, alinhado à Base Nacional Comum Curricular (BNCC).",
|
const systemInstruction = "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,
|
// Se estiver em fallback, damos preferência ao Gemini pela capacidade de grounding e busca
|
||||||
max_tokens: 3000
|
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({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
metadata,
|
metadata,
|
||||||
report: aiResponse.text || ''
|
report: systemNotice + reportText
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Erro ao processar análise do VideoMind:', err);
|
console.error('Erro ao processar análise do VideoMind:', err);
|
||||||
|
|||||||
Reference in New Issue
Block a user