feat: integrado o classificador Essentia de gênero e humor ao resu
- integrado o classificador Essentia de gênero e humor ao resultado musical - reorganizado o fluxo da aba Editar vídeo para revisar o plano antes de aplicar Resumo: - 3 arquivos alterados - 0 novos - 3 modificados - 0 removidos 3 files changed, 32 insertions(+), 21 deletions(-) Arquivos: - code/cep-plugin/index.html - code/cep-plugin/main.js - code/engine/integracoes/audio/provider_de_analise_musical_essentia.py
This commit is contained in:
@@ -162,13 +162,14 @@
|
|||||||
<div class="step-head">
|
<div class="step-head">
|
||||||
<span class="step-number" aria-hidden="true">2</span>
|
<span class="step-number" aria-hidden="true">2</span>
|
||||||
<div class="step-title">
|
<div class="step-title">
|
||||||
<h2>Concluir edição</h2>
|
<h2>Revisar plano de edição</h2>
|
||||||
<p>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.</p>
|
<p>Carrega do banco o plano criado para esta sequência e mostra as decisões antes da aplicação.</p>
|
||||||
</div>
|
</div>
|
||||||
<span class="step-chip" id="step2Chip">Bloqueado</span>
|
<span class="step-chip" id="step2Chip">Aguardando plano</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<button id="btnBuildPlan" class="button button-primary" onclick="silenceConcluirEdicao()" type="button" disabled>Concluir edição</button>
|
<p class="field-help" id="planoResumoEdicao">O plano editorial pendente será carregado automaticamente da sequência selecionada.</p>
|
||||||
|
<button id="btnBuildPlan" class="button button-primary" onclick="carregarPlanoEditorialSalvo()" type="button" disabled>Carregar plano salvo</button>
|
||||||
<dl class="kv" id="silenceJsonCard" hidden>
|
<dl class="kv" id="silenceJsonCard" hidden>
|
||||||
<div><dt>Trechos</dt><dd id="jsonSegmentCount">—</dd></div>
|
<div><dt>Trechos</dt><dd id="jsonSegmentCount">—</dd></div>
|
||||||
<div><dt>Arquivo</dt><dd class="kv-path" id="jsonOutputPath">—</dd></div>
|
<div><dt>Arquivo</dt><dd class="kv-path" id="jsonOutputPath">—</dd></div>
|
||||||
@@ -191,10 +192,7 @@
|
|||||||
<span class="step-chip" id="step3Chip">Bloqueado</span>
|
<span class="step-chip" id="step3Chip">Bloqueado</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<label class="field-label" for="editorialPlanJson">JSON de ações devolvido pela IA</label>
|
<label class="field-label" for="editorialPlanJson">Plano carregado do banco</label>
|
||||||
<div class="button-row">
|
|
||||||
<button type="button" class="button button-ghost" id="btnLoadSavedEditorialPlan" onclick="carregarPlanoEditorialSalvo()" disabled>Carregar plano salvo no banco</button>
|
|
||||||
</div>
|
|
||||||
<p class="field-help" id="editorialSavedPlanStatus">O plano será lido diretamente do banco da edição concluída.</p>
|
<p class="field-help" id="editorialSavedPlanStatus">O plano será lido diretamente do banco da edição concluída.</p>
|
||||||
<textarea id="editorialPlanJson" class="editorial-plan-json" rows="10" spellcheck="false" placeholder='Cole aqui o JSON com source e actions.'></textarea>
|
<textarea id="editorialPlanJson" class="editorial-plan-json" rows="10" spellcheck="false" placeholder='Cole aqui o JSON com source e actions.'></textarea>
|
||||||
<p class="field-help" id="editorialPlanJsonStatus">Cole o plano recebido da IA. O painel valida o formato antes de executar.</p>
|
<p class="field-help" id="editorialPlanJsonStatus">Cole o plano recebido da IA. O painel valida o formato antes de executar.</p>
|
||||||
|
|||||||
+11
-10
@@ -2157,7 +2157,7 @@ function silenceSelecionarTipoVideo() {
|
|||||||
if (!tipo) {
|
if (!tipo) {
|
||||||
document.getElementById("silenceTipoVideoInfo").textContent = "Selecione um tipo cadastrado para continuar.";
|
document.getElementById("silenceTipoVideoInfo").textContent = "Selecione um tipo cadastrado para continuar.";
|
||||||
setStep(1, "ready", "Selecione um tipo");
|
setStep(1, "ready", "Selecione um tipo");
|
||||||
setStep(2, "locked", "Selecione o tipo");
|
setStep(2, "locked", "Aguardando plano");
|
||||||
document.getElementById("btnBuildPlan").disabled = true;
|
document.getElementById("btnBuildPlan").disabled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2383,9 +2383,9 @@ function silenceLoadScannerAnalysis() {
|
|||||||
info.textContent = silenceState.sequenceName + " · " + quantidade + " trecho(s) · " +
|
info.textContent = silenceState.sequenceName + " · " + quantidade + " trecho(s) · " +
|
||||||
(audioDoBanco.metricas_de_voz_disponiveis ? "métricas disponíveis" : "métricas não realizadas") + " · " +
|
(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");
|
(audioDoBanco.diarizacao_disponivel ? falantes.length + " falante(s)" : "diarização não realizada");
|
||||||
setStep(2, "locked", "Selecione o tipo");
|
setStep(2, "locked", "Aguardando plano");
|
||||||
setStep(1, "ready", "Selecione um tipo");
|
setStep(1, "ready", "Tipo no Projeto");
|
||||||
setStep(3, "locked", "Aguardando conclusão");
|
setStep(3, "locked", "Aguardando plano");
|
||||||
renderizarTiposDeVideoParaEdicao();
|
renderizarTiposDeVideoParaEdicao();
|
||||||
document.getElementById("btnBuildPlan").disabled = true;
|
document.getElementById("btnBuildPlan").disabled = true;
|
||||||
// btnDiarize/btnVoiceFeatures/silenceDiarizeInfo/silenceVoiceFeaturesInfo ficavam no
|
// btnDiarize/btnVoiceFeatures/silenceDiarizeInfo/silenceVoiceFeaturesInfo ficavam no
|
||||||
@@ -2711,8 +2711,8 @@ function silenceSelectSequence() {
|
|||||||
setStep(1, "done", "Timeline escolhida");
|
setStep(1, "done", "Timeline escolhida");
|
||||||
lockStepsFrom(2);
|
lockStepsFrom(2);
|
||||||
setStep(2, "ready", "Sua vez");
|
setStep(2, "ready", "Sua vez");
|
||||||
|
document.getElementById("btnBuildPlan").disabled = false;
|
||||||
setStep(3, "ready", "Carregar plano salvo");
|
setStep(3, "ready", "Carregar plano salvo");
|
||||||
document.getElementById("btnLoadSavedEditorialPlan").disabled = false;
|
|
||||||
document.getElementById("btnTranscribe").disabled = false;
|
document.getElementById("btnTranscribe").disabled = false;
|
||||||
document.getElementById("silenceJsonCard").hidden = true;
|
document.getElementById("silenceJsonCard").hidden = true;
|
||||||
document.getElementById("jsonFileActions").hidden = true;
|
document.getElementById("jsonFileActions").hidden = true;
|
||||||
@@ -2734,7 +2734,7 @@ function lockStepsFrom(first) {
|
|||||||
if (first <= 3) planoEditorialIdCarregado = null;
|
if (first <= 3) planoEditorialIdCarregado = null;
|
||||||
var buttons = {
|
var buttons = {
|
||||||
2: ["btnBuildPlan"],
|
2: ["btnBuildPlan"],
|
||||||
3: ["btnApplyEditorialActions", "btnLoadSavedEditorialPlan"],
|
3: ["btnApplyEditorialActions"],
|
||||||
};
|
};
|
||||||
for (var n = first; n <= 5; n++) {
|
for (var n = first; n <= 5; n++) {
|
||||||
setStep(n, "locked", "Bloqueado");
|
setStep(n, "locked", "Bloqueado");
|
||||||
@@ -3316,7 +3316,6 @@ function silenceConcluirEdicao() {
|
|||||||
}
|
}
|
||||||
setStep(2, "done", "Edição concluída");
|
setStep(2, "done", "Edição concluída");
|
||||||
setStep(3, "locked", "Aguardando plano da IA");
|
setStep(3, "locked", "Aguardando plano da IA");
|
||||||
document.getElementById("btnLoadSavedEditorialPlan").disabled = false;
|
|
||||||
taskEnd(true, "Edição concluída e salva no banco.");
|
taskEnd(true, "Edição concluída e salva no banco.");
|
||||||
silenceLog("Edição concluída e salva no banco de análises.", "ok");
|
silenceLog("Edição concluída e salva no banco de análises.", "ok");
|
||||||
showToast("ok", "Edição concluída e salva no banco.");
|
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.");
|
showToast("err", "Detecte a sequência antes de carregar o plano.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setBusy("btnLoadSavedEditorialPlan", true);
|
setBusy("btnBuildPlan", true);
|
||||||
silenceLog("Lendo o plano editorial diretamente do banco…");
|
silenceLog("Lendo o plano editorial diretamente do banco…");
|
||||||
runStreamed(
|
runStreamed(
|
||||||
SCANNER_PYTHON_BIN,
|
SCANNER_PYTHON_BIN,
|
||||||
[CARREGAR_PLANO_SCRIPT, "--banco", ANALISES_DB_PATH, "--video-id", String(silenceState.sequenceId)],
|
[CARREGAR_PLANO_SCRIPT, "--banco", ANALISES_DB_PATH, "--video-id", String(silenceState.sequenceId)],
|
||||||
function (linha) { silenceLog(linha); },
|
function (linha) { silenceLog(linha); },
|
||||||
function (codigo, ultimoErro) {
|
function (codigo, ultimoErro) {
|
||||||
setBusy("btnLoadSavedEditorialPlan", false);
|
setBusy("btnBuildPlan", false);
|
||||||
if (codigo !== 0) {
|
if (codigo !== 0) {
|
||||||
silenceLog("Não foi possível carregar o plano salvo.", "err");
|
silenceLog("Não foi possível carregar o plano salvo.", "err");
|
||||||
showToast("err", ultimoErro || "Nenhum plano salvo encontrado para este vídeo.");
|
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.");
|
if (!resposta.ok || !resposta.plano) throw new Error("Resposta inválida do banco.");
|
||||||
planoEditorialIdCarregado = resposta.plano.plano_id;
|
planoEditorialIdCarregado = resposta.plano.plano_id;
|
||||||
document.getElementById("editorialPlanJson").value = JSON.stringify(resposta.plano, null, 2);
|
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("editorialSavedPlanStatus").textContent = "Plano " + planoEditorialIdCarregado + " carregado do banco.";
|
||||||
document.getElementById("editorialPlanJsonStatus").textContent = "Plano salvo no SQLite; pronto para aprovação e aplicação.";
|
document.getElementById("editorialPlanJsonStatus").textContent = "Plano salvo no SQLite; pronto para aprovação e aplicação.";
|
||||||
document.getElementById("btnApplyEditorialActions").disabled = false;
|
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");
|
silenceLog("Plano " + planoEditorialIdCarregado + " carregado diretamente do SQLite.", "ok");
|
||||||
showToast("ok", "Plano salvo carregado.");
|
showToast("ok", "Plano salvo carregado.");
|
||||||
} catch (erro) {
|
} catch (erro) {
|
||||||
|
|||||||
@@ -59,8 +59,18 @@ class AnalisadorDeMusicaInstrumentalEssentia:
|
|||||||
pontuacoes_de_humor: tuple[Any, ...] = ()
|
pontuacoes_de_humor: tuple[Any, ...] = ()
|
||||||
if self._classificador is not None:
|
if self._classificador is not None:
|
||||||
pontuacoes_de_genero, pontuacoes_de_humor = self._classificador.classificar(caminho)
|
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(
|
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]]:
|
def _obter_extrator(self) -> Callable[[str], tuple[Any, Any]]:
|
||||||
@@ -82,6 +92,8 @@ class AnalisadorDeMusicaInstrumentalEssentia:
|
|||||||
dados: Any,
|
dados: Any,
|
||||||
pontuacoes_de_genero: tuple[Any, ...] = (),
|
pontuacoes_de_genero: tuple[Any, ...] = (),
|
||||||
pontuacoes_de_humor: tuple[Any, ...] = (),
|
pontuacoes_de_humor: tuple[Any, ...] = (),
|
||||||
|
generos: tuple[str, ...] = (),
|
||||||
|
humores: tuple[str, ...] = (),
|
||||||
) -> ResultadoDaAnaliseMusical:
|
) -> ResultadoDaAnaliseMusical:
|
||||||
return ResultadoDaAnaliseMusical(
|
return ResultadoDaAnaliseMusical(
|
||||||
caminho_do_arquivo=caminho,
|
caminho_do_arquivo=caminho,
|
||||||
@@ -91,8 +103,8 @@ class AnalisadorDeMusicaInstrumentalEssentia:
|
|||||||
modo=self._texto(self._buscar(dados, "tonal.key_edma.scale")),
|
modo=self._texto(self._buscar(dados, "tonal.key_edma.scale")),
|
||||||
intensidade=self._numero(self._buscar(dados, "lowlevel.average_loudness")),
|
intensidade=self._numero(self._buscar(dados, "lowlevel.average_loudness")),
|
||||||
dancabilidade=self._numero(self._buscar(dados, "rhythm.danceability")),
|
dancabilidade=self._numero(self._buscar(dados, "rhythm.danceability")),
|
||||||
generos=tuple(item.etiqueta for item in pontuacoes_de_genero),
|
generos=generos,
|
||||||
humores=tuple(item.etiqueta for item in pontuacoes_de_humor),
|
humores=humores,
|
||||||
instrumentos=self._etiquetas(dados, ("instrument", "instruments")),
|
instrumentos=self._etiquetas(dados, ("instrument", "instruments")),
|
||||||
etiquetas=self._etiquetas(dados, ("tags", "semantic")),
|
etiquetas=self._etiquetas(dados, ("tags", "semantic")),
|
||||||
pontuacoes_de_genero=pontuacoes_de_genero,
|
pontuacoes_de_genero=pontuacoes_de_genero,
|
||||||
|
|||||||
Reference in New Issue
Block a user