feat: criado repositório jhonny-editor no Gitea
criado repositório jhonny-editor no Gitea adicionado script admin/deploy.command com commit automático atualizado admin/DEV-NOTES.md com template limpo Resumo: - 32 arquivos alterados - 16 novos - 15 modificados - 0 removidos 16 files changed, 638 insertions(+), 61 deletions(-) Arquivos: - code/engine/skills/boas-praticas-oo.md -> .agents/skills/boas-praticas-oo/SKILL.md - AGENTS.md - code/cep-plugin/index.html - code/cep-plugin/main.js - code/cep-plugin/styles.css - code/engine/integracoes/visual/apple_vision.py - code/engine/integracoes/visual/apple_vision_runner.swift - code/engine/integracoes/visual/extrator_ffmpeg.py - code/engine/scanner/__init__.py - code/engine/scanner/configuracao_visual.py - code/engine/scanner/coordenacao/__init__.py - code/engine/scanner/retakes/adaptador_de_falas.py - code/engine/scanner/retakes/agrupador_de_takes.py - code/engine/scanner/retakes/detector_de_reinicios.py - code/engine/scanner/retakes/modelos_de_retakes.py - code/engine/scanner/visual.py - .jhonny/ - .retakes/ - CODING_STANDARDS.md - code/engine/executar_retakes.py - code/engine/persistencia/ - code/engine/scanner/retakes/__init__.py - code/engine/scanner/retakes/carregador_de_artefatos.py - code/engine/scanner/retakes/classificador_de_retakes.py - code/engine/scanner/retakes/coordenador_de_retakes.py - code/engine/scanner/retakes/deteccao_de_retakes.py - code/engine/scanner/retakes/gerador_de_evidencias.py - code/engine/scanner/retakes/repositorio_de_retakes.py - code/engine/testes/test_consultas_de_persistencia.py - code/engine/testes/test_deteccao_de_retakes.py - code/engine/testes/test_persistencia_sqlite.py - code/relatorios/audio/arquivos/92f97877259a86a8095b1eecafdefe357212a12247d04b78df60e0c0ae38b2ea/
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""Carrega as transcrições produzidas pelo scanner para análise de retakes.
|
||||
|
||||
O painel não retranscreve vídeos: os artefatos ``<caso>-audio-faixa-N.json``
|
||||
gerados pelo scanner já contêm os segmentos de fala por clipe. Esta classe
|
||||
converte esses artefatos em falas prontas para o ``CoordenadorDeRetakes``,
|
||||
sem duplicar a lógica de transcrição.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from .adaptador_de_falas import AdaptadorDeFalas
|
||||
from .modelos_de_retakes import Fala
|
||||
|
||||
|
||||
class ArtefatoDeTranscricaoInvalido(ValueError):
|
||||
"""Erro levantado quando um artefato do scanner não tem transcrição útil."""
|
||||
|
||||
|
||||
class CarregadorDeArtefatosDeAudio:
|
||||
"""Lê os artefatos de transcrição do scanner e devolve falas ordenadas."""
|
||||
|
||||
def __init__(self, adaptador: AdaptadorDeFalas | None = None) -> None:
|
||||
self.adaptador = adaptador or AdaptadorDeFalas()
|
||||
|
||||
def carregar(self, caminhos_dos_artefatos: list[str | Path],
|
||||
video_id: str) -> list[Fala]:
|
||||
"""Converte os artefatos informados em falas prontas para análise.
|
||||
|
||||
Artefatos sem transcrição concluída são ignorados. Quando nenhum
|
||||
artefato contiver segmentos, levanta ``ArtefatoDeTranscricaoInvalido``
|
||||
para que a tela possa avisar o usuário sem executar a análise.
|
||||
"""
|
||||
falas: list[Fala] = []
|
||||
for caminho in caminhos_dos_artefatos:
|
||||
falas.extend(self._falas_do_artefato(Path(caminho), video_id))
|
||||
if not falas:
|
||||
raise ArtefatoDeTranscricaoInvalido(
|
||||
"Nenhum artefato de transcrição contém segmentos de fala. "
|
||||
"Execute o Scanner com transcrição antes de analisar retakes.")
|
||||
return falas
|
||||
|
||||
def _falas_do_artefato(self, caminho: Path,
|
||||
video_id: str) -> list[Fala]:
|
||||
"""Extrai as falas de um único artefato ``-audio-faixa-N.json``."""
|
||||
if not caminho.is_file():
|
||||
return []
|
||||
dados = json.loads(caminho.read_text(encoding="utf-8"))
|
||||
if dados.get("status") != "concluida":
|
||||
return []
|
||||
pares: list[tuple[str, list[object]]] = []
|
||||
for item in dados.get("segmentos_por_clipe", []):
|
||||
segmentos = [SimpleNamespace(**segmento)
|
||||
for segmento in item.get("segmentos", [])]
|
||||
if segmentos:
|
||||
pares.append((str(item.get("clipe", "clipe")), segmentos))
|
||||
return self.adaptador.converter_de_segmentos(pares, video_id=video_id)
|
||||
Reference in New Issue
Block a user