Files
jhonny-editor/code/engine/integracoes/visual/README.md
T
João Henrique c1b544f4b5 feat: reorganizado o fluxo de edição para validar a análise do Sca
- reorganizado o fluxo de edição para validar a análise do Scanner, selecionar o tipo de vídeo e enviar suas instruções no JSON.
- banco de análises: métricas de fala viraram colunas, busca lexical FTS5, enunciados com embeddings, views achatadas de leitura (fala/palavra/linha do tempo/fala com visual), ingestor do pipeline de voz e gravação idempotente de evidências visuais e cenas.
- retakes passam a ser gravados no banco de análises (SQLite) em vez de JSON por caso, com status de revisão persistido.
- planos de edição e suas aplicações passam a ser registrados no banco, em vez de se perderem no arquivo temporário.
- comando de limpeza das evidências visuais e cenas duplicadas por execuções antigas do Scanner.
- análise visual: OpenCV (rostos) e PySceneDetect passam a entrar no detector local por padrão; novo adapter InsightFace gera assinatura facial (embedding) para reconhecer a mesma pessoa entre tomadas, gravada como evidência visual no banco.
- corrigido: métricas de fala (energia, pitch, velocidade) agora gravam nas colunas dedicadas, não só no JSON; a view fala+visual passa a casar por vídeo e tempo, já que o mesmo arquivo entra na timeline como clipes distintos de vídeo e áudio; views são recriadas a cada abertura do banco para uma correção de consulta chegar a bancos já existentes.
- reordenadas as abas do painel CEP para Scanner, Refinar e Editar vídeo

Resumo:
- 24 arquivos alterados
- 9 novos
- 15 modificados
- 0 removidos

 15 files changed, 872 insertions(+), 29 deletions(-)

Arquivos:
  - .jhonny/analises.db
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/engine/aplicar_plano_de_edicao.py
  - code/engine/integracoes/visual/README.md
  - code/engine/integracoes/visual/__init__.py
  - code/engine/integracoes/visual/analisadores.py
  - code/engine/persistencia/__init__.py
  - code/engine/persistencia/esquema.py
  - code/engine/persistencia/repositorio_de_analises_sqlite.py
  - code/engine/persistencia/repositorio_de_retakes_sqlite.py
  - code/engine/requirements-visual.txt
  - code/engine/scanner/configuracao_visual.py
  - code/engine/scanner/visual.py
  - code/engine/testes/test_analise_visual_local.py
  - .jhonny/analises.db.pos-scanner-084841
  - code/engine/integracoes/embeddings/
  - code/engine/limpar_duplicatas.py
  - code/engine/persistencia/busca_de_conteudo.py
  - code/engine/persistencia/enunciados.py
  - code/engine/persistencia/ingestao_de_voz.py
  - code/engine/persistencia/limpeza.py
  - code/engine/persistencia/repositorio_de_planos.py
  - code/engine/testes/test_busca_de_conteudo.py
2026-09-10 08:58:22 -04:00

8.0 KiB

Análise visual local

Configuração no painel

A configuração do Scanner é apresentada na aba Scanner do painel CEP em code/cep-plugin/. O perfil salvo segue o contrato versionado de ConfiguracaoVisualDoScanner; ele define amostragem, faixas, recursos Vision, cenas, continuidade, reenquadramento e interpretação antes de montar os adapters.

Acesso à timeline do Premiere

Quando a análise precisar ler a timeline, a sequência ativa, as faixas ou os clipes do Premiere, use sempre a classe existente engine.integracoes.premiere.leitura.AcessoAoEditor. O módulo visual não deve criar chamadas MCP, abrir processos do Premiere ou acessar o bridge diretamente.

O acesso deve seguir esta composição:

from engine.integracoes.premiere.leitura import AcessoAoEditor, AcessoATimeline
from engine.scanner import DescobertaDaTimeline
from engine.integracoes.premiere.conversores import ConversorDeTimeline

