- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
683 lines
14 KiB
Markdown
683 lines
14 KiB
Markdown
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.
|