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

644 lines
14 KiB
Markdown

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
```text
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:
```text
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
```python
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:
```text
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
```python
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:
```text
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
```python
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:
```text
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
```python
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:
```python
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:
```text
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
```python
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
```json
{
"nome": "deteccao_de_cenas",
"status": "concluida",
"itens_processados": 48,
"resultados_produzidos": 17,
"duracao": 12.4,
"avisos": [],
"erros": []
}
```
---
# 6. `StatusDaAnalise`
Arquivo:
```text
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
```text
NAO_INICIADA
AGUARDANDO
EM_EXECUCAO
CONCLUIDA
CONCLUIDA_COM_AVISOS
FALHOU
CANCELADA
IGNORADA
```
## Exemplo
```python
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:
```text
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
```python
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:
```text
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
```python
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
```text
AnalisadorDeTimeline
↓
PipelineDoScanner
↓
Analisador
↓
Classes específicas de análise
↓
ContextoDeAnalise
↓
ResultadoDaAnalise
```
A configuração controla o comportamento:
```text
ConfiguracaoDoScanner
↓
AnalisadorDeTimeline
↓
PipelineDoScanner
```
E os erros são registrados durante a execução:
```text
Classe de análise
↓
ErroDeAnalise
↓
ContextoDeAnalise
↓
ResultadoDaAnalise
```
# Fluxo de execução
```text
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:
```text
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:
```text
ErroDeAnalise
ConfiguracaoDoScanner
```
E somente então começaria a implementar as análises concretas:
```text
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.**