acesso_ao_editor = AcessoAoEditor(AcessoATimeline(cliente_mcp))
descoberta = DescobertaDaTimeline(acesso_ao_editor, ConversorDeTimeline())

Depois, a timeline convertida entra no ContextoDeAnalise e o Scanner executa AnaliseVisualDaTimeline. A classe de acesso isola o MCP e preserva a separação entre a integração com o Premiere e os analyzers locais.

Não duplicar esse acesso em novos adapters ou analyzers. Para testes, injetar um fake de AcessoAoEditor/AcessoATimeline ou usar uma timeline de domínio pronta.

Captura para análise visual

A análise visual não exporta um frame renderizado pelo Premiere. Para cada clipe de vídeo, o fluxo usa os campos retornados pelo MCP em get_active_sequence:

  1. sourceFile identifica o arquivo original do projectItem.
  2. inPoint e outPoint delimitam o trecho usado pelo clipe.
  3. O extrator abre sourceFile localmente e amostra o primeiro frame do trecho, usando inPoint como tempo inicial na origem.
  4. Vision/OpenCV/ONNX recebem esse frame persistido, mantendo o timestamp de origem; nenhum frame é exportado da timeline do Premiere.

Portanto, start/end são tempos da timeline e inPoint/outPoint são tempos do arquivo original. Não misturar esses relógios ao analisar um clipe.

O Scanner usa apenas as interfaces em contratos.py. As bibliotecas externas ficam em adapters concretos, para que possam ser habilitadas, substituídas ou testadas isoladamente.

Papel Adapter
Extrair frames ExtratorDeQuadrosOpenCV
Medir qualidade AnalisadorDeQualidadeOpenCV
Rosto e olhos visíveis AnalisadorDeRostosOpenCV
Composição e área para legendas AnalisadorDeComposicaoOpenCV
Tremor/movimento de câmera AnalisadorDeTremorOpenCV
Continuidade e frame congelado AnalisadorDeContinuidadeOpenCV
Detectar objetos AnalisadorDeObjetosONNX
Detectar pose e mãos AnalisadorDePoseMediaPipe
Reconhecer a mesma pessoa entre tomadas (assinatura facial) AnalisadorDeRostosInsightFace
OCR e faces macOS AnalisadorAppleVision
Vision + Apple Intelligence (Swift isolado) AnalisadorAppleVisionNativo
Similaridade temporal por feature print AnalisadorSequenciaAppleVisionNativo
Extrair frames para Vision sem OpenCV ExtratorDeQuadrosFFmpeg
Detectar cenas DetectorDeCenasPySceneDetect

AnalisadorDeObjetosONNX exige dois adapters específicos do modelo: preparar(imagem, entradas) e decodificar(saidas, quadro). Isso mantém os detalhes de cada arquivo ONNX fora do Scanner e permite trocar de modelo sem alterar a interface do domínio.

AnalisadorDePoseMediaPipe recebe caminhos explícitos para os arquivos .task de pose e mãos. Os modelos ficam em /Volumes/Merongo/SISTEMAS/MODELOSIA/mediapipe/ e não são acoplados ao pacote Python. Ele executa em subprocesso: falhas nativas do MediaPipe são contidas e retornam como indisponibilidade do adapter, sem encerrar o processo do Scanner.

AnalisadorDeRostosOpenCV usa os arquivos locais haarcascade_frontalface_default.xml e haarcascade_eye.xml. Quando a distribuição do OpenCV não os incluir, forneça diretorio_de_modelos apontando para a pasta que os contém. Ele entra automaticamente no detector local (criar_detector_visual_local) quando "faces" está em recursos_vision (padrão do perfil).

