Skip to main content
Glama

Estúdio

App web de pré-produção e produção de vídeo com IA, para séries, filmes e spots: bíblia visual, história e guiões, assets (personagens, locais, adereços) com folhas geradas, maquetes 3D dos locais, storyboard, encenação e câmaras, geração de vídeo plano a plano, montagem, uma Sala de argumentistas partilhada com agentes de IA (servidor MCP) e uma agenda de trabalho. Interface em português europeu.

Stack: FastAPI + SQLModel/SQLite + Alembic + Jinja2/HTMX (idiomorph) + three.js, num contentor Docker. Um só utilizador (o dono), com login por email e password.

Estrutura

app/             código (rotas, modelos, templates, estáticos, servidor MCP)
design/          design da UI (HANDOFF.md, ecrãs HTML e PNG de referência)
docs/            arquitetura, regras dos prompts e registo de decisões
migrations/      migrações Alembic (correm sozinhas no arranque)
deploy/nginx/    modelo do site nginx para um servidor com HTTPS
scripts/         deploy.sh (publicar com a fila de geração vazia) e backup.sh
tests/           testes (python -m unittest)
data/            volume: base de dados e ficheiros — fora do repositório
.env             segredos — fora do repositório (modelo em .env.example)

Related MCP server: Idea to Motion

Requisitos

  • Docker com o plugin Compose (Docker Desktop no Mac/Windows, ou Docker Engine no Linux), num processador x86-64 (Intel/AMD); ARM funciona em emulação (ver «rede local»).

  • ~4 GB de disco para a imagem (inclui o Chromium headless, usado para os renders das maquetes e para os PDFs).

  • Para gerar imagens e vídeos: contas nos fornecedores que quiseres usar (ver «Fornecedores de IA»). Sem nenhum, a app funciona para organizar o trabalho, escrever e carregar ficheiros feitos noutro lado.

Configuração (.env)

cp .env.example .env && chmod 600 .env

Variável

Para quê

SECRET_KEY

assina a sessão e cifra as chaves de API guardadas. Gerar: python3 -c "import secrets; print(secrets.token_urlsafe(48))". Não a mudes depois (as chaves guardadas ficariam ilegíveis).

ADMIN_EMAIL

o email com que entras (o único utilizador).

ADMIN_INITIAL_PASSWORD_HASH

hash argon2 da password inicial, entre aspas simples (tem $). Gerar: docker compose run --rm --no-deps app python -m app.cli hash-password. Mudas a password no primeiro login.

COOKIE_SECURE

true com HTTPS (servidor); false em http://localhost.

PUBLIC_URL

o endereço onde a app é aberta (ex.: https://estudio.example.com ou http://localhost:8010). O conector MCP e o login OAuth dele usam-no.

AUTHOR_NAME

o teu nome na Sala de argumentistas (ex.: Ana); por omissão «Autor».

CLAUDE_CODE_OAUTH_TOKEN

opcional: liga o Assistente e o escritor de prompts ao Claude (ver abaixo). Em alternativa ANTHROPIC_API_KEY.

Instalação numa máquina local (Mac, Windows, Linux)

git clone <este repositório> estudio && cd estudio
cp .env.example .env
# no .env: SECRET_KEY, ADMIN_EMAIL, COOKIE_SECURE=false, PUBLIC_URL=http://localhost:8010
docker compose build
docker compose run --rm --no-deps app python -m app.cli hash-password   # escreve a password; cola o hash no .env
mkdir -p data
docker compose up -d

Abre http://localhost:8010 e entra com o ADMIN_EMAIL e a password inicial. No arranque, a app cria a base de dados, aplica as migrações e as listas iniciais. Os dados ficam em ./data (base de dados SQLite e ficheiros de media).

No Linux, se o contentor não conseguir escrever em ./data: sudo chown -R 10001:10001 data (o contentor corre como utilizador sem privilégios, uid 10001).

O conector MCP só funciona com o Claude/ChatGPT na web se a app estiver acessível pela internet com HTTPS (ver abaixo). Em local, podes usá-lo a partir de clientes MCP na mesma máquina (ex.: Claude Code) com PUBLIC_URL=http://localhost:8010.

Instalação num servidor da rede local (mini PC, NAS, computador sempre ligado)

Para usar a app a partir de vários computadores, tablets ou telemóveis da mesma rede, sem a pôr na internet:

  1. No computador que vai servir a app, instala o Docker e segue a instalação local acima, com estas linhas no .env:

    BIND_ADDRESS=0.0.0.0                  # aceita ligações de toda a rede local (e não só do próprio computador)
    PORT=8010
    PUBLIC_URL=http://192.168.1.50:8010   # o IP fixo desse computador na rede (ou o nome, ex. http://estudio.local:8010)
    COOKIE_SECURE=false                   # sem HTTPS na rede local
  2. Dá a esse computador um IP fixo (no router: «reserva de DHCP») para o endereço não mudar.

  3. Se houver firewall (Windows, ufw no Linux, NAS), abre a porta 8010 só para a rede local.

  4. Nos outros aparelhos, abre http://192.168.1.50:8010.

Notas:

  • Sem HTTPS, a password e a sessão passam em claro na rede: usa isto só numa rede tua, nunca em Wi-Fi público, e não faças reencaminhamento da porta no router para a internet.

  • Querendo HTTPS dentro de casa: um proxy como Caddy ou o nginx com um certificado próprio, e aí COOKIE_SECURE=true e PUBLIC_URL=https://….

  • O conector MCP do Claude e do ChatGPT na web precisa de chegar à app pela internet com HTTPS. Numa rede local, sem abrir portas, a forma mais simples é um túnel (ex.: Cloudflare Tunnel ou Tailscale Funnel) para um endereço https://…, que passa a ser o PUBLIC_URL (com COOKIE_SECURE=true). Sem túnel, o resto da app funciona na mesma.

  • Em processadores ARM (Mac com Apple Silicon, Raspberry Pi, alguns NAS) a imagem corre em emulação x86-64: funciona, mas a construção e os renders são mais lentos. Recomenda-se 4 GB de RAM ou mais.

Instalação num servidor (VPS com HTTPS)

  1. DNS: um registo A (e AAAA, se tiveres IPv6) do teu domínio, ex. estudio.example.com, para o IP do servidor.

  2. Código e configuração:

    git clone <este repositório> /opt/estudio && cd /opt/estudio
    cp .env.example .env && chmod 600 .env
    # no .env: SECRET_KEY, ADMIN_EMAIL, COOKIE_SECURE=true, PUBLIC_URL=https://estudio.example.com, AUTHOR_NAME
    docker compose build
    docker compose run --rm --no-deps app python -m app.cli hash-password   # → ADMIN_INITIAL_PASSWORD_HASH
    mkdir -p data && chown -R 10001:10001 data && chmod 700 data
    docker compose up -d

    A app fica a ouvir só em 127.0.0.1:8010; quem a expõe é o nginx.

  3. nginx e certificado (Let's Encrypt):

    sed 's/estudio.example.com/O_TEU_DOMINIO/g' deploy/nginx/estudio.conf.example > /etc/nginx/sites-available/estudio.conf
    ln -s /etc/nginx/sites-available/estudio.conf /etc/nginx/sites-enabled/estudio.conf
    # na primeira vez o certificado ainda não existe: comenta o bloco «listen 443» e recarrega o nginx, depois:
    certbot certonly --webroot -w /var/www/html -d O_TEU_DOMINIO
    # volta a pôr o bloco 443
    nginx -t && systemctl reload nginx

    O nginx aceita pedidos até 200 MB (clips de vídeo) e faz a renovação do certificado com o timer do certbot.

  4. Backup diário (opcional): scripts/backup.sh (base de dados e media, um só ficheiro em /var/backups/director/); por exemplo em /etc/cron.d/estudio-backup: 30 3 * * * root /opt/estudio/scripts/backup.sh >> /var/log/estudio-backup.log 2>&1.

  5. Atualizar: git pull && ./scripts/deploy.sh (constrói a imagem e só reinicia com a fila de geração vazia, para não repetir pedidos pagos).

Fornecedores de IA

Nada disto é obrigatório; cada um liga uma parte da geração.

  • Claude (Assistente, escritor de prompts, cotações do Artlist): claude setup-token numa máquina com o Claude Code e a tua subscrição; põe o token em CLAUDE_CODE_OAUTH_TOKEN e docker compose up -d.

  • Artlist (imagens e vídeo): Configuração → Ligações → ligar a conta (a app usa o servidor MCP do Artlist através do Claude Code no contentor). Precisa do token do Claude acima.

  • GPT Image (subscrição ChatGPT, pelo Codex CLI): docker compose exec app codex login --device-auth.

  • fal.ai, BytePlus (Seedance) e outros: chaves em Configuração → Chaves de API (cifradas na base de dados).

Conector MCP (Claude, ChatGPT)

A app é um servidor MCP em <PUBLIC_URL>/mcp, com OAuth (registo dinâmico de clientes) e o teu login como autorização. No Claude: Definições → Conectores → Adicionar conector personalizado → <PUBLIC_URL>/mcp. No ChatGPT: modo de programador → Apps e conectores → Criar, com o mesmo endereço e OAuth. As ferramentas cobrem projetos, história e guião, assets, maquetes, storyboard, vídeo, Sala de argumentistas e Agenda; nada é aprovado sem ti e gerações pagas pedem a confirmação do custo.

Testes

docker compose exec app python -m unittest discover -s tests -v

Acesso

  • Só o email definido em ADMIN_EMAIL tem acesso.

  • No primeiro login é obrigatório mudar a password. A nova password fica guardada (em hash argon2) na base de dados. O .env guarda apenas a password inicial.

  • Mudar a password mais tarde: menu Alterar password. Todas as outras sessões terminam.

  • Esqueci-me da password: docker compose exec app python -m app.cli reset-password repõe a password inicial do .env, que terá de ser mudada no login seguinte.

  • Máximo de 5 tentativas falhadas por IP em 15 minutos.

Ficheiros

  • Ficheiros em data/media/<PREFIXO>/: assets/<CÓDIGO>/vN.ext (folhas), assets/<CÓDIGO>/retrato/vN.ext (retratos das personagens), assets/<CÓDIGO>/maquete/ (renders e vistas dos locais), planos/<id>/clip|maquete|fotogramas/. A base de dados guarda só o caminho.

  • Os nomes ao descarregar e no zip seguem o código: PRJ_ANA_sheet.png, AVT_C01_P02_v3.mp4, e na exportação da montagem 01_AVT_C01_P01.mp4… pela ordem dos planos.

  • Vídeos: MP4 ou MOV até 200 MB; a duração é lida do próprio ficheiro (caixa mvhd).

  • Uploads aceites: PNG, JPG e WEBP até 25 MB (tipo verificado pelo conteúdo com Pillow). O nginx aceita pedidos até 200 MB, a pensar nos clips de vídeo.

  • Rejeitar um resultado apaga o ficheiro do disco e retira-o de onde era usado. O registo fica, marcado como rejeitado, e nunca pode ser escolhido como referência.

Regras de prompts

Os prompts (folhas, retratos, vistas, vídeo, capa) são escritos pelo escritor de prompts, com as regras de docs/PROMPT_RULES.md e as guias de Configuração → Prompts (ver docs/DECISOES.md); a app não os monta. Junto a cada prompt aparecem os avisos da secção 5 — nenhum bloqueia; limites e listas de palavras editáveis em Configuração → Validações de prompts. Cada prompt editado guarda versões que se podem repor. O Assistente recebe estas regras sempre que propõe ou corrige um prompt.

Assistente (Claude Code)

O painel do Assistente chama o Claude Code CLI dentro do contentor, com o utilizador sem privilégios da app, em modo não interativo (claude -p): sem ferramentas (--tools ""), --restricted, sem MCP nem definições de terceiros, sem sessões gravadas, numa pasta temporária vazia e com tempo limite (Configuração → Modelos e prompts → Assistente). A resposta é JSON validado (--json-schema); cada proposta é verificada contra os campos permitidos no ecrã atual e só é gravada com Aplicar.

Ligar (uma vez):

claude setup-token            # no VPS, com a tua conta Claude; copia o token que aparece
nano .env                     # CLAUDE_CODE_OAUTH_TOKEN=<token>
docker compose up -d          # recria o contentor com o token

Em alternativa ao token, ANTHROPIC_API_KEY= no .env.

GPT Image (Codex CLI)

Gera e edita imagens (folhas de asset, retratos, vistas da maquete dos locais e capa do projeto) com o GPT Image da subscrição ChatGPT, através do Codex CLI instalado no contentor (versão fixa no Dockerfile). O login fica em data/codex/ (fora do backup):

docker compose exec app codex login --device-auth    # abre o link, introduz o código

Os pedidos entram numa fila (um de cada vez) e o resultado aparece nos Resultados como "por decidir", com a etiqueta GPT. "Editar com GPT" refaz uma imagem com uma alteração descrita em inglês. O Codex corre como utilizador sem privilégios, numa pasta temporária, com um ambiente mínimo (sem os segredos da app); a shell dele fica bloqueada pela sandbox. Cada imagem gasta o limite do Codex 3–5× mais do que uma mensagem. Ligar/desligar e tempo limite em Configuração.

Backup

scripts/backup.sh corre todos os dias às 03:30 (/etc/cron.d/director-backup) e cria /var/backups/director/director-backup.tar.gz, com a base de dados e data/media. Existe apenas um backup: o novo substitui o anterior, e só depois de estar completo. Log: /var/log/director-backup.log.

Restaurar:

docker compose down
tar -xzf /var/backups/director/director-backup.tar.gz -C data/
chown -R 10001:10001 data
docker compose up -d

Operação

docker compose logs -f                 # logs
docker compose up -d --build           # atualizar após alterações ao código
docker compose exec app alembic revision --autogenerate -m "..."   # nova migração (dev)

As migrações correm com PRAGMA foreign_keys=OFF (ver migrations/env.py): no SQLite, o modo batch recria tabelas e, com as chaves estrangeiras ativas, o DROP apagaria em cascata os dados das tabelas filhas. Fazer sempre scripts/backup.sh antes de publicar uma migração.

Visual

app/static/css/estudio.css é o CSS do design, copiado sem alterações. Os ajustes da app (scroll, tamanhos em tablet/telemóvel, componentes extra) estão em app/static/css/app.css. O tema claro guarda-se no browser (Configuração → Conta).

Chaves de API

Configuração → Chaves de API guarda as chaves dos fornecedores de modelos (Anthropic, OpenAI, Google, Mistral, Z.ai, Alibaba, DeepSeek, MiniMax, xAI, BytePlus, Black Forest Labs, Kling, Azure, Meta, Runway, Luma, OpenRouter, fal.ai, Replicate). Ficam cifradas (Fernet) na base de dados com uma chave derivada de SECRET_KEY: o backup não as expõe, mas mudar o SECRET_KEY torna-as ilegíveis (a página pede para as introduzir de novo). Nunca são mostradas depois de gravadas. Ter uma chave guardada não liga o fornecedor à app: cada integração (Assistente, imagens, vídeo) é à parte.

Licença

Copyright (C) 2026 Leca-pt

Este programa é software livre: podes redistribuí-lo e/ou modificá-lo nos termos da GNU Affero General Public License, tal como publicada pela Free Software Foundation, versão 3 da licença ou (à tua escolha) qualquer versão posterior. É distribuído na esperança de ser útil, mas sem qualquer garantia, nem mesmo a garantia implícita de comerciabilidade ou de adequação a um fim específico. O texto completo está em LICENSE.

Em resumo: podes usar, estudar, alterar e partilhar a app. Se a alterares e a puseres a funcionar para outras pessoas (por exemplo, num servidor acessível pela internet), tens de lhes dar acesso ao código-fonte da tua versão, também sob a AGPL-3.0.

Componentes de terceiros mantêm as suas próprias licenças (ex.: three.js, MIT, em app/static/vendor/three/).

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers