Files
jhonny-editor/code/engine/arquitetura/scanner.md
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

14 KiB

Para começar, eu não criaria todas as classes de análise imediatamente. O ideal é definir primeiro as classes básicas e estruturais do módulo scanner. Elas formarão a base sobre a qual as análises específicas serão construídas.

Eu dividiria em quatro grupos:

  1. Coordenação do processo.
  2. Representação dos dados.
  3. Contratos das análises.
  4. Controle de execução e resultados.

Estrutura básica inicial

scanner/
├── __init__.py
│
├── coordenacao/
│   ├── __init__.py
│   ├── analisador_de_timeline.py
│   ├── pipeline_do_scanner.py
│   └── contexto_de_analise.py
│
├── contratos/
│   ├── __init__.py
│   └── analisador.py
│
├── modelos/
│   ├── __init__.py
│   ├── resultado_da_analise.py
│   ├── status_da_analise.py
│   └── erro_de_analise.py
│
└── configuracao/
    ├── __init__.py
    └── configuracao_do_scanner.py

A seguir está o papel detalhado de cada classe.


1. AnalisadorDeTimeline

Arquivo:

scanner/coordenacao/analisador_de_timeline.py

Papel principal

É a classe de entrada do scanner.

Ela representa o processo completo de análise de uma timeline. O restante do sistema deverá utilizar essa classe para iniciar uma análise, sem precisar conhecer todas as etapas internas.

O que deve fazer

  • Receber a timeline que será analisada.
  • Receber as configurações do scanner.
  • Receber ou montar o pipeline.
  • Criar o contexto inicial.
  • Iniciar a execução do pipeline.
  • Acompanhar o status geral da análise.
  • Retornar o resultado final.
  • Permitir informar progresso.
  • Permitir cancelamento futuro.
  • Tratar falhas gerais do processo.
  • Registrar informações gerais da execução.
  • Identificar se a análise já foi realizada anteriormente.
  • Permitir retomar uma análise interrompida, quando essa funcionalidade existir.

O que não deve fazer

  • Extrair áudio diretamente.
  • Executar transcrição.
  • Detectar cenas.
  • Analisar imagens.
  • Detectar retakes.
  • Implementar chamadas para OpenCV, FFmpeg, Whisper ou APIs.
  • Decidir quais trechos serão cortados.
  • Alterar a timeline.

Exemplo conceitual

class AnalisadorDeTimeline:
    """Ponto de entrada para a análise completa de uma timeline."""

    def __init__(self, pipeline, configuracao):
        self.pipeline = pipeline
        self.configuracao = configuracao

    def analisar(self, timeline):
        """Inicia a análise da timeline e retorna o resultado."""
        contexto = ContextoDeAnalise(
            timeline=timeline,
            configuracao=self.configuracao
        )

        return self.pipeline.executar(contexto)

2. PipelineDoScanner

Arquivo:

scanner/coordenacao/pipeline_do_scanner.py

Papel principal

É a classe responsável por controlar a ordem de execução das análises.

Ela não sabe como cada análise funciona. Apenas sabe quais análises precisam ser executadas e em qual sequência.

O que deve fazer

  • Receber uma lista de análises.
  • Executar as análises na ordem configurada.
  • Entregar o contexto para cada análise.
  • Atualizar o status da execução.
  • Registrar a análise atualmente em execução.
  • Registrar análises concluídas.
  • Identificar falhas.
  • Permitir interromper o processo.
  • Permitir executar somente determinadas análises.
  • Permitir ignorar análises opcionais.
  • Permitir futuramente executar análises independentes em paralelo.
  • Garantir que uma análise só seja executada quando suas dependências estiverem disponíveis.
  • Retornar o contexto atualizado.

Exemplo

class PipelineDoScanner:
    """Executa as análises do scanner em uma ordem definida."""

    def __init__(self, analises):
        self.analises = analises

    def executar(self, contexto):
        """Executa todas as análises configuradas."""
        for analise in self.analises:
            contexto = analise.executar(contexto)

        return contexto

O que não deve fazer

  • Conhecer detalhes dos providers.
  • Saber como o áudio é extraído.
  • Saber como o Whisper funciona.
  • Implementar algoritmos de detecção de cenas.
  • Tomar decisões de edição.
  • Manipular diretamente a timeline.

3. ContextoDeAnalise

Arquivo:

scanner/coordenacao/contexto_de_analise.py

Papel principal

É o objeto que transporta os dados entre as análises.

Cada análise recebe o mesmo contexto, lê os dados de que precisa e adiciona seus próprios resultados.

Ele evita que cada classe precise receber dezenas de parâmetros separados.

O que deve armazenar

Dados da origem

  • Timeline analisada.
  • Identificador da análise.
  • Data e hora de início.
  • Configuração utilizada.
  • Versão do scanner.
  • Identificador do projeto ou sequência.

Dados descobertos

  • Sequências.
  • Faixas de vídeo.
  • Faixas de áudio.
  • Clipes.
  • Arquivos relacionados.
  • Relações entre áudio e vídeo.
  • Elementos desativados.
  • Elementos offline.

Dados técnicos

  • Metadados dos arquivos.
  • Duração.
  • Resolução.
  • Taxa de quadros.
  • Codecs.
  • Timecodes.
  • Informações de áudio.

Dados processados

  • Áudios extraídos.
  • Quadros extraídos.
  • Transcrições.
  • Características visuais.
  • Características de áudio.
  • Cenas detectadas.
  • Eventos detectados.
  • Possíveis retakes.

Controle da execução

  • Status atual.
  • Análise em execução.
  • Análises concluídas.
  • Erros.
  • Avisos.
  • Percentual de progresso.
  • Tempo de execução.

O que não deve fazer

  • Executar análises.
  • Chamar providers.
  • Implementar algoritmos.
  • Decidir cortes.
  • Alterar a timeline.
  • Fazer persistência diretamente.

Exemplo

class ContextoDeAnalise:
    """Armazena os dados compartilhados durante a análise."""

    def __init__(self, timeline, configuracao):
        self.timeline = timeline
        self.configuracao = configuracao

        self.clipes = []
        self.arquivos = []
        self.metadados = {}
        self.audios = {}
        self.quadros = {}
        self.transcricoes = {}
        self.cenas = []
        self.eventos = []
        self.retakes = []

        self.status = "nao_iniciada"
        self.analise_atual = None
        self.analises_concluidas = []
        self.erros = []
        self.avisos = []

4. Analisador

Arquivo:

scanner/contratos/analisador.py

Papel principal

É o contrato comum das classes de análise.

Ele define que toda análise precisa possuir um método padronizado, como executar().

Não é uma análise concreta. É uma classe-base ou interface.

O que deve definir

  • Método executar(contexto).
  • Identificação da análise.
  • Nome amigável.
  • Dependências, quando necessário.
  • Indicação se a análise é obrigatória ou opcional.
  • Validação básica do contexto.
  • Possibilidade de informar progresso.
  • Possibilidade de verificar cancelamento.

Exemplo

from abc import ABC, abstractmethod


class Analisador(ABC):
    """Define o contrato comum das análises do scanner."""

    nome = "analisador"

    @abstractmethod
    def executar(self, contexto):
        """Executa a análise sobre o contexto."""
        raise NotImplementedError

    def validar_contexto(self, contexto):
        """Valida se o contexto possui os dados necessários."""
        return True

As classes específicas poderão seguir esse contrato:

class DeteccaoDeCenas(Analisador):
    """Detecta cenas utilizando um provider especializado."""

    nome = "deteccao_de_cenas"

    def executar(self, contexto):
        """Executa a detecção de cenas."""
        return contexto

5. ResultadoDaAnalise

Arquivo:

scanner/modelos/resultado_da_analise.py

Papel principal

Representa o resultado produzido por uma análise individual.

Ele será útil para que o pipeline saiba se uma análise terminou corretamente, quais dados produziu e se houve problemas.

O que deve armazenar

  • Nome da análise.
  • Status.
  • Data e hora de início.
  • Data e hora de término.
  • Duração.
  • Quantidade de itens processados.
  • Quantidade de resultados produzidos.
  • Avisos.
  • Erros.
  • Dados resumidos.
  • Identificador da execução.

Exemplo

class ResultadoDaAnalise:
    """Representa o resultado de uma análise individual."""

    def __init__(self, nome, status="concluida"):
        self.nome = nome
        self.status = status
        self.inicio = None
        self.fim = None
        self.duracao = None
        self.itens_processados = 0
        self.resultados_produzidos = 0
        self.avisos = []
        self.erros = []
        self.dados = {}

Exemplo de resultado

{
  "nome": "deteccao_de_cenas",
  "status": "concluida",
  "itens_processados": 48,
  "resultados_produzidos": 17,
  "duracao": 12.4,
  "avisos": [],
  "erros": []
}

6. StatusDaAnalise

Arquivo:

scanner/modelos/status_da_analise.py

Papel principal

Centraliza os estados possíveis de uma análise.

Isso evita que cada classe utilize textos diferentes para representar o mesmo estado.

Estados possíveis

NAO_INICIADA
AGUARDANDO
EM_EXECUCAO
CONCLUIDA
CONCLUIDA_COM_AVISOS
FALHOU
CANCELADA
IGNORADA

Exemplo

from enum import Enum