AnalisadorDeRostosInsightFace resolve o que nem o OpenCV nem o Apple Vision fazem: reconhecer que o rosto de um clipe é a mesma pessoa de outro clipe. Ele devolve duas evidências por rosto — rosto (mesma forma de bounding box dos outros adapters) e identidade_facial (com assinatura_facial, um vetor de 512 posições, mais idade_aproximada/genero_aparente quando o modelo os estimar). Aceita tanto o frame decodificado em quadro.imagem (pipeline OpenCV) quanto um frame persistido em quadro.caminho (pipeline Apple Vision/FFmpeg), lendo o PNG com OpenCV nesse segundo caso. Por ser mais pesado (baixa o modelo buffalo_l na primeira execução), só entra nos detectores locais e no detector Apple Vision quando perfil.identidade_facial=True — desligado por padrão.

AnalisadorAppleVisionNativo é a opção Apple recomendada. Seu runner Swift executa faces/landmarks, qualidade facial, pessoas, pose, mãos, OCR, classificação e estética de forma independente. A interpretação editorial pelo FoundationModels só é criada a partir dessas evidências e é salva em separado. Falhas nativas por recurso viram diagnostico_apple_vision, sem derrubar o Scanner nem descartar os fatos que funcionaram.

Além de rostos, pessoas, pose, mãos, OCR, categorias e estética, o runner Apple retorna códigos/QR, horizonte, retângulos, densidade de contornos, ocupação da máscara de pessoas e similaridade visual entre frames. Os valores são fatos normalizados; descrição, contexto e ação devem ser derivados depois, a partir dessas evidências temporizadas.

Montagem

from engine.integracoes.visual import (
    AnalisadorDeQualidadeOpenCV,
    AnalisadorDeRostosOpenCV,
    AnalisadorDeComposicaoOpenCV,
    AnalisadorDeTremorOpenCV,
    AnalisadorDeContinuidadeOpenCV,
    DetectorDeCenasPySceneDetect,
    ExtratorDeQuadrosOpenCV,
)
from engine.scanner.visual import DetectorDeCenas

detector = DetectorDeCenas(
    ExtratorDeQuadrosOpenCV(intervalo_em_segundos=1.0, diretorio_de_cache=".frames"),
    analisadores_de_frame=[
        AnalisadorDeQualidadeOpenCV(), AnalisadorDeRostosOpenCV(),
        AnalisadorDeComposicaoOpenCV(),
    ],
    analisadores_de_sequencia=[
        AnalisadorDeTremorOpenCV(), AnalisadorDeContinuidadeOpenCV(),
    ],
    detectores_de_intervalo=[DetectorDeCenasPySceneDetect()],
)

Depois, passe esse DetectorDeCenas para AnaliseVisualDaTimeline ao montar o PipelineDoScanner.

Para o caminho local padrão, a montagem pode ser reduzida a:

from engine.scanner import AnaliseVisualDaTimeline, PipelineDoScanner, criar_detector_visual_local

pipeline = PipelineDoScanner([AnaliseVisualDaTimeline(criar_detector_visual_local())])
contexto = pipeline.executar(contexto)

O resultado fica em contexto.caracteristicas_visuais (por clipe), contexto.cenas_visuais (cenas com observações) e contexto.avisos. Quando OpenCV/FFmpeg ou outro adapter opcional não estiver disponível, o clipe é marcado com disponivel=False e os demais continuam sendo processados.

Montagem recomendada para Apple Vision

from engine.scanner import AnaliseVisualDaTimeline, PipelineDoScanner, criar_detector_apple_vision

pipeline = PipelineDoScanner([
    AnaliseVisualDaTimeline(criar_detector_apple_vision(intervalo_em_segundos=1.0)),
])

Esse detector extrai PNGs do arquivo original com FFmpeg, usando o intervalo inPoint/outPoint do clipe, e não exporta imagens renderizadas pelo Premiere. Ele também recua a amostra no fim de vídeos muito curtos quando não há um frame decodificável exatamente no timestamp solicitado.

Os analyzers de sequência não tentam concluir a intenção de uma pessoa. Eles retornam indícios temporais (possivel_tremor, possivel_descontinuidade e possivel_frame_congelado) para que a camada editorial decida como tratá-los.