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
This commit is contained in:
João Henrique
2026-09-08 09:59:31 -04:00
commit b541f502ba
1507 changed files with 387650 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
# Arquitetura do Sistema
Esta pasta concentra a especificação arquitetural do novo sistema Python orientado a objetos.
## Objetivo
Documentar previamente:
- a estrutura geral do sistema;
- os módulos e submódulos;
- as responsabilidades de cada classe;
- o que cada classe não deve fazer;
- os fluxos entre os módulos;
- as regras de dependência e integração;
- as decisões arquiteturais do projeto.
## Regra de nomenclatura
Todos os nomes de módulos, classes, métodos, funções e variáveis serão sempre em PT-BR.
## Organização da documentação
Cada módulo principal deverá possuir um documento próprio nesta pasta.
```text
arquitetura/
├── README.md
├── scanner.md
├── integracao-com-premiere.md
├── leitura-da-timeline-via-mcp.md
├── plano-primeira-etapa-scanner-e-mcp.md
├── planos-proximas-etapas.md
├── analisador-de-conteudo.md
├── motor-de-decisao.md
├── gerador-de-plano-de-edicao.md
├── aplicador-de-plano.md
├── validador.md
├── providers-de-ia.md
├── modelo-de-dominio.md
├── persistencia.md
├── configuracao.md
├── logging.md
└── testes.md
```
Os documentos serão criados conforme cada módulo for projetado. Não devemos escrever código de implementação antes de definir sua arquitetura neste diretório.
## Princípios gerais
1. O domínio deve ser independente de infraestrutura e de ferramentas externas.
2. Cada módulo deve ter uma responsabilidade clara.
3. As dependências devem ser recebidas por abstrações bem definidas.
4. Integrações externas devem ser implementadas por adaptadores substituíveis.
5. O fluxo entre módulos deve ser explícito e documentado.
6. Cada classe deve declarar suas responsabilidades e suas proibições.
7. O sistema deve ser testável sem depender de serviços externos reais.
@@ -0,0 +1,682 @@
Sim. **O ideal é tratar o MCP como um módulo completo de integração com o Premiere**, e não como uma única classe responsável por tudo.
O MCP será utilizado para várias finalidades:
* Ler a timeline ativa;
* Ler sequências, faixas e clipes;
* Obter propriedades dos clipes;
* Criar, mover, cortar ou excluir elementos;
* Aplicar alterações na timeline;
* Executar comandos no Premiere;
* Consultar o estado atual do projeto;
* Validar se uma operação foi executada corretamente.
Por isso, uma única classe como `ClienteMCP` ficaria sobrecarregada rapidamente.
## Estrutura recomendada
```text
integracoes/
└── premiere/
├── __init__.py
│
├── cliente_mcp.py
├── sessao_mcp.py
├── erros_mcp.py
│
├── leitura/
│ ├── acesso_a_timeline.py
│ ├── acesso_a_sequencia.py
│ ├── acesso_a_faixas.py
│ └── acesso_a_clipes.py
│
├── escrita/
│ ├── executor_de_comandos.py
│ ├── manipulador_de_clipes.py
│ ├── manipulador_de_timeline.py
│ └── aplicador_de_operacoes.py
│
├── conversores/
│ ├── conversor_de_timeline.py
│ ├── conversor_de_clipes.py
│ └── conversor_de_respostas.py
│
└── contratos/
├── acesso_ao_editor.py
└── executor_do_editor.py
```
A ideia principal é separar:
> **Comunicação com o MCP**, **leitura do Premiere**, **execução de comandos** e **conversão dos dados**.
---
# 1. `ClienteMCP`
Arquivo:
```text
integracoes/premiere/cliente_mcp.py
```
Classe:
```python
class ClienteMCP:
"""Responsável pela comunicação técnica com o servidor MCP do Premiere."""
```
Essa classe deve cuidar somente da comunicação.
Responsabilidades:
* Abrir conexão;
* Encerrar conexão;
* Enviar uma chamada;
* Receber a resposta;
* Controlar timeout;
* Tratar erros de comunicação;
* Registrar logs;
* Identificar falhas de conexão;
* Possivelmente reconectar.
Exemplo conceitual:
```python
class ClienteMCP:
"""Executa chamadas técnicas contra o servidor MCP."""
def conectar(self) -> None:
"""Estabelece a conexão com o MCP."""
def desconectar(self) -> None:
"""Encerra a conexão com o MCP."""
def chamar(self, nome_da_ferramenta: str, argumentos: dict) -> dict:
"""Executa uma ferramenta MCP e retorna sua resposta."""
```
Ele **não deve saber o que é uma timeline, um clipe ou um retake**.
Para ele, existe apenas:
```text
chamar ferramenta → receber resposta
```
---
# 2. `SessaoMCP`
Arquivo:
```text
integracoes/premiere/sessao_mcp.py
```
Classe:
```python
class SessaoMCP:
"""Controla o estado de uma sessão de comunicação com o Premiere."""
```
Pode ser útil para armazenar:
* Identificação da sessão;
* Estado da conexão;
* Projeto atual;
* Sequência ativa;
* Última operação executada;
* Ferramentas disponíveis;
* Informações de capacidade do MCP.
Exemplo:
```python
class SessaoMCP:
"""Representa o estado atual da integração com o Premiere."""
def __init__(self):
self.conectado = False
self.projeto_atual = None
self.sequencia_ativa = None
```
Essa classe não é obrigatória na primeira versão, mas será útil quando a integração crescer.
---
# 3. Módulo de leitura
O módulo de leitura seria responsável por transformar comandos técnicos do MCP em operações compreensíveis pelo sistema.
## `AcessoATimeline`
Arquivo:
```text
integracoes/premiere/leitura/acesso_a_timeline.py
```
Classe:
```python
class AcessoATimeline:
"""Fornece operações de leitura da timeline do Premiere."""
```
Métodos possíveis:
```python
class AcessoATimeline:
"""Lê a estrutura da timeline ativa."""
def obter_timeline_ativa(self):
"""Retorna os dados da timeline ativa."""
def obter_sequencia_ativa(self):
"""Retorna a sequência atualmente selecionada."""
def obter_faixas(self):
"""Retorna as faixas de vídeo e áudio."""
def obter_clipes(self):
"""Retorna os clipes presentes na timeline."""
def obter_detalhes_do_clipe(self, identificador_do_clipe):
"""Retorna os detalhes de um clipe específico."""
```
O fluxo seria:
```text
AcessoATimeline
↓
ClienteMCP
↓
MCP do Premiere
```
O scanner chamaria:
```python
timeline = acesso_a_timeline.obter_timeline_ativa()
```
E não:
```python
cliente_mcp.chamar("alguma_ferramenta_interna", {...})
```
Isso é importante porque o restante do sistema não deve conhecer os detalhes do MCP.
---
## Outras classes de leitura
Podemos dividir conforme a complexidade:
```text
leitura/
├── acesso_a_timeline.py
├── acesso_a_sequencia.py
├── acesso_a_faixas.py
├── acesso_a_clipes.py
├── acesso_a_projeto.py
└── acesso_a_itens_de_midia.py
```
Entretanto, no início, não é necessário criar todas imediatamente.
Podemos começar com:
```text
AcessoAoEditor
```
e depois dividir quando a classe crescer demais.
---
# 4. `AcessoAoEditor`
Eu recomendaria inicialmente uma classe de fachada chamada `AcessoAoEditor`.
Arquivo:
```text
integracoes/premiere/acesso_ao_editor.py
```
Classe:
```python
class AcessoAoEditor:
"""Oferece uma interface simplificada para consultar o Premiere."""
```
Ela funcionaria como uma porta de entrada para as operações de leitura:
```python
class AcessoAoEditor:
"""Centraliza o acesso estruturado aos dados do Premiere."""
def __init__(self, acesso_a_timeline, acesso_a_clipes):
self.acesso_a_timeline = acesso_a_timeline
self.acesso_a_clipes = acesso_a_clipes
def obter_timeline_ativa(self):
"""Obtém a timeline ativa."""
return self.acesso_a_timeline.obter_timeline_ativa()
def obter_clipes(self):
"""Obtém os clipes da timeline ativa."""
return self.acesso_a_clipes.obter_clipes()
```
Assim, o scanner dependeria de:
```python
AcessoAoEditor
```
e não diretamente de:
```python
ClienteMCP
```
---
# 5. Módulo de escrita
A leitura e a escrita devem ser separadas.
```text
integracoes/premiere/
├── leitura/
└── escrita/
```
Isso evita misturar:
* Consultar dados;
* Alterar dados;
* Executar comandos destrutivos.
## `ExecutorDeComandos`
Arquivo:
```text
integracoes/premiere/escrita/executor_de_comandos.py
```
Classe:
```python
class ExecutorDeComandos:
"""Executa comandos de alteração no Premiere por meio do MCP."""
```
Responsabilidades:
* Executar uma operação;
* Enviar parâmetros;
* Receber resultado;
* Identificar falhas;
* Retornar confirmação da operação.
Exemplo:
```python
class ExecutorDeComandos:
"""Executa comandos no editor."""
def executar(self, nome_do_comando: str, argumentos: dict):
"""Executa um comando no Premiere."""
```
Mas essa classe não deveria decidir **qual comando deve ser executado**. Ela apenas executa o comando que recebeu.
---
## `AplicadorDeOperacoes`
Arquivo:
```text
integracoes/premiere/escrita/aplicador_de_operacoes.py
```
Classe:
```python
class AplicadorDeOperacoes:
"""Aplica operações de edição estruturadas na timeline."""
```
Essa classe recebe operações já definidas pelo plano de edição:
```python
class AplicadorDeOperacoes:
"""Aplica operações de edição no Premiere."""
def aplicar_corte(self, operacao):
"""Aplica uma operação de corte."""
def mover_clipe(self, operacao):
"""Move um clipe na timeline."""
def excluir_clipe(self, operacao):
"""Exclui um clipe da timeline."""
def aplicar_plano(self, plano):
"""Aplica todas as operações de um plano de edição."""
```
O fluxo seria:
```text
AplicadorDeOperacoes
↓
ExecutorDeComandos
↓
ClienteMCP
↓
MCP do Premiere
```
---
# 6. `ConversorDeTimeline`
Arquivo:
```text
integracoes/premiere/conversores/conversor_de_timeline.py
```
Classe:
```python
class ConversorDeTimeline:
"""Converte os dados brutos do Premiere para o modelo interno do sistema."""
```
Essa classe é muito importante.
O MCP pode retornar dados em um formato específico, por exemplo:
```json
{
"sequence": {
"name": "Sequência 01",
"timebase": 25
},
"tracks": [],
"clips": []
}
```
Mas o sistema não deveria depender diretamente desse formato.
O conversor transforma isso em objetos próprios:
```python
class ConversorDeTimeline:
"""Converte uma resposta do Premiere para o domínio interno."""
def converter(self, dados_brutos):
"""Converte os dados brutos em uma timeline do sistema."""
```
Assim, se futuramente o MCP mudar, somente a integração e os conversores precisarão ser ajustados.
O restante do sistema continua funcionando.
---
# 7. Contratos para desacoplar o sistema
O ideal é criar contratos para que o scanner não dependa de uma implementação específica.
## `AcessoAoEditor`
Arquivo:
```text
integracoes/premiere/contratos/acesso_ao_editor.py
```
Exemplo:
```python
from abc import ABC, abstractmethod
class AcessoAoEditor(ABC):
"""Define as operações de leitura necessárias para acessar um editor."""
@abstractmethod
def obter_timeline_ativa(self):
"""Obtém a timeline ativa do editor."""
raise NotImplementedError
@abstractmethod
def obter_clipes(self):
"""Obtém os clipes da timeline."""
raise NotImplementedError
```
Depois podemos ter:
```text
AcessoAoEditor
├── AcessoAoPremiere
├── AcessoAoOpenCut
└── AcessoAoEditorSimulado
```
O último é especialmente útil para testes.
Por exemplo:
```python
class AcessoAoEditorSimulado(AcessoAoEditor):
"""Fornece dados fictícios para testes sem abrir o Premiere."""
```
---
# 8. Como o scanner usaria isso
A classe `DescobertaDaTimeline` não deveria conhecer MCP.
Ela deveria conhecer apenas uma interface de acesso ao editor.
```python
class DescobertaDaTimeline:
"""Descobre a estrutura da timeline a partir do editor."""
def __init__(self, acesso_ao_editor):
self.acesso_ao_editor = acesso_ao_editor
def executar(self, contexto):
"""Lê a timeline e armazena os dados no contexto."""
timeline = self.acesso_ao_editor.obter_timeline_ativa()
contexto.timeline = timeline
return contexto
```
O encadeamento seria:
```text
DescobertaDaTimeline
↓
AcessoAoPremiere
↓
AcessoATimeline
↓
ClienteMCP
↓
MCP do Premiere
```
Ou, usando uma fachada:
```text
DescobertaDaTimeline
↓
AcessoAoEditor
↓
ClienteMCP
↓
MCP do Premiere
```
---
# 9. Arquitetura completa recomendada
```text
projeto/
│
├── scanner/
│ ├── coordenacao/
│ │ ├── analisador_de_timeline.py
│ │ ├── pipeline_do_scanner.py
│ │ └── contexto_de_analise.py
│ │
│ ├── descoberta/
│ │ ├── descoberta_da_timeline.py
│ │ ├── descoberta_de_clipes.py
│ │ └── descoberta_de_arquivos.py
│ │
│ ├── metadados/
│ ├── audio/
│ ├── transcricao/
│ ├── visual/
│ ├── cenas/
│ └── retakes/
│
├── providers/
│ ├── transcricao/
│ ├── analise_visual/
│ ├── deteccao_de_cenas/
│ └── analise_de_audio/
│
├── integracoes/
│ └── premiere/
│ ├── cliente_mcp.py
│ ├── sessao_mcp.py
│ ├── erros_mcp.py
│ │
│ ├── leitura/
│ │ ├── acesso_a_timeline.py
│ │ ├── acesso_a_sequencia.py
│ │ ├── acesso_a_faixas.py
│ │ └── acesso_a_clipes.py
│ │
│ ├── escrita/
│ │ ├── executor_de_comandos.py
│ │ ├── aplicador_de_operacoes.py
│ │ └── manipulador_de_timeline.py
│ │
│ ├── conversores/
│ │ ├── conversor_de_timeline.py
│ │ ├── conversor_de_clipes.py
│ │ └── conversor_de_respostas.py
│ │
│ └── contratos/
│ ├── acesso_ao_editor.py
│ └── executor_do_editor.py
│
├── dominio/
├── configuracao/
├── persistencia/
└── testes/
```
## Minha recomendação prática
Para a primeira versão, não criaria todas as classes imediatamente. Começaria assim:
```text
integracoes/
└── premiere/
├── cliente_mcp.py
├── acesso_ao_editor.py
├── executor_de_comandos.py
├── conversor_de_timeline.py
└── erros_mcp.py
```
Depois, quando as responsabilidades crescerem:
```text
acesso_ao_editor.py
```
poderá ser dividido em:
```text
leitura/
├── acesso_a_timeline.py
├── acesso_a_clipes.py
└── acesso_a_projeto.py
```
E:
```text
executor_de_comandos.py
```
poderá ser dividido em:
```text
escrita/
├── aplicador_de_operacoes.py
├── manipulador_de_clipes.py
└── manipulador_de_timeline.py
```
## Regra central
A arquitetura deve seguir esta separação:
```text
Scanner
define o que precisa ser analisado
Integração com o Premiere
acessa e altera o editor
Cliente MCP
faz a comunicação técnica
Conversores
transformam dados externos em dados internos
Providers
executam análises usando tecnologias específicas
Motor de decisão
decide o que fazer com os resultados
Aplicador de plano
transforma decisões em operações no editor
```
Portanto, a resposta direta é:
> **MCP deve ser um módulo de integração completo, com `ClienteMCP` como classe de comunicação central, classes especializadas de leitura e escrita, conversores e contratos.** Ele não deve ser uma única classe gigante nem ficar misturado dentro do scanner.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,117 @@
# Plano de leitura de vídeo com tecnologias Apple
## Conclusão
O caminho recomendado é um pipeline híbrido, local e substituível:
1. `FFmpeg` continua extraindo áudio e amostras de vídeo.
2. `Speech` faz a transcrição temporal do áudio no macOS, preferencialmente com `supportsOnDeviceRecognition` e `requiresOnDeviceRecognition` quando disponíveis.
3. `Vision` analisa os quadros: OCR, pessoas/objetos, rostos, códigos, poses e mudanças de cena conforme a necessidade.
4. `FoundationModels` (Apple Intelligence) recebe um pacote compacto de evidências — transcrição, descrições dos quadros, OCR e metadados — e produz resumo, tópicos, classificação e sugestões editoriais estruturadas.
O modelo de linguagem não deve receber o arquivo de vídeo inteiro como entrada direta. A documentação do Foundation Models descreve geração e entendimento de texto, geração estruturada, ferramentas e análise de imagens; a análise de vídeo deve ser orquestrada pelo nosso pipeline, ou por um provider multimodal próprio no futuro.
## O que já existe no Engine
- `engine/scanner/analise.py` já define `ProviderDeTranscricao` e `ProviderDeAnaliseVisual`.
- `engine/scanner/transcricao_da_timeline.py` já divide o resultado por clipe e corrige os offsets das partes.
- `engine/integracoes/midia/extracao_de_audio.py` já gera WAV mono, 16 kHz e blocos de até 600 s.
- `engine/integracoes/apple_speech/` já possui um executável Swift usando `SFSpeechRecognizer` e um provider Python.
- `engine/integracoes/whisper/` fornece fallback local.
O relatório Apple atual confirma que o adaptador está integrado ao fluxo, mas também evidencia uma falha operacional a investigar: a execução reportada não encontrou fala em todos os intervalos. Antes de comparar qualidade, devemos validar permissão, disponibilidade do locale, formato/volume do WAV e se o modo on-device foi realmente ativado.
## Tecnologias disponíveis
### Speech
`SFSpeechRecognizer` aceita arquivos existentes com `SFSpeechURLRecognitionRequest`, fornece segmentos com timestamp e expõe `supportsOnDeviceRecognition`. Há limite documentado para tarefas longas, portanto a divisão existente em blocos é adequada. O provider deve manter os offsets, a confiança e o locale.
### Vision
Vision é a camada Apple para análise de fotos e vídeos. Para o primeiro corte, implementar apenas:
- `RecognizeTextRequest` para texto em tela;
- detecção de pessoas/objetos ou classificação, se a decisão editorial exigir;
- amostragem temporal de quadros e agrupamento de resultados semelhantes;
- detecção de mudança de cena, caso a implementação determinística atual ainda não cubra o caso.
Vision não deve ser chamado em todos os frames. O sampler deve escolher, por exemplo, um frame a cada 1–2 segundos e frames próximos a cortes, mantendo `timestamp`, `confidence` e a origem do frame.
### Foundation Models / Apple Intelligence
`FoundationModels` fornece o LLM local que alimenta Apple Intelligence. É adequado para resumir a transcrição, extrair entidades/tópicos, classificar trechos, sugerir títulos e gerar estruturas Swift com `@Generable`. A disponibilidade precisa ser verificada em runtime por `SystemLanguageModel.default`; Apple Intelligence precisa estar habilitado e o sistema/dispositivo precisa ser compatível.
O contexto deve ser limitado e particionado. A documentação técnica da Apple indica janela de contexto de 4096 tokens para o modelo on-device; enviar o vídeo inteiro ou uma transcrição longa em uma única solicitação não é seguro. O contrato deve prever `truncation`, `modelUnavailable`, `guardrail` e `timeout`.
### App Intents
É uma opção posterior para expor ações do Engine ao Siri/Apple Intelligence — por exemplo, “resumir o clipe selecionado” ou “encontrar trechos em que se fala de X”. Não é a API de leitura do vídeo; é a camada de descoberta e ação.
## Arquitetura proposta
```text
Timeline/clip
├─ AudioExtractor ──> AppleSpeechProvider | WhisperProvider
├─ FrameSampler ────> VisionProvider
└─ MediaEvidenceStore
└─ FoundationModelsProvider
└─ AnalysisResult / EditorialPlan
```
Adicionar interfaces no domínio, mantendo o scanner independente:
```python
class ProviderDeQuadros(Protocol):
def amostrar(self, clipe: Any) -> list[QuadroDeVideo]: ...
class ProviderDeAnaliseSemantica(Protocol):
def interpretar(self, evidencias: PacoteDeEvidencias) -> ResultadoSemantico: ...
```
`QuadroDeVideo` deve conter `timestamp`, caminho temporário ou bytes, dimensões e índice. `EvidenciaDeVideo` deve conter tipo (`transcricao`, `ocr`, `objeto`, `cena`), intervalo temporal, valor, confiança e provider. O resultado do Foundation Models deve ser estruturado e validado antes de entrar em `caracteristicas_visuais`, `cenas` ou plano de edição.
## Implementação em fases
### Fase 1 — endurecer Apple Speech
- Corrigir o build/instalação do executável Swift para o ambiente do usuário.
- Tornar `somente_no_dispositivo=True` a opção explícita de privacidade.
- Capturar stderr, código de saída, locale, disponibilidade e modo efetivo no resultado.
- Testar WAV com fala conhecida em `pt-BR`, inclusive blocos menores que um minuto.
- Comparar Apple Speech, Whisper e Groq usando o mesmo áudio e medir WER, latência e falhas.
### Fase 2 — Vision
- Criar um pequeno helper Swift ou um app/CLI macOS que receba vídeo, timestamps e operações.
- Usar AVFoundation para ler frames; usar Vision por frame.
- Devolver JSON versionado, com timestamp absoluto e confiança.
- Adicionar testes com fixtures de texto em tela, pessoa e quadro sem conteúdo.
### Fase 3 — Foundation Models
- Criar um processo Swift residente (mais eficiente que iniciar um processo por trecho).
- Receber JSON de evidências via stdin/stdout ou IPC existente.
- Usar `LanguageModelSession` e geração guiada para um `ResultadoSemantico` fixo.
- Fazer chunking da transcrição e uma segunda etapa de consolidação.
- Persistir prompt/model-version/evidence revision para reprodutibilidade.
### Fase 4 — integração editorial
- Alimentar o `EditorialContextPack` com evidências citáveis e intervalos temporais.
- Manter análise e plano como operações read-only até validação.
- Só depois conectar resultados a rough-cut, marcadores ou legendas via APIs já existentes do Premiere.
## Decisão recomendada agora
Implementar primeiro `AppleSpeechProvider` robusto e `VisionEvidenceProvider`; deixar `FoundationModelsProvider` como uma etapa semântica posterior. Isso entrega leitura real de áudio e imagem imediatamente, preserva fallback para Windows/Whisper e evita acoplar o Engine Python a APIs Apple que só existem no macOS.
## Fontes oficiais
- [Foundation Models](https://developer.apple.com/documentation/FoundationModels)
- [Generating content and performing tasks with Foundation Models](https://developer.apple.com/documentation/FoundationModels/generating-content-and-performing-tasks-with-foundation-models)
- [Foundation Models updates](https://developer.apple.com/documentation/Updates/FoundationModels)
- [Built-in intelligence](https://developer.apple.com/documentation/technologyoverviews/built-in-intelligence)
- [SFSpeechRecognizer](https://developer.apple.com/documentation/speech/sfspeechrecognizer)
- [Apple Intelligence para desenvolvedores](https://developer.apple.com/apple-intelligence/)
- [TN3193 — context window](https://developer.apple.com/documentation/Technotes/tn3193-managing-the-on-device-foundation-model-s-context-window)
@@ -0,0 +1,366 @@
# Plano de Desenvolvimento — Primeira Etapa
## Scanner e leitura da timeline via MCP
## Status
Plano de desenvolvimento da primeira etapa. Este documento organiza a implementação futura; não autoriza a criação imediata de código sem que cada fase esteja preparada e validada.
## Objetivo
Construir o primeiro fluxo funcional do sistema capaz de ler a timeline ativa do Premiere por meio do MCP e transformá-la em uma representação interna confiável.
Ao final desta etapa, o sistema deverá conseguir:
1. comunicar-se com o MCP;
2. verificar a disponibilidade do Premiere;
3. ler a sequência ativa, faixas e clipes;
4. converter respostas externas em objetos do domínio;
5. validar dados incompletos ou inválidos;
6. executar a descoberta por meio do `Scanner`;
7. registrar erros e informações relevantes;
8. testar todo o fluxo sem depender do Premiere real.
## Limites da etapa
### Incluído
- conexão e chamadas técnicas ao MCP;
- sessão e erros da integração;
- leitura da timeline, sequência, faixas e clipes;
- conversores de dados externos;
- entidades e objetos de valor necessários;
- contrato de acesso ao editor;
- contexto, pipeline e descoberta da timeline;
- configuração mínima do scanner;
- logs técnicos e de fluxo;
- testes unitários, de integração simulada e de conversores;
- fixtures baseadas em respostas reais do MCP.
### Não incluído
- corte, exclusão ou movimentação de clipes;
- qualquer escrita no Premiere;
- plano de edição;
- decisão automática;
- transcrição;
- análise visual;
- análise de áudio;
- detecção de cenas;
- detecção de retakes;
- uso obrigatório de provider de IA;
- otimizações prematuras ou execução paralela.
## Estrutura planejada
```text
engine/
├── arquitetura/
│ └── documentação da arquitetura
├── scanner/
│ ├── coordenacao/
│ ├── contratos/
│ ├── modelos/
│ ├── configuracao/
│ └── descoberta/
├── integracoes/
│ └── premiere/
│ ├── cliente_mcp.py
│ ├── sessao_mcp.py
│ ├── erros_mcp.py
│ ├── leitura/
│ ├── conversores/
│ └── contratos/
├── dominio/
│ ├── entidades/
│ └── objetos_de_valor/
├── configuracao/
├── persistencia/
├── logging/
└── testes/
```
## Fases de desenvolvimento
### Fase 0 — Preparação e confirmação arquitetural
**Objetivo:** garantir que o desenho está coerente antes da implementação.
**Atividades:**
- revisar `scanner.md`, `integracao-com-premiere.md` e `leitura-da-timeline-via-mcp.md`;
- revisar a skill `boas-praticas-oo.md`;
- confirmar que todos os identificadores internos serão em PT-BR;
- definir os contratos antes das implementações concretas;
- confirmar que o scanner não terá dependência direta do MCP;
- identificar quais classes são realmente necessárias na primeira versão.
**Entrega:** arquitetura aprovada e sem responsabilidades sobrepostas.
### Fase 1 — Descoberta da API real do MCP
**Objetivo:** conhecer o contrato externo antes de criar adaptadores definitivos.
**Atividades:**
- identificar como o MCP é iniciado;
- verificar como a conexão é estabelecida;
- listar as ferramentas disponíveis;
- identificar ferramentas para projeto, sequência, faixas e clipes;
- registrar argumentos, respostas e erros;
- observar formato dos identificadores e dos tempos;
- capturar respostas reais anonimizadas para fixtures;
- confirmar se a comunicação é síncrona ou assíncrona;
- confirmar se existe estado de sessão.
**Regra:** nomes de ferramentas e campos externos não serão inventados. Eles ficarão isolados na integração.
**Entrega:** inventário do MCP e conjunto inicial de fixtures reais.
### Fase 2 — Contratos e modelos do domínio
**Objetivo:** definir as interfaces internas antes dos adaptadores.
**Contratos:**
- `ContratoDeAcessoAoEditor`;
- contrato de etapa do scanner;
- contrato de conversor, quando necessário.
**Entidades:**
- `Projeto`;
- `Sequencia`;
- `Timeline`;
- `Faixa`;
- `Clipe`.
**Objetos de valor:**
- `IntervaloDeTempo`;
- `TipoDeFaixa`;
- `TipoDeMidia`;
- identificadores internos e externos, se necessário.
**Invariantes mínimas:**
- intervalo não pode iniciar antes de zero;
- fim não pode ser anterior ao início;
- identificadores devem ser preservados;
- posição na timeline e posição na origem são distintas;
- clipe pode estar offline sem invalidar toda a timeline;
- nome não é identificador único.
**Entrega:** modelo interno independente de MCP e editor.
### Fase 3 — Cliente e sessão MCP
**Objetivo:** encapsular a comunicação técnica externa.
**Classes:**
- `ClienteMCP`;
- `SessaoMCP`;
- `ErroMCP`;
- `ErroDeConexaoMCP`;
- `ErroDeFerramentaMCP`;
- `ErroDeRespostaMCP`;
- `FerramentaMCPNaoEncontrada`.
**Responsabilidades:**
- conectar e desconectar;
- informar estado da conexão;
- chamar ferramentas;
- controlar timeout;
- retornar resposta bruta;
- traduzir falhas técnicas em erros específicos;
- registrar logs técnicos.
**Restrições:**
- não criar entidades de domínio;
- não conhecer timeline, clipe, cena ou retake;
- não decidir qual ferramenta usar para uma regra de negócio;
- não misturar leitura e escrita.
**Entrega:** comunicação técnica testável com cliente simulado.
### Fase 4 — Leitura estruturada do Premiere
**Objetivo:** oferecer operações de alto nível para o restante do sistema.
**Classes iniciais:**
- `AcessoAoEditor`;
- `AcessoATimeline`;
- `AcessoAClipes`.
**Operações iniciais:**
- obter timeline ativa;
- obter sequência ativa;
- obter faixas;
- obter clipes;
- obter detalhes de um clipe.
Essas classes poderão começar com uma fachada simples e ser divididas somente quando houver crescimento real de responsabilidade.
**Entrega:** leitura sem que o scanner conheça nomes de ferramentas MCP.
### Fase 5 — Conversão e validação
**Objetivo:** transformar respostas externas em objetos internos confiáveis.
**Classes:**
- `ConversorDeTimeline`;
- `ConversorDeFaixas`;
- `ConversorDeClipes`.
**Atividades:**
- normalizar nomes de campos;
- converter tempos e identificadores;
- aplicar valores padrão seguros;
- validar campos obrigatórios;
- preservar campos externos relevantes;
- tratar tipos desconhecidos;
- diferenciar resposta incompleta de timeline vazia;
- gerar erros de validação estruturados.
**Entrega:** timeline de domínio construída a partir de fixtures externas.
### Fase 6 — Núcleo do scanner
**Objetivo:** executar a descoberta por meio do fluxo arquitetural definido.
**Classes:**
- `ContextoDeAnalise`;
- `Analisador`;
- `ResultadoDaAnalise`;
- `StatusDaAnalise`;
- `ErroDeAnalise`;
- `DescobertaDaTimeline`;
- `PipelineDoScanner`;
- `AnalisadorDeTimeline`.
**Fluxo:**
```text
AnalisadorDeTimeline
↓
ContextoDeAnalise
↓
PipelineDoScanner
↓
DescobertaDaTimeline
↓
ContratoDeAcessoAoEditor
↓
Timeline do domínio
↓
Contexto atualizado
```
Na primeira versão, o pipeline poderá conter somente `DescobertaDaTimeline`.
**Entrega:** scanner capaz de retornar o contexto com a timeline lida.
### Fase 7 — Testes e integração simulada
**Objetivo:** garantir comportamento sem depender do Premiere real.
**Implementar:**
- `AcessoAoEditorSimulado`;
- fixtures de projeto, sequência, faixas e clipes;
- testes do cliente MCP;
- testes dos acessos de leitura;
- testes dos conversores;
- testes das entidades e objetos de valor;
- testes do pipeline;
- testes da descoberta;
- testes de integração simulada.
**Cenários obrigatórios:**
- timeline válida;
- timeline vazia;
- nenhuma sequência ativa;
- sequência sem clipes;
- mídia offline;
- resposta incompleta;
- intervalo inválido;
- ferramenta inexistente;
- timeout;
- MCP indisponível;
- campos adicionais desconhecidos.
**Entrega:** suíte automatizada reproduzível.
### Fase 8 — Validação com Premiere real
**Objetivo:** confirmar o fluxo contra o ambiente real.
**Atividades:**
- conectar ao MCP real;
- listar ferramentas e comparar com o inventário;
- ler projeto e sequência reais;
- comparar resposta real com fixtures;
- validar faixas e clipes;
- testar projeto vazio;
- testar mídia offline;
- verificar logs sem dados sensíveis;
- confirmar que nenhuma ferramenta de escrita foi chamada.
**Entrega:** relatório de validação da leitura real.
## Critérios de conclusão
A primeira etapa estará concluída quando:
- o scanner depender apenas de contratos internos;
- o MCP estiver isolado no módulo de integração;
- a timeline ativa puder ser lida do Premiere;
- faixas e clipes forem convertidos para o domínio;
- intervalos da timeline e da origem forem preservados separadamente;
- mídia offline for representada sem interromper toda a leitura;
- timeline vazia for tratada como resultado válido quando apropriado;
- erros técnicos e de validação forem distinguíveis;
- o fluxo puder ser executado com integração simulada;
- os testes automatizados estiverem passando;
- os logs forem úteis e seguros;
- nenhuma alteração for feita na timeline;
- todos os identificadores internos respeitarem PT-BR;
- a implementação estiver aderente à skill de boas práticas OO.
## Ordem resumida
```text
Arquitetura
↓
API real do MCP
↓
Contratos e domínio
↓
ClienteMCP
↓
AcessoAoEditor
↓
Conversores
↓
Contexto e pipeline
↓
DescobertaDaTimeline
↓
Testes simulados
↓
Validação com Premiere real
```
## Regra final
O MCP é o mecanismo de comunicação com o editor. O scanner é o módulo que organiza a descoberta. O domínio representa os dados. Os conversores isolam formatos externos. Nenhuma dessas responsabilidades deve ser concentrada em uma única classe.
@@ -0,0 +1,264 @@
# Planos das Próximas Etapas
## Visão geral
O desenvolvimento será incremental. Cada etapa deverá produzir uma capacidade funcional verificável, com testes e integração controlada. Nenhuma etapa deverá antecipar responsabilidades de etapas posteriores.
## Etapa 1 — Concluir a leitura da timeline
### Objetivo
Produzir uma representação interna completa e confiável da sequência ativa do Premiere.
### Implementar
- `SessaoMCP`;
- `AcessoASequencia`;
- `AcessoAFaixas`;
- `AcessoAClipes`;
- `ConversorDeFaixas`;
- `ConversorDeClipes`;
- `ConversorDeRespostas`;
- `ResultadoDaAnalise`;
- `StatusDaAnalise`;
- `ErroDeAnalise`;
- validação estruturada;
- fixtures de respostas reais;
- persistência inicial do resultado.
### Resultado esperado
```text
Premiere → MCP → Domínio → ContextoDeAnalise
```
Sem cortes, alterações ou decisões editoriais.
## Etapa 2 — Descoberta de arquivos e metadados
### Objetivo
Relacionar cada clipe ao arquivo de origem e obter suas características técnicas.
### Implementar
- `DescobertaDeArquivos`;
- `ExtracaoDeMetadados`;
- adaptador para leitura de arquivos;
- identificação de mídia offline;
- codecs, resolução, duração e taxa de quadros;
- validação de arquivos inacessíveis;
- cache de metadados;
- testes com arquivos reais e simulados.
### Regra
O módulo não deverá avaliar qualidade artística nem decidir se um clipe deve ser usado.
## Etapa 3 — Extração e análise de áudio
### Objetivo
Preparar o áudio e gerar informações temporais sobre o sinal sonoro.
### Implementar
- `ExtracaoDeAudio`;
- `AnaliseDeAudio`;
- contratos de provider de áudio;
- adaptador para FFmpeg ou ferramenta definida;
- silêncio, pausas, volume, clipping e ruído;
- marcadores temporais;
- arquivos intermediários e limpeza segura;
- testes sem dependência do Premiere.
### Regra
Esta etapa não transcreve e não decide cortes.
## Etapa 4 — Transcrição
### Objetivo
Produzir texto sincronizado com o áudio dos clipes.
### Implementar
- `TranscricaoDeAudio`;
- `ProviderDeTranscricao`;
- primeiro adaptador de transcrição;
- segmentos, palavras e confiança;
- associação entre transcrição e clipe;
- cache e retomada;
- tratamento de falha parcial;
- testes com provider simulado.
### Regra
O scanner armazenará a transcrição, mas não decidirá cortes com base nela.
## Etapa 5 — Extração e análise visual
### Objetivo
Obter quadros representativos e características visuais dos clipes.
### Implementar
- `ExtracaoDeQuadros`;
- `AnaliseVisual`;
- `ProviderDeAnaliseVisual`;
- seleção temporal de quadros;
- cache de imagens;
- foco, exposição, estabilidade, pessoas e composição;
- confiança e referências temporais;
- testes com provider simulado.
## Etapa 6 — Cenas e eventos
### Objetivo
Consolidar sinais de vídeo, áudio e texto em cenas e eventos temporais.
### Implementar
- `DeteccaoDeCenas`;
- `DeteccaoDeEventos`;
- contratos de providers;
- combinação de resultados;
- deduplicação;
- confiança;
- eventos de fala, silêncio, pausas e mudanças visuais;
- testes de consolidação.
### Regra
Evento detectado é informação. Não é decisão de edição.
## Etapa 7 — Detecção de retakes
### Objetivo
Identificar possíveis tomadas repetidas ou alternativas.
### Implementar
- `DeteccaoDeRetakes`;
- comparação de transcrições;
- comparação visual;
- comparação de áudio;
- agrupamento de tomadas semelhantes;
- nível de similaridade;
- vínculos entre clipes e grupos de retake;
- testes com casos positivos e negativos.
## Etapa 8 — Persistência e reprocessamento
### Objetivo
Permitir salvar, consultar e retomar análises.
### Implementar
- contrato de repositório da análise;
- armazenamento da versão do scanner;
- armazenamento da configuração utilizada;
- revisão da timeline;
- cache por etapa;
- retomada após falha;
- invalidação seletiva;
- persistência de erros e avisos.
## Etapa 9 — Motor de decisão
### Objetivo
Interpretar os resultados do scanner e escolher ações editoriais.
### Implementar somente após o scanner
- `MotorDeDecisao`;
- regras editoriais;
- critérios de seleção;
- explicação das decisões;
- conflitos entre regras;
- nível de confiança;
- saída estruturada.
### Regra
O motor de decisão não deverá consultar diretamente o MCP. Ele trabalhará apenas com o resultado persistido do scanner.
## Etapa 10 — Plano e aplicação de edição
### Objetivo
Transformar decisões em operações verificáveis e aplicá-las com segurança.
### Implementar
- `GeradorDePlanoDeEdicao`;
- modelo de operação;
- validação do plano;
- `AplicadorDeOperacoes`;
- executor de comandos MCP;
- confirmação após cada operação;
- rollback ou estratégia de recuperação;
- modo de simulação;
- auditoria completa.
### Regra
Nenhuma escrita deverá ser liberada sem validação explícita do plano e confirmação do estado do Premiere.
## Ordem de prioridade
```text
Leitura completa da timeline
↓
Arquivos e metadados
↓
Áudio
↓
Transcrição
↓
Análise visual
↓
Cenas e eventos
↓
Retakes
↓
Persistência e retomada
↓
Motor de decisão
↓
Plano de edição
↓
Aplicação no Premiere
```
## Critério para avançar de etapa
Só avançaremos quando a etapa atual tiver:
- responsabilidade documentada;
- contratos definidos;
- implementação isolada;
- testes automatizados;
- integração simulada;
- tratamento de erros;
- logs adequados;
- validação contra o ambiente real, quando aplicável;
- nenhum acoplamento indevido com etapas futuras.
## Próximo plano imediato
O próximo incremento será a conclusão da leitura da timeline, com foco em:
1. separar os modelos de domínio em módulos próprios;
2. criar `ConversorDeFaixas`;
3. criar `ConversorDeClipes`;
4. adicionar validação estruturada;
5. salvar fixtures reais do MCP;
6. ampliar os testes;
7. executar novamente a leitura contra o Premiere.
+643
View File
@@ -0,0 +1,643 @@
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.**