class StatusDaAnalise(Enum):
    """Define os estados possíveis de uma análise."""

    NAO_INICIADA = "nao_iniciada"
    AGUARDANDO = "aguardando"
    EM_EXECUCAO = "em_execucao"
    CONCLUIDA = "concluida"
    CONCLUIDA_COM_AVISOS = "concluida_com_avisos"
    FALHOU = "falhou"
    CANCELADA = "cancelada"
    IGNORADA = "ignorada"

7. ErroDeAnalise

Arquivo:

scanner/modelos/erro_de_analise.py

Papel principal

Representa erros ocorridos durante o processo de análise de maneira estruturada.

Em vez de armazenar apenas uma mensagem solta, o sistema poderá saber exatamente onde e por que o erro aconteceu.

O que deve armazenar

  • Nome da análise.
  • Código do erro.
  • Mensagem.
  • Detalhes técnicos.
  • Arquivo relacionado.
  • Clipe relacionado.
  • Provider envolvido.
  • Data e hora.
  • Indicação se o erro interrompe o pipeline.
  • Sugestão de recuperação, quando possível.

Exemplo

class ErroDeAnalise:
    """Representa um erro ocorrido durante uma análise."""

    def __init__(
        self,
        mensagem,
        codigo=None,
        nome_da_analise=None,
        arquivo=None,
        interrompe_pipeline=False
    ):
        self.mensagem = mensagem
        self.codigo = codigo
        self.nome_da_analise = nome_da_analise
        self.arquivo = arquivo
        self.interrompe_pipeline = interrompe_pipeline

8. ConfiguracaoDoScanner

Arquivo:

scanner/configuracao/configuracao_do_scanner.py

Papel principal

Armazena as configurações que controlam como o scanner deverá funcionar.

Ela não deve conter regras específicas de um provider. As configurações dos providers podem ficar em seus próprios módulos.

O que deve controlar

  • Quais análises serão executadas.
  • Ordem das análises.
  • Análises obrigatórias.
  • Análises opcionais.
  • Uso de cache.
  • Uso de arquivos temporários.
  • Diretório de trabalho.
  • Nível de detalhamento.
  • Quantidade de quadros extraídos.
  • Intervalo de amostragem.
  • Limite de duração.
  • Execução paralela.
  • Comportamento diante de erros.
  • Persistência automática.
  • Retomada de análise.
  • Nível de logging.

Exemplo

class ConfiguracaoDoScanner:
    """Define as configurações gerais do scanner."""

    def __init__(self):
        self.executar_transcricao = True
        self.executar_analise_visual = True
        self.executar_deteccao_de_cenas = True
        self.executar_deteccao_de_retakes = True
        self.usar_cache = True
        self.continuar_em_caso_de_erro = True
        self.salvar_resultados_automaticamente = True

Como essas classes se relacionam

AnalisadorDeTimeline
        ↓
PipelineDoScanner
        ↓
Analisador
        ↓
Classes específicas de análise
        ↓
ContextoDeAnalise
        ↓
ResultadoDaAnalise

A configuração controla o comportamento:

ConfiguracaoDoScanner
        ↓
AnalisadorDeTimeline
        ↓
PipelineDoScanner

E os erros são registrados durante a execução:

Classe de análise
        ↓
ErroDeAnalise
        ↓
ContextoDeAnalise
        ↓
ResultadoDaAnalise

Fluxo de execução

1. AnalisadorDeTimeline recebe a timeline.
2. Cria o ContextoDeAnalise.
3. Carrega a ConfiguracaoDoScanner.
4. Monta o PipelineDoScanner.
5. O pipeline executa cada Analisador.
6. Cada análise lê e atualiza o contexto.
7. Cada análise produz um ResultadoDaAnalise.
8. Erros e avisos são registrados.
9. O contexto final é retornado.
10. O resultado poderá ser salvo pelo módulo de persistência.

Classes que eu criaria primeiro

Para a primeira implementação, começaria somente com estas:

scanner/
├── coordenacao/
│   ├── analisador_de_timeline.py
│   ├── pipeline_do_scanner.py
│   └── contexto_de_analise.py
│
├── contratos/
│   └── analisador.py
│
└── modelos/
    ├── resultado_da_analise.py
    └── status_da_analise.py

Depois acrescentaria:

ErroDeAnalise
ConfiguracaoDoScanner

E somente então começaria a implementar as análises concretas:

DescobertaDaTimeline
DescobertaDeClipes
DescobertaDeArquivos
ExtracaoDeMetadados
ExtracaoDeAudio
TranscricaoDeAudio
ExtracaoDeQuadros
AnaliseVisual
AnaliseDeAudio
DeteccaoDeCenas
DeteccaoDeEventos
DeteccaoDeRetakes
PersistenciaDaAnalise

A ideia central é:

As classes básicas não analisam o vídeo diretamente. Elas criam a estrutura que permite que todas as análises funcionem de forma organizada, substituível, testável e independente dos providers.