feat: criado monitoramento contínuo de trilhas com varredura recur

- criado monitoramento contínuo de trilhas com varredura recursiva e baixa prioridade
- gerado e validado plano editorial revisável do depoimento da Erika sem aplicação na timeline
- adicionada leitura e comparação estrutural da timeline após aplicar planos de edição
- limitadas as classificações de trilhas às duas maiores probabilidades de cada categoria
- limpo o catálogo musical para reiniciar as análises sem remover dados de vídeo

Resumo:
- 34 arquivos alterados
- 6 novos
- 28 modificados
- 0 removidos

 28 files changed, 833 insertions(+), 75 deletions(-)

Arquivos:
  - .jhonny/analises.db
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/engine/analisar_trilhas.py
  - code/engine/aplicar_plano_de_edicao.py
  - code/engine/consultar_detalhes_de_trilha.py
  - code/engine/editor/__init__.py
  - code/engine/editor/aplicador_de_plano_de_edicao.py
  - code/engine/editor/backup_de_sequencia.py
  - code/engine/editor/escrita/escrita_no_editor.py
  - code/engine/editor/modelos.py
  - code/engine/editor/validacao_semantica.py
  - code/engine/integracoes/audio/classificador_de_musica_essentia.py
  - code/engine/integracoes/audio/modelos_de_analise_musical.py
  - code/engine/integracoes/audio/provider_de_analise_musical_essentia.py
  - code/engine/persistencia/esquema.py
  - code/engine/persistencia/repositorio_de_trilhas.py
  - code/engine/testes/duplos_de_premiere.py
  - code/engine/testes/test_aplicador_de_plano_de_edicao.py
  - code/engine/testes/test_aplicar_plano_de_edicao.py
  - code/engine/testes/test_escrita_no_editor.py
  - code/engine/testes/test_leitor_de_plano_de_edicao.py
  - code/engine/testes/test_validador_semantico_de_plano.py
  - code/plugins/premiere-pro/skills/editar-por-voz/SKILL.md
  - code/plugins/premiere-pro/skills/editar-por-voz/criterios/08-formato-de-saida.md
  - code/plugins/premiere-pro/skills/editar-por-voz/criterios/10-revisao-humana.md
  - code/src/tools/timeline.ts
  - code/tests/tools/tool-modules.test.ts
  - .jhonny/planos/
  - code/.jhonny/analises.db-shm
  - code/.jhonny/analises.db-wal
  - code/engine/editor/verificador_da_aplicacao.py
  - code/engine/testes/test_verificador_da_aplicacao.py
  - code/plugins/premiere-pro/skills/editar-por-voz/criterios/11-gancho.md
This commit is contained in:
João Henrique
2026-09-10 15:09:27 -04:00
parent da400de7d3
commit 2c9bdf2ff0
34 changed files with 1179 additions and 75 deletions
@@ -36,7 +36,7 @@ class ClassificadorDeMusicaEssentia:
def classificar(
self, arquivo: str | Path,
) -> tuple[tuple[PontuacaoDeEtiqueta, ...], tuple[PontuacaoDeEtiqueta, ...]]:
) -> tuple[tuple[PontuacaoDeEtiqueta, ...], tuple[PontuacaoDeEtiqueta, ...], tuple[PontuacaoDeEtiqueta, ...]]:
"""
Classifica o gênero e o humor diretamente do conteúdo do arquivo.
@@ -71,11 +71,19 @@ class ClassificadorDeMusicaEssentia:
embedding = modelo_de_embedding(audio)
previsao_de_genero = modelo_de_genero(embedding)
previsao_de_humor = modelo_de_humor(embedding)
pontuacoes_de_humor = self._converter_pontuacoes(previsao_de_humor, "humor")
nomes_de_tema = {"action", "adventure", "advertising", "background", "children", "christmas", "commercial", "corporate", "documentary", "drama", "film", "game", "movie", "nature", "sport", "trailer", "travel"}
return (
self._converter_pontuacoes(previsao_de_genero, "genero"),
self._converter_pontuacoes(previsao_de_humor, "humor"),
self._duas_maiores(self._converter_pontuacoes(previsao_de_genero, "genero")),
self._duas_maiores(tuple(item for item in pontuacoes_de_humor if item.etiqueta not in nomes_de_tema)),
self._duas_maiores(tuple(item for item in pontuacoes_de_humor if item.etiqueta in nomes_de_tema)),
)
@staticmethod
def _duas_maiores(pontuacoes: tuple[PontuacaoDeEtiqueta, ...]) -> tuple[PontuacaoDeEtiqueta, ...]:
"""Retorna as duas maiores probabilidades, preservando o ranking."""
return pontuacoes[:2]
def _obter_modelos(self, classe_de_embedding: Any, classe_de_classificacao: Any):
if self._modelos_carregados is not None:
return self._modelos_carregados
@@ -41,5 +41,7 @@ class ResultadoDaAnaliseMusical:
etiquetas: tuple[str, ...] = field(default_factory=tuple)
pontuacoes_de_genero: tuple[PontuacaoDeEtiqueta, ...] = field(default_factory=tuple)
pontuacoes_de_humor: tuple[PontuacaoDeEtiqueta, ...] = field(default_factory=tuple)
pontuacoes_de_tema: tuple[PontuacaoDeEtiqueta, ...] = field(default_factory=tuple)
temas: tuple[str, ...] = field(default_factory=tuple)
provedor: str = "Essentia"
modelo: str | None = None
@@ -57,8 +57,12 @@ class AnalisadorDeMusicaInstrumentalEssentia:
raise ValueError("O Essentia devolveu uma análise vazia.")
pontuacoes_de_genero: tuple[Any, ...] = ()
pontuacoes_de_humor: tuple[Any, ...] = ()
pontuacoes_de_tema: tuple[Any, ...] = ()
if self._classificador is not None:
pontuacoes_de_genero, pontuacoes_de_humor = self._classificador.classificar(caminho)
classificacoes = self._classificador.classificar(caminho)
pontuacoes_de_genero, pontuacoes_de_humor = classificacoes[:2]
if len(classificacoes) > 2:
pontuacoes_de_tema = classificacoes[2]
generos = (
tuple(item.etiqueta for item in pontuacoes_de_genero)
if pontuacoes_de_genero
@@ -70,7 +74,7 @@ class AnalisadorDeMusicaInstrumentalEssentia:
else self._etiquetas(dados, ("mood", "moods"))
)
return self._converter_resultado(
caminho, dados, pontuacoes_de_genero, pontuacoes_de_humor, generos, humores,
caminho, dados, pontuacoes_de_genero, pontuacoes_de_humor, generos, humores, pontuacoes_de_tema,
)
def _obter_extrator(self) -> Callable[[str], tuple[Any, Any]]:
@@ -94,6 +98,7 @@ class AnalisadorDeMusicaInstrumentalEssentia:
pontuacoes_de_humor: tuple[Any, ...] = (),
generos: tuple[str, ...] = (),
humores: tuple[str, ...] = (),
pontuacoes_de_tema: tuple[Any, ...] = (),
) -> ResultadoDaAnaliseMusical:
return ResultadoDaAnaliseMusical(
caminho_do_arquivo=caminho,
@@ -105,10 +110,12 @@ class AnalisadorDeMusicaInstrumentalEssentia:
dancabilidade=self._numero(self._buscar(dados, "rhythm.danceability")),
generos=generos,
humores=humores,
temas=tuple(item.etiqueta for item in pontuacoes_de_tema),
instrumentos=self._etiquetas(dados, ("instrument", "instruments")),
etiquetas=self._etiquetas(dados, ("tags", "semantic")),
pontuacoes_de_genero=pontuacoes_de_genero,
pontuacoes_de_humor=pontuacoes_de_humor,
pontuacoes_de_tema=pontuacoes_de_tema,
modelo=self._nome_do_modelo,
)