feat: destacado no deploy o resumo que será gravado na mensagem do
- destacado no deploy o resumo que será gravado na mensagem do commit Resumo: - 8 arquivos alterados - 1 novos - 7 modificados - 0 removidos 7 files changed, 143 insertions(+), 11 deletions(-) Arquivos: - .jhonny/analises.db - admin/deploy.command - code/engine/executar_scanner.py - code/engine/integracoes/midia/__init__.py - code/engine/integracoes/visual/apple_vision.py - code/engine/scanner/configuracao_visual.py - code/engine/scanner/visual.py - code/engine/integracoes/midia/compactador_de_proxy.py
This commit is contained in:
@@ -15,13 +15,41 @@ CAMINHO_DO_CODIGO = Path(__file__).resolve().parent.parent
|
||||
if str(CAMINHO_DO_CODIGO) not in sys.path:
|
||||
sys.path.insert(0, str(CAMINHO_DO_CODIGO))
|
||||
|
||||
|
||||
def _encontrar_caminho_da_midia() -> str:
|
||||
"""Localiza a pasta com ``ffmpeg``/``ffprobe`` para o PATH dos subprocessos.
|
||||
|
||||
O Premiere é aberto pelo Finder/LaunchServices (sem shell de login), então o
|
||||
PATH herdado pelo painel não costuma trazer ``/opt/homebrew/bin``. Essa
|
||||
função devolve o primeiro caminho conhecido onde essas ferramentas existem,
|
||||
ou string vazia quando nenhum é encontrado.
|
||||
"""
|
||||
for candidato in ("/opt/homebrew/bin", "/usr/local/bin"):
|
||||
if Path(candidato, "ffprobe").is_file() or Path(candidato, "ffmpeg").is_file():
|
||||
return candidato
|
||||
return ""
|
||||
|
||||
|
||||
# O mesmo ajuste de PATH já usado em ``admin/deploy.command`` e
|
||||
# ``admin/install.command``: sem ele, a extração de frames e a transcrição
|
||||
# falham com ``No such file or directory: 'ffprobe'``.
|
||||
CAMINHO_DA_MIDIA = _encontrar_caminho_da_midia()
|
||||
if CAMINHO_DA_MIDIA:
|
||||
os.environ["PATH"] = CAMINHO_DA_MIDIA + os.pathsep + os.environ.get("PATH", "")
|
||||
|
||||
from engine.integracoes.premiere.conversores import ConversorDeTimeline
|
||||
from engine.scanner import ConfiguracaoVisualDoScanner, criar_detector_apple_vision, gerar_relatorio_visual
|
||||
from engine.scanner.transcricao_da_timeline import TranscricaoDaTimeline
|
||||
from engine.persistencia import RepositorioDeAnalisesSQLite, RepositorioDeTimelineSQLite
|
||||
|
||||
|
||||
MODELO_DIARIZACAO_PADRAO = "pyannote/speaker-diarization-community-1"
|
||||
|
||||
# O padrão do banco de análises é ``.jhonny/analises.db`` relativo ao cwd, mas o
|
||||
# painel roda o scanner com cwd ``code``. Fixamos o caminho absoluto na raiz do
|
||||
# projeto para garantir que a gravação sempre caia no mesmo banco.
|
||||
CAMINHO_DO_BANCO = CAMINHO_DO_CODIGO.parent / ".jhonny" / "analises.db"
|
||||
|
||||
|
||||
def nome_seguro(nome: str) -> str:
|
||||
return re.sub(r"[^A-Za-z0-9._-]+", "-", nome.strip()).strip(".-") or "timeline"
|
||||
@@ -41,6 +69,13 @@ def executar(entrada: Path, saida: Path) -> Path:
|
||||
print(json.dumps({"evento": "progresso", "etapa": etapa, "percentual": round(percentual, 1),
|
||||
"clipe": clipe}, ensure_ascii=False), flush=True)
|
||||
|
||||
# Persistência: timeline/estrutura + análise visual + transcrição vão para o
|
||||
# banco SQLite do projeto (mesmo dos relatórios gerados).
|
||||
repositorio_de_timeline = RepositorioDeTimelineSQLite(CAMINHO_DO_BANCO)
|
||||
repositorio_de_analises = RepositorioDeAnalisesSQLite(CAMINHO_DO_BANCO)
|
||||
emitir("Persistindo timeline", 0)
|
||||
repositorio_de_timeline.registrar_timeline(timeline)
|
||||
|
||||
resultados = []
|
||||
for clipe in clipes:
|
||||
peso = max(1, math.ceil((clipe.intervalo_na_origem or clipe.intervalo_na_timeline).duracao /
|
||||
@@ -60,6 +95,11 @@ def executar(entrada: Path, saida: Path) -> Path:
|
||||
arquivo = Path(tempfile.gettempdir()) / f"scanner-{clipe.identificador}.json"
|
||||
gerar_relatorio_visual(clipe, resultado, arquivo, configuracao.intervalo_em_segundos)
|
||||
resultados.append(json.loads(arquivo.read_text(encoding="utf-8")))
|
||||
# Grava no banco os fatos visuais e as cenas detectadas deste clipe.
|
||||
repositorio_de_analises.registrar_evidencias_visuais(
|
||||
timeline.identificador, clipe.identificador, resultado.evidencias)
|
||||
repositorio_de_analises.registrar_cenas(
|
||||
timeline.identificador, resultado.cenas, clipe.identificador)
|
||||
except Exception as erro:
|
||||
resultados.append({"clipe": {"identificador": clipe.identificador, "nome": clipe.nome,
|
||||
"arquivo_original": clipe.arquivo}, "erro": str(erro)})
|
||||
@@ -111,6 +151,8 @@ def executar(entrada: Path, saida: Path) -> Path:
|
||||
transcricoes = TranscricaoDaTimeline(provider, diretoria_de_trabalho=pasta / ".cache-audio",
|
||||
diarizador=diarizador).executar(
|
||||
Timeline(timeline.identificador, timeline.nome, faixas=faixas_de_audio))
|
||||
# Persiste a transcrição (segmentos + falas) no banco de análises.
|
||||
repositorio_de_analises.registrar_transcricoes(timeline.identificador, transcricoes)
|
||||
for transcricao in transcricoes:
|
||||
transcricoes_por_clipe[transcricao.identificador_do_clipe] = [
|
||||
{"inicio": item.inicio, "fim": item.fim, "texto": item.texto,
|
||||
|
||||
Reference in New Issue
Block a user