`;
// Inserir o conteúdo da análise no container de resultado
let inserted = false;
// Opção 1: Tentar inserir no resultContentContainer
const resultContentContainer = document.querySelector('.result-content');
if (resultContentContainer) {
resultContentContainer.prepend(analysisContentContainer);
inserted = true;
}
// Opção 2: Tentar inserir usando pdfViewer como referência
if (!inserted && JaniceApp.elements.pdfViewer && JaniceApp.elements.pdfViewer.parentNode) {
JaniceApp.elements.pdfViewer.parentNode.insertBefore(analysisContentContainer, JaniceApp.elements.pdfViewer);
inserted = true;
}
// Opção 3: Tentar inserir diretamente no resultContainer
if (!inserted) {
const resultContainer = document.getElementById('result-container');
if (resultContainer) {
resultContainer.prepend(analysisContentContainer);
inserted = true;
}
}
// Se nenhuma das opções funcionou, registrar erro
if (!inserted) {
console.error('Não foi possível encontrar um container para inserir o conteúdo da análise');
throw new Error('Não foi possível exibir a análise. Container não encontrado.');
}
// Configurar PDF com verificação de nulos
if (analysis.pdfUrl) {
// Verificar se pdfViewer existe antes de tentar definir seu innerHTML
if (JaniceApp.elements.pdfViewer) {
JaniceApp.elements.pdfViewer.innerHTML = `
Relatório PDF Pronto
Seu relatório estratégico foi gerado com sucesso e está pronto para visualização.
O PDF será aberto em uma nova aba do navegador
`;
}
// Verificar se exportPdfButton existe antes de modificá-lo
if (JaniceApp.elements.exportPdfButton) {
JaniceApp.elements.exportPdfButton.disabled = false;
JaniceApp.elements.exportPdfButton.innerHTML = ' Abrir Relatório PDF';
}
} else {
// Verificar se pdfViewer existe antes de tentar definir seu innerHTML
if (JaniceApp.elements.pdfViewer) {
JaniceApp.elements.pdfViewer.innerHTML = `
PDF não disponível. Você ainda pode copiar o relatório usando o botão abaixo.
`;
}
// Verificar se exportPdfButton existe antes de modificá-lo
if (JaniceApp.elements.exportPdfButton) {
JaniceApp.elements.exportPdfButton.disabled = true;
JaniceApp.elements.exportPdfButton.innerHTML = ' PDF Indisponível';
}
}
// Mostrar apenas a seção de resultados (estado exclusivo)
JaniceApp.utils.showOnlySection('result-container');
// Scroll automático para a seção de resultados
JaniceApp.utils.scrollToElement('result-container');
} catch (error) {
console.error('Erro ao visualizar análise:', error);
alert('Não foi possível carregar a análise. Tente novamente.');
}
},
// Deletar análise
deleteAnalysis: async function(analysisId) {
if (!confirm('Tem certeza que deseja excluir esta análise? Esta ação não pode ser desfeita.')) {
return;
}
try {
const response = await fetch(`/api/analises/${analysisId}`, {
method: 'DELETE'
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Erro ao excluir análise');
}
// Recarregar lista de análises
if (JaniceApp.state.currentClientId) {
this.loadClientAnalyses(JaniceApp.state.currentClientId);
}
console.log('✅ Análise excluída com sucesso');
} catch (error) {
console.error('Erro ao excluir análise:', error);
alert('Não foi possível excluir a análise. Tente novamente.');
}
},
// Formatar markdown específico para análises
formatMarkdownForAnalysis: function(text) {
if (!text) return '';
let formatted = text;
// Converter títulos
formatted = formatted.replace(/^# (.+)$/gm, '
Importante: A transcrição ocorre em tempo real, o que significa que um arquivo de 10 minutos levará aproximadamente 10 minutos para ser processado. O sistema usa Whisper para oferecer alta qualidade de transcrição.
`;
// Adicionar a caixa de informação antes do formulário
const formContainer = document.querySelector('.transcription-form-container');
if (formContainer && !formContainer.querySelector('.info-box')) {
formContainer.insertBefore(infoBox, formContainer.firstChild);
}
// Mostrar apenas o formulário de transcrição (estado exclusivo)
JaniceApp.utils.showOnlySection('transcription-container');
// Scroll automático para o formulário de transcrição
JaniceApp.utils.scrollToElement('transcription-container');
},
// Submeter formulário de transcrição
submitTranscriptionForm: async function(event) {
event.preventDefault();
// Validar campos
if (!JaniceApp.elements.transcriptionTitleInput.value.trim()) {
alert('O título da transcrição é obrigatório');
return;
}
if (!JaniceApp.elements.transcriptionFileInput.files.length) {
alert('Por favor, selecione um arquivo de áudio ou vídeo');
return;
}
// Verificar tamanho do arquivo (máximo 2GB)
const fileSize = JaniceApp.elements.transcriptionFileInput.files[0].size / (1024 * 1024); // tamanho em MB
console.log('🔥 [SCRIPT_3] Função submitTranscriptionForm do script_3.js foi chamada!');
console.log('🔥 [SCRIPT_3] Tamanho do arquivo:', fileSize.toFixed(2), 'MB');
if (fileSize > 2048) { // 2GB = 2048MB
alert('O arquivo é muito grande. O tamanho máximo permitido é 2GB (2048MB).');
return;
}
try {
// Estimar duração do áudio baseada no tamanho do arquivo
const estimatedAudioMinutes = Math.max(1, Math.ceil(fileSize / 1)); // ~1MB por minuto
// Registrar processo no painel de processos ativos com metadados
const client = JaniceApp.state.currentClients.find(c => c._id === JaniceApp.state.currentClientId);
const processMetadata = {
duracaoAudioMinutos: estimatedAudioMinutes,
tamanhoArquivoMB: fileSize
};
const processId = JaniceApp.state.activeProcessesManager.registerProcess(
'transcricao',
JaniceApp.state.currentClientId,
`Transcrição: ${JaniceApp.elements.transcriptionTitleInput.value.trim()}`,
null,
processMetadata
);
// Mostrar tela de carregamento
JaniceApp.elements.transcriptionContainer.style.display = 'none';
JaniceApp.elements.welcomeContainer.style.display = 'none';
JaniceApp.elements.errorContainer.style.display = 'none';
JaniceApp.elements.resultContainer.style.display = 'none';
JaniceApp.elements.loadingContainer.style.display = 'block';
// Adicionar classe para modo transcrição (simplifica interface)
JaniceApp.elements.loadingContainer.classList.add('transcription-mode');
// Adaptar tela de carregamento para transcrição
JaniceApp.elements.loadingStatus.textContent = 'Iniciando transcrição...';
document.querySelector('.loading-text').textContent = 'Processando arquivo de áudio/vídeo...';
// Estimar duração baseada no tamanho do arquivo (aproximadamente 1MB por minuto para áudio de qualidade média)
const estimatedMinutes = Math.max(1, Math.ceil(fileSize / 1));
// Adicionar aviso sobre tempo de processamento real
const infoElement = document.createElement('div');
infoElement.className = 'transcription-time-info';
infoElement.innerHTML = `
Tempo estimado: A transcrição ocorre aproximadamente em tempo real.
Este arquivo de cerca de ${estimatedMinutes} minutos levará aproximadamente ${estimatedMinutes} minutos para ser processado.
`;
infoElement.style.margin = '15px 0';
infoElement.style.padding = '10px';
infoElement.style.backgroundColor = '#f8f9fa';
infoElement.style.borderRadius = '5px';
infoElement.style.fontSize = '14px';
// Adicionar elemento abaixo da barra de progresso
const progressContainer = document.querySelector('.progress-container');
if (progressContainer && !progressContainer.querySelector('.transcription-time-info')) {
progressContainer.appendChild(infoElement);
}
// Adaptação para transcrição
document.getElementById('step-1').querySelector('.step-text').textContent = 'Preparando arquivo';
document.getElementById('step-2').querySelector('.step-text').textContent = 'Processando áudio';
document.getElementById('step-3').querySelector('.step-text').textContent = 'Gerando transcrição';
document.getElementById('step-4').querySelector('.step-text').textContent = 'Finalizando';
// Resetar barra de progresso
JaniceApp.modules.analysis.resetProgress();
// Decidir qual rota usar baseado no tamanho do arquivo
let response;
if (fileSize > 100) { // Arquivos maiores que 100MB usam Cloudinary
console.log('📤 [SCRIPT_3] Arquivo grande detectado, usando rota Cloudinary...');
// Verificar se a função Cloudinary está disponível
if (typeof window.submitTranscriptionFormCloudinary === 'function') {
console.log('✅ [SCRIPT_3] Delegando para função Cloudinary...');
// Delegar para a função Cloudinary
return window.submitTranscriptionFormCloudinary(event);
} else {
console.warn('⚠️ [SCRIPT_3] Função Cloudinary não disponível, usando upload direto...');
}
}
console.log('📤 [SCRIPT_3] Usando upload direto via servidor...');
// Preparar dados do formulário para upload direto
const formData = new FormData();
formData.append('titulo', JaniceApp.elements.transcriptionTitleInput.value.trim());
formData.append('idioma', JaniceApp.elements.transcriptionLanguageSelect.value);
formData.append('arquivo', JaniceApp.elements.transcriptionFileInput.files[0]);
// Enviar requisição para iniciar transcrição via upload direto
response = await fetch(`/api/transcricoes/upload/${JaniceApp.state.currentClientId}`, {
method: 'POST',
body: formData
});
if (!response.ok) {
// Tentar extrair o erro da resposta
let errorMessage = 'Erro ao iniciar transcrição';
try {
const errorData = await response.json();
errorMessage = errorData.erro || 'Erro ao iniciar transcrição';
} catch (jsonError) {
// Caso a resposta não seja um JSON válido, tentar obter o texto
try {
const errorText = await response.text();
if (errorText.includes('Tipo de arquivo não suportado')) {
errorMessage = 'Tipo de arquivo não suportado. Por favor, envie apenas arquivos de áudio ou vídeo.';
} else if (errorText.length < 200) {
// Se for um texto curto, exibir diretamente
errorMessage = errorText;
}
} catch (textError) {
// Fallback para mensagem genérica
console.error('Erro ao processar resposta:', textError);
}
}
throw new Error(errorMessage);
}
// Obter ID da transcrição para acompanhar progresso
const data = await response.json();
const transcriptionId = data.transcricaoId;
// Iniciar monitoramento de progresso via verificação periódica
// O sistema SSE de processos ativos já está conectado e funcionando
setTimeout(() => {
this.startPeriodicStatusCheck(transcriptionId);
}, 10000); // Iniciar após 10 segundos
// Atualizar lista de transcrições em segundo plano
this.loadClientTranscriptions(JaniceApp.state.currentClientId);
} catch (error) {
console.error('Erro:', error);
JaniceApp.modules.analysis.showError(error.message || 'Ocorreu um erro ao iniciar a transcrição.');
}
},
// Carregar transcrições do cliente
loadClientTranscriptions: async function(clientId) {
try {
console.log(`🔄 [DEBUG] Carregando transcrições para cliente: ${clientId}`);
// Quebrar cache do navegador adicionando timestamp
const response = await fetch(`/api/transcricoes/cliente/${clientId}?t=${Date.now()}`, {
credentials: 'include',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
console.error(`❌ [FETCH-ERROR] Status: ${response.status} ${response.statusText}`);
console.error(`❌ [FETCH-ERROR] URL: ${response.url}`);
console.error(`❌ [FETCH-ERROR] Headers:`, Object.fromEntries(response.headers.entries()));
if (response.status === 502) {
throw new Error('Erro 502: Servidor temporariamente indisponível. Tente novamente em alguns segundos.');
} else if (response.status === 401) {
throw new Error('Erro de autenticação. Faça login novamente.');
} else {
throw new Error(`Erro ${response.status}: ${response.statusText}`);
}
}
const transcriptions = await response.json();
console.log(`🔍 [DEBUG] Encontradas ${transcriptions.length} transcrições para cliente ${clientId}:`, transcriptions);
// Validar se todas as transcrições pertencem ao cliente correto
transcriptions.forEach(t => {
if (t.cliente !== clientId) {
console.error(`❌ [BUG] Transcrição ${t._id} pertence ao cliente ${t.cliente}, não ${clientId}`);
}
});
if (!transcriptions.length) {
JaniceApp.elements.transcriptionList.innerHTML = `
Nenhuma transcrição realizada
`;
return;
}
// Ordenar transcrições por data (mais recente primeiro)
transcriptions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
// Renderizar lista de transcrições
JaniceApp.elements.transcriptionList.innerHTML = transcriptions.map(transcription => {
// Calcular duração formatada
const duration = this.formatDuration(transcription.duracao);
// Determinar status e classe CSS
let statusClass = 'completed';
let statusText = 'Concluído';
if (transcription.emProgresso) {
statusClass = 'in-progress';
statusText = 'Em progresso';
} else if (transcription.erro) {
statusClass = 'error';
statusText = 'Erro';
}
return `