diff --git a/code/cep-plugin/index.html b/code/cep-plugin/index.html index c7b855e..6fcf8b1 100755 --- a/code/cep-plugin/index.html +++ b/code/cep-plugin/index.html @@ -162,13 +162,14 @@
-

Concluir edição

-

Salva no banco a análise carregada, o tipo de vídeo e as configurações editoriais escolhidas. O JSON para a IA poderá ser gerado depois, quando necessário.

+

Revisar plano de edição

+

Carrega do banco o plano criado para esta sequência e mostra as decisões antes da aplicação.

- Bloqueado + Aguardando plano
- +

O plano editorial pendente será carregado automaticamente da sequência selecionada.

+
- -
- -
+

O plano será lido diretamente do banco da edição concluída.

Cole o plano recebido da IA. O painel valida o formato antes de executar.

diff --git a/code/cep-plugin/main.js b/code/cep-plugin/main.js index 120dcb0..61876d7 100755 --- a/code/cep-plugin/main.js +++ b/code/cep-plugin/main.js @@ -2157,7 +2157,7 @@ function silenceSelecionarTipoVideo() { if (!tipo) { document.getElementById("silenceTipoVideoInfo").textContent = "Selecione um tipo cadastrado para continuar."; setStep(1, "ready", "Selecione um tipo"); - setStep(2, "locked", "Selecione o tipo"); + setStep(2, "locked", "Aguardando plano"); document.getElementById("btnBuildPlan").disabled = true; return; } @@ -2383,9 +2383,9 @@ function silenceLoadScannerAnalysis() { info.textContent = silenceState.sequenceName + " · " + quantidade + " trecho(s) · " + (audioDoBanco.metricas_de_voz_disponiveis ? "métricas disponíveis" : "métricas não realizadas") + " · " + (audioDoBanco.diarizacao_disponivel ? falantes.length + " falante(s)" : "diarização não realizada"); - setStep(2, "locked", "Selecione o tipo"); - setStep(1, "ready", "Selecione um tipo"); - setStep(3, "locked", "Aguardando conclusão"); + setStep(2, "locked", "Aguardando plano"); + setStep(1, "ready", "Tipo no Projeto"); + setStep(3, "locked", "Aguardando plano"); renderizarTiposDeVideoParaEdicao(); document.getElementById("btnBuildPlan").disabled = true; // btnDiarize/btnVoiceFeatures/silenceDiarizeInfo/silenceVoiceFeaturesInfo ficavam no @@ -2711,8 +2711,8 @@ function silenceSelectSequence() { setStep(1, "done", "Timeline escolhida"); lockStepsFrom(2); setStep(2, "ready", "Sua vez"); + document.getElementById("btnBuildPlan").disabled = false; setStep(3, "ready", "Carregar plano salvo"); - document.getElementById("btnLoadSavedEditorialPlan").disabled = false; document.getElementById("btnTranscribe").disabled = false; document.getElementById("silenceJsonCard").hidden = true; document.getElementById("jsonFileActions").hidden = true; @@ -2734,7 +2734,7 @@ function lockStepsFrom(first) { if (first <= 3) planoEditorialIdCarregado = null; var buttons = { 2: ["btnBuildPlan"], - 3: ["btnApplyEditorialActions", "btnLoadSavedEditorialPlan"], + 3: ["btnApplyEditorialActions"], }; for (var n = first; n <= 5; n++) { setStep(n, "locked", "Bloqueado"); @@ -3316,7 +3316,6 @@ function silenceConcluirEdicao() { } setStep(2, "done", "Edição concluída"); setStep(3, "locked", "Aguardando plano da IA"); - document.getElementById("btnLoadSavedEditorialPlan").disabled = false; taskEnd(true, "Edição concluída e salva no banco."); silenceLog("Edição concluída e salva no banco de análises.", "ok"); showToast("ok", "Edição concluída e salva no banco."); @@ -3330,14 +3329,14 @@ function carregarPlanoEditorialSalvo() { showToast("err", "Detecte a sequência antes de carregar o plano."); return; } - setBusy("btnLoadSavedEditorialPlan", true); + setBusy("btnBuildPlan", true); silenceLog("Lendo o plano editorial diretamente do banco…"); runStreamed( SCANNER_PYTHON_BIN, [CARREGAR_PLANO_SCRIPT, "--banco", ANALISES_DB_PATH, "--video-id", String(silenceState.sequenceId)], function (linha) { silenceLog(linha); }, function (codigo, ultimoErro) { - setBusy("btnLoadSavedEditorialPlan", false); + setBusy("btnBuildPlan", false); if (codigo !== 0) { silenceLog("Não foi possível carregar o plano salvo.", "err"); showToast("err", ultimoErro || "Nenhum plano salvo encontrado para este vídeo."); @@ -3348,10 +3347,12 @@ function carregarPlanoEditorialSalvo() { if (!resposta.ok || !resposta.plano) throw new Error("Resposta inválida do banco."); planoEditorialIdCarregado = resposta.plano.plano_id; document.getElementById("editorialPlanJson").value = JSON.stringify(resposta.plano, null, 2); + document.getElementById("planoResumoEdicao").textContent = "Plano " + planoEditorialIdCarregado + " encontrado · " + resposta.plano.actions.length + " ação(ões) · aguardando aprovação."; document.getElementById("editorialSavedPlanStatus").textContent = "Plano " + planoEditorialIdCarregado + " carregado do banco."; document.getElementById("editorialPlanJsonStatus").textContent = "Plano salvo no SQLite; pronto para aprovação e aplicação."; document.getElementById("btnApplyEditorialActions").disabled = false; - setStep(3, "ready", "Plano carregado"); + setStep(2, "done", "Plano carregado"); + setStep(3, "ready", "Pronto para aplicar"); silenceLog("Plano " + planoEditorialIdCarregado + " carregado diretamente do SQLite.", "ok"); showToast("ok", "Plano salvo carregado."); } catch (erro) { diff --git a/code/engine/integracoes/audio/provider_de_analise_musical_essentia.py b/code/engine/integracoes/audio/provider_de_analise_musical_essentia.py index 0d42c1c..87ed606 100644 --- a/code/engine/integracoes/audio/provider_de_analise_musical_essentia.py +++ b/code/engine/integracoes/audio/provider_de_analise_musical_essentia.py @@ -59,8 +59,18 @@ class AnalisadorDeMusicaInstrumentalEssentia: pontuacoes_de_humor: tuple[Any, ...] = () if self._classificador is not None: pontuacoes_de_genero, pontuacoes_de_humor = self._classificador.classificar(caminho) + generos = ( + tuple(item.etiqueta for item in pontuacoes_de_genero) + if pontuacoes_de_genero + else self._etiquetas(dados, ("genre", "genres")) + ) + humores = ( + tuple(item.etiqueta for item in pontuacoes_de_humor) + if pontuacoes_de_humor + else self._etiquetas(dados, ("mood", "moods")) + ) return self._converter_resultado( - caminho, dados, pontuacoes_de_genero, pontuacoes_de_humor, + caminho, dados, pontuacoes_de_genero, pontuacoes_de_humor, generos, humores, ) def _obter_extrator(self) -> Callable[[str], tuple[Any, Any]]: @@ -82,6 +92,8 @@ class AnalisadorDeMusicaInstrumentalEssentia: dados: Any, pontuacoes_de_genero: tuple[Any, ...] = (), pontuacoes_de_humor: tuple[Any, ...] = (), + generos: tuple[str, ...] = (), + humores: tuple[str, ...] = (), ) -> ResultadoDaAnaliseMusical: return ResultadoDaAnaliseMusical( caminho_do_arquivo=caminho, @@ -91,8 +103,8 @@ class AnalisadorDeMusicaInstrumentalEssentia: modo=self._texto(self._buscar(dados, "tonal.key_edma.scale")), intensidade=self._numero(self._buscar(dados, "lowlevel.average_loudness")), dancabilidade=self._numero(self._buscar(dados, "rhythm.danceability")), - generos=tuple(item.etiqueta for item in pontuacoes_de_genero), - humores=tuple(item.etiqueta for item in pontuacoes_de_humor), + generos=generos, + humores=humores, instrumentos=self._etiquetas(dados, ("instrument", "instruments")), etiquetas=self._etiquetas(dados, ("tags", "semantic")), pontuacoes_de_genero=pontuacoes_de_genero,