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.**