Vídeo com IA: Claude Code, Codex e ElevenLabs · Capítulo 3 de 25 · 26 min
Montar a bancada de vídeo com IA mesmo sem nunca ter usado o terminal
Deixe terminal e ferramentas prontos no seu sistema com as chaves fora do código e um teto de gasto e leia cada erro de API antes de pedir ajuda ao agente.
Este capítulo faz parte do curso gratuito Vídeo com IA: Claude Code, Codex e ElevenLabs.
Bancada pronta não é aquela em que todos os instaladores terminaram. É aquela em que você acha um arquivo, executa uma ferramenta, reconhece uma falha e mostra ao agente só o que ele precisa para corrigi-la, sem expor nenhuma chave.
Sem isso, o primeiro erro vira uma tarde perdida. Um command not found parece defeito do programa, uma chave colada no chat fica no histórico, e um 429 repetido em laço gasta crédito e prolonga o bloqueio. Sem o log certo, o agente inventa uma causa plausível e mexe no que estava funcionando.
Nesta aula você monta a bancada no seu sistema (Windows, macOS ou Linux) e separa três verificações que costumam ser confundidas: ferramenta encontrada, configuração local válida e autenticação aceita pelo serviço. No fim, você tem um log curto que qualquer agente consegue ler.
Abrir o terminal e fazer o sistema achar as ferramentas
Terminal é a janela onde você digita comandos em vez de clicar, como pedir no balcão em vez de procurar na prateleira. CLI, a interface de linha de comando, é o programa que você opera por ali: claude, codex e ffmpeg são CLIs. Três comandos resolvem a orientação: pwd mostra a pasta atual, cd muda de pasta e ls lista o que tem nela (no PowerShell, os três também funcionam). Caminho com espaço vai entre aspas, como cd "Meus vídeos".
Caminho relativo parte da pasta em que você está, como audio/narracao.mp3; caminho absoluto dá o endereço completo, como C:\Users\voce\video-ia\audio\narracao.mp3 no Windows ou /Users/voce/video-ia/audio/narracao.mp3 no macOS. Quase todo "arquivo não encontrado" de iniciante é um script rodado na pasta errada: confira com pwd antes de culpar o código.
PATH é a lista de pastas onde o terminal procura um programa quando você digita o nome dele, como uma agenda de endereços. Se a pasta do FFmpeg não está na lista, o terminal responde command not found (no Windows, que o termo não é reconhecido como nome de cmdlet) mesmo com o programa instalado. Depois de instalar ou mexer no PATH, feche e abra o terminal, porque a janela antiga guarda a lista velha.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Instale Node.js, Python e FFmpeg pelos instaladores oficiais de cada projeto, e o Claude Code pelo comando da página de início rápido da documentação dele; o passo a passo com telas está em instalar o Claude Code e dar a primeira ordem. O Claude Code pede um plano pago (o Pro custa US$ 20 por mês em 09/10/2026) ou uma chave de API. A instalação e a configuração do Codex têm aula própria, a de configurar o Codex com GPT-6 Astra; aqui basta ele responder a codex --version.
Depois, rode o diagnóstico do seu sistema na pasta video-ia. Ele lista o PATH, procura cada ferramenta, confere as versões mínimas e cria o ambiente virtual (.venv), a pasta isolada onde ficam os pacotes Python do projeto; o porquê do isolamento está em ambientes virtuais e pip.
Versões e diagnóstico da bancada por sistema
package Versões de referência
Os números abaixo são as versões de referência desta bancada. O HyperFrames exige Node.js 22 ou superior e FFmpeg; o curso adota Python 3.12 ou superior porque o PyAV 19, a biblioteca Python que conversa com o FFmpeg, deixou de suportar o 3.11 em 29/09/2026 (a 19.0.1, de 03/10/2026, mantém a regra). As versões abaixo são as vigentes em 12/10/2026; confira a sua com codex --version, npx hyperframes --version e ffmpeg -version antes de abrir um chamado.
Que versões a bancada precisa ter em 12/10/2026
22+
Node.js
exigência do HyperFrames 0.8.149, de 11/10/2026
3.12+
Python
PyAV 19.0.1, de 03/10/2026, sem Python 3.11
9.0.2
FFmpeg
estável na página de downloads; confira com ffmpeg -version
0.162.1
Codex CLI
versão estável de 09/10/2026
Fonte: Releases do HyperFrames (11/10/2026), do PyAV (03/10/2026) e do Codex (09/10/2026) e página de downloads do FFmpeg, em 12/10/2026.
Windows
Abra o PowerShell pelo menu Iniciar e entre na pasta com cd. Se o Windows recusar a ativação do ambiente virtual por política de execução, rode Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass, que vale só para aquela janela. No Windows o Python costuma responder como python, e não python3.
# Diagnóstico da bancada no Windows. Abra o PowerShell na pasta video-ia e cole.
Write-Host "Pasta atual: $(Get-Location)"
# PATH: as pastas onde o terminal procura programas, uma por linha.
$env:Path -split ";" | Where-Object { $_ } | ForEach-Object { Write-Host " PATH: $_" }
$faltou = $false
foreach ($f in "node", "npm", "python", "ffmpeg", "ffprobe", "claude", "codex") {
$cmd = Get-Command $f -ErrorAction SilentlyContinue
if ($cmd) { Write-Host "ENCONTRADO: $f em $($cmd.Source)" }
else { Write-Host "AUSENTE: $f (instale ou ponha a pasta dele no PATH)"; $faltou = $true }
}
if ($faltou) { Write-Host "Corrija os AUSENTE, feche este terminal e abra outro."; exit 1 }
# Versões mínimas da bancada: Node 22+ (HyperFrames) e Python 3.12+ (PyAV 19).
node -e "process.exit(Number(process.versions.node.split('.')[0]) >= 22 ? 0 : 1)"
if ($LASTEXITCODE -ne 0) { Write-Host "Node abaixo de 22."; exit 1 }
python -c "import sys; sys.exit(0 if sys.version_info >= (3, 12) else 1)"
if ($LASTEXITCODE -ne 0) { Write-Host "Python abaixo de 3.12."; exit 1 }
node --version; python --version; (ffmpeg -version)[0]; codex --version
# Variável de ambiente: diga se existe sem mostrar o valor.
if ($env:ANTHROPIC_API_KEY) { "ANTHROPIC_API_KEY: definida" } else { "ANTHROPIC_API_KEY: ausente (normal antes do .env)" }
# Ambiente virtual do projeto.
if (-not (Test-Path ".venv")) { python -m venv .venv }
Write-Host "OK. Ative com: .\.venv\Scripts\Activate.ps1"
macOS
No macOS, abra o app Terminal (em Aplicativos, Utilitários). Salve o bloco como scripts/diagnostico.sh, dê permissão de execução com chmod +x, que marca o arquivo como programa, e rode ./scripts/diagnostico.sh. Sem o chmod, o sistema responde Permission denied.
#!/usr/bin/env bash
# Diagnóstico da bancada no macOS. Salve como scripts/diagnostico.sh e rode:
# chmod +x scripts/diagnostico.sh && ./scripts/diagnostico.sh
set -euo pipefail
printf 'Pasta atual: %s\n' "$PWD"
# PATH: as pastas onde o terminal procura programas, uma por linha.
printf '%s\n' "$PATH" | tr ':' '\n' | sed 's/^/ PATH: /'
faltou=0
for f in node npm python3 ffmpeg ffprobe claude codex; do
if command -v "$f" >/dev/null 2>&1; then
printf 'ENCONTRADO: %s em %s\n' "$f" "$(command -v "$f")"
else
printf 'AUSENTE: %s (instale ou ponha a pasta dele no PATH)\n' "$f"
faltou=1
fi
done
[ "$faltou" -eq 0 ] || { echo "Corrija os AUSENTE e abra um terminal novo."; exit 1; }
# Versões mínimas da bancada: Node 22+ (HyperFrames) e Python 3.12+ (PyAV 19).
node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 22 ? 0 : 1)' \
|| { echo "Node abaixo de 22."; exit 1; }
python3 -c 'import sys; sys.exit(0 if sys.version_info >= (3, 12) else 1)' \
|| { echo "Python abaixo de 3.12."; exit 1; }
node --version; python3 --version; ffmpeg -version | head -n 1; codex --version
# Variável de ambiente: diga se existe sem mostrar o valor.
[ -n "${ANTHROPIC_API_KEY:-}" ] && echo "ANTHROPIC_API_KEY: definida" \
|| echo "ANTHROPIC_API_KEY: ausente (normal antes do .env)"
# Ambiente virtual do projeto.
[ -d .venv ] || python3 -m venv .venv
echo "OK. Ative com: source .venv/bin/activate"
Linux
Vale para Linux e para o WSL2, o Linux que roda dentro do Windows. O script mostra também as permissões dele mesmo: o x em -rwx é a marca de executável. Em algumas distribuições o módulo de ambiente virtual vem num pacote separado; se o venv falhar, instale esse pacote pelo gerenciador da distribuição.
#!/usr/bin/env bash
# Diagnóstico da bancada no Linux e no WSL2. Salve como scripts/diagnostico.sh e rode:
# chmod +x scripts/diagnostico.sh && ./scripts/diagnostico.sh
set -euo pipefail
printf 'Pasta atual: %s (usuário %s)\n' "$PWD" "$(id -un)"
# Permissões do próprio script: o x em -rwx indica que ele pode ser executado.
ls -l "$0"
printf '%s\n' "$PATH" | tr ':' '\n' | sed 's/^/ PATH: /'
faltou=0
for f in node npm python3 ffmpeg ffprobe claude codex; do
if command -v "$f" >/dev/null 2>&1; then
printf 'ENCONTRADO: %s em %s\n' "$f" "$(command -v "$f")"
else
printf 'AUSENTE: %s (instale ou ponha a pasta dele no PATH)\n' "$f"
faltou=1
fi
done
[ "$faltou" -eq 0 ] || { echo "Corrija os AUSENTE e abra um terminal novo."; exit 1; }
node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 22 ? 0 : 1)' \
|| { echo "Node abaixo de 22."; exit 1; }
python3 -c 'import sys; sys.exit(0 if sys.version_info >= (3, 12) else 1)' \
|| { echo "Python abaixo de 3.12."; exit 1; }
node --version; python3 --version; ffmpeg -version | head -n 1; codex --version
[ -n "${ANTHROPIC_API_KEY:-}" ] && echo "ANTHROPIC_API_KEY: definida" \
|| echo "ANTHROPIC_API_KEY: ausente (normal antes do .env)"
# Se falhar aqui, instale o pacote de venv do Python pelo gerenciador da distribuição.
[ -d .venv ] || python3 -m venv .venv
echo "OK. Ative com: source .venv/bin/activate"
Guardar as chaves fora do código e definir um teto de gasto
Variável de ambiente é um recado que o sistema entrega ao programa quando ele começa, como a ficha que acompanha o pedido na cozinha. A chave de API viaja assim, e não escrita dentro do script. O arquivo .env guarda essas variáveis num texto local; ele não é criptografia, não é lido automaticamente por todo programa e nunca vai para o Git nem para o chat do agente. A mesma prática, aplicada a repositórios, aparece em chaves de API guardadas em Secrets.
O script abaixo cria o .env sem mostrar as chaves na tela, recusa sobrescrever um arquivo existente e põe .env no .gitignore. Os nomes de modelo também ficam no .env: quando um modelo mudar, você troca uma linha e nenhum script. Salve como scripts/criar_env.py e rode python scripts/criar_env.py (no macOS e no Linux, python3).
"""Cria o .env da bancada sem mostrar as chaves. Funciona em Windows, macOS e Linux.
Rode na pasta video-ia: python scripts/criar_env.py (macOS e Linux: python3)
"""
import getpass
import os
import sys
from pathlib import Path
raiz = Path(__file__).resolve().parents[1]
env = raiz / ".env"
if env.exists():
sys.exit(".env já existe. Edite no seu editor, sem mostrar a tela ao agente.")
# getpass não mostra o que você digita: a tela parece parada, e é assim mesmo.
anthropic = getpass.getpass("Chave Anthropic (Enter deixa pendente): ").strip()
openai = getpass.getpass("Chave OpenAI (Enter deixa pendente): ").strip()
eleven = getpass.getpass("Chave ElevenLabs (Enter deixa pendente): ").strip()
linhas = [
"# Arquivo local. Não versionar, não colar no chat, não mostrar na tela.",
f"ANTHROPIC_API_KEY={anthropic}",
f"OPENAI_API_KEY={openai}",
f"ELEVENLABS_API_KEY={eleven}",
# Nomes de modelo ficam aqui, e não no código: trocar de modelo é trocar uma linha.
# ANTHROPIC_MODEL é só o do teste desta aula; os MODEL_* seguem o padrão das aulas 12 a 14.
"ANTHROPIC_MODEL=claude-sonnet-5-5", # troque por claude-haiku-5-5 para o teste mais barato
"MODEL_EXECUTOR=gpt-6.1-sol",
"MODEL_IMAGE=gpt-image-2.5-flare",
"MODEL_TTS=eleven_v4",
"MODEL_VIDEO=gemini-omni-1.1-flash",
# Teto local do curso, em dólar: regra do script, não limite do fornecedor.
"COURSE_BUDGET_USD=1.00",
"COURSE_TEST_RESERVATION_USD=0.05",
]
# O_EXCL recusa sobrescrever; 0o600 deixa o arquivo legível só pelo seu usuário
# no macOS e no Linux (no Windows, ele herda a proteção da sua pasta de usuário).
fd = os.open(env, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, "w", encoding="utf-8") as arquivo:
arquivo.write("\n".join(linhas) + "\n")
gitignore = raiz / ".gitignore"
atuais = gitignore.read_text(encoding="utf-8").splitlines() if gitignore.exists() else []
if ".env" not in atuais:
with gitignore.open("a", encoding="utf-8") as arquivo:
arquivo.write(".env\n")
preenchidas = sum(bool(c) for c in (anthropic, openai, eleven))
print(f"OK: .env criado com {preenchidas} chave(s). Nenhum valor foi exibido.")
Chave presente não é chave válida: só o serviço diz se aceita. O teto de gasto também tem duas camadas. A local, que você vê no .env (US$ 1,00 de teto e US$ 0,05 de reserva por teste), é uma regra do curso: o script recusa a chamada se a soma passar do teto, mas não segura um pedido já enviado. A do fornecedor fica no painel de cobrança de cada conta, e cada um trata o limite de um jeito; ative a sua antes de automatizar qualquer coisa. O max_budget_usd do Agent SDK limita aquele agente, e não a ElevenLabs nem o serviço de vídeo; ele mede uma estimativa pela tabela de preços, e a estimativa muda quando a tabela muda, como em 09/10/2026, quando o Claude Code 2.1.296 reprecificou a leitura de cache do Sonnet 5.5 para US$ 0,10 por milhão de tokens.
A chave fica num arquivo que só a máquina lê. O agente recebe o nome da variável, nunca o valor: se ele pedir a chave no chat para testar, recuse e aponte o .env. A mesma regra vale para a senha de instalador: quando uma instalação pedir senha de administrador, digite na janela do sistema, nunca na conversa, e exija que o agente peça permissão antes de cada instalação. Desde 12/10/2026 esse é o combinado de segurança do curso, e ele é mais barato do que trocar uma chave vazada.
A chave só a máquina lê
Segredo entra no .env e na janela do sistema; no chat entra só o nome da variável.
- Chave de API: no .env, fora do Git, legível só pelo seu usuário
- Senha de instalador: na janela do sistema, nunca na conversa
- Agente pede permissão antes de cada instalação
- Se o agente pedir a chave para testar, recuse e aponte o arquivo
O teste: Procure a chave no registro do chat e do terminal: não pode aparecer em lugar nenhum.
alexandrecaramaschi.com/educacao/frontends-com-vibecoding
Testar uma chamada pequena e ler o erro sem inventar a causa
Código HTTP é o número com que o serviço responde, como a senha do balcão que diz se o pedido foi aceito. Log é o registro de evidências da execução, e retry é repetir uma tentativa. Repetir sem saber se a primeira foi processada pode duplicar trabalho e custo, sobretudo em geração de mídia paga. A tabela traz a primeira leitura de cada família de código; a causa exata depende do fornecedor e da mensagem que vem junto.
Os códigos de erro e o 429 sem Retry-After
list Primeira leitura de cada código
Primeira leitura de cada código de erro
| Código | O que costuma indicar | Antes de repetir |
|---|---|---|
| 401 | Credencial ausente, errada ou de outra conta | Confira qual chave o script leu, sem imprimi-la |
| 429 | Limite de ritmo, cota do dia ou cota zerada no painel; pode vir sem Retry-After | Espere, reduza o ritmo, no máximo três tentativas sem cabeçalho e não rode em laço |
| 5xx | Falha do lado do serviço ou de quem intermedeia | Confira se a tentativa anterior foi processada |
| Sem resposta | Rede ou tempo esgotado antes da resposta | Trate o resultado como desconhecido e confira o consumo |
429 não quer dizer sempre falta de saldo, e 5xx não garante que nada foi cobrado. Em projetos pagos da Gemini API, relatos de 28/09 e 01/10/2026 mostram 429 com cota zerada no painel e sem Retry-After.
alertTriangle Ler um 429 que vem sem Retry-After
O 429 tem três leituras, e só uma delas se resolve esperando. A primeira é limite de ritmo: pedidos por minuto acima do permitido; espere e reduza o ritmo. A segunda é cota do dia: o painel do fornecedor mostra o limite diário por modelo, e ele pode aparecer zerado mesmo em projeto pago, como nos relatos de 28/09 e 01/10/2026 no fórum oficial da Gemini API, em que o Veo 3.1 devolvia 429 com cota zerada no painel, sem o cabeçalho Retry-After e sem solução publicada; o caminho ali é o painel e um chamado de suporte, não o retry. A terceira leitura é a que não existe: 429 não diz que o crédito acabou, e tratar como saldo leva a recarregar a conta sem necessidade.
A regra do curso desde 12/10/2026: se o Retry-After veio, espere exatamente esse valor; se não veio, o script faz no máximo três tentativas com espera crescente e para, registrando a etapa como bloqueada por cota. Você sabe que leu certo quando o log mostra o código, a presença ou ausência do cabeçalho e a ação tomada, e quando nenhuma tentativa foi disparada em laço. O erro comum é deixar o laço rodar até o fornecedor liberar; o conserto é o teto de três tentativas, que a aula do pipeline idempotente coloca no código do orquestrador.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
O script de teste tem dois modos. Com --simular 401, --simular 429 ou --simular 500, grava eventos de treino marcados simulado: true, sem rede e sem custo. Com --online, faz uma única chamada ao modelo do .env pela Messages API: o Claude Sonnet 5.5 (claude-sonnet-5-5, US$ 2 de entrada e US$ 10 de saída por milhão de tokens) ou, para o teste mais barato, o Claude Haiku 5.5 (claude-haiku-5-5, Haiku padrão da API desde 07/10/2026, US$ 0,10 e US$ 0,50 por milhão de tokens), com os headers x-api-key e anthropic-version: 2023-06-01, só depois de você digitar AUTORIZO.
Antes do envio, a tentativa é gravada como pendente; se a resposta não vier, ela continua pendente até você conferir o consumo no painel do fornecedor. Salve como scripts/testar_api.py.
"""Teste controlado da Messages API: simulação sem rede ou uma chamada autorizada.
python scripts/testar_api.py --simular 429 (sem rede, sem custo)
python scripts/testar_api.py --online (uma chamada, pede AUTORIZO)
"""
import argparse
import json
import os
import uuid
from datetime import datetime, timezone
from decimal import Decimal
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
raiz = Path(__file__).resolve().parents[1]
(raiz / "logs").mkdir(exist_ok=True)
(raiz / "custos").mkdir(exist_ok=True)
URL = "https://api.anthropic.com/v1/messages"
PRECO = { # US$ por milhão: entrada, saída (tabela de 12/10/2026)
"claude-sonnet-5-5": (Decimal(2), Decimal(10)),
"claude-haiku-5-5": (Decimal("0.10"), Decimal("0.50")),
}
def carregar_env(caminho):
"""Lê KEY=valor do .env sem executar nada (ao contrário de source)."""
if not caminho.exists():
return
for linha in caminho.read_text(encoding="utf-8").splitlines():
linha = linha.strip()
if linha and not linha.startswith("#") and "=" in linha:
chave, valor = linha.split("=", 1)
os.environ.setdefault(chave.strip(), valor.strip())
def registrar(status, simulado, acao, tipo=None):
"""Grava só campos permitidos: nunca headers, corpo do pedido ou chave."""
evento = {"data": datetime.now(timezone.utc).isoformat(), "etapa": "diagnostico_messages",
"status": status, "simulado": simulado, "acao": acao}
if tipo:
evento["tipo_do_erro"] = tipo
with (raiz / "logs/api-seguro.jsonl").open("a", encoding="utf-8") as f:
f.write(json.dumps(evento, ensure_ascii=False) + "\n")
print(json.dumps(evento, ensure_ascii=False))
def orientar(status):
if status == 401:
return "Conferir qual chave foi lida e de qual conta ela é; não repetir."
if status == 429:
return "Limite de ritmo ou cota: esperar, reduzir o ritmo, não repetir em laço."
if isinstance(status, int) and 500 <= status <= 599:
return "Falha do serviço: ver se a tentativa anterior foi processada antes de repetir."
return "Ler a mensagem do serviço e reconciliar o consumo antes de repetir."
parser = argparse.ArgumentParser()
modo = parser.add_mutually_exclusive_group(required=True)
modo.add_argument("--simular", type=int, choices=[401, 429, 500, 503])
modo.add_argument("--online", action="store_true")
args = parser.parse_args()
if args.simular:
registrar(args.simular, True, orientar(args.simular))
raise SystemExit(0)
carregar_env(raiz / ".env")
modelo = os.environ.get("ANTHROPIC_MODEL", "")
if modelo not in PRECO:
raise SystemExit("Modelo sem preço neste script: revise a tabela PRECO antes.")
chave = os.environ.get("ANTHROPIC_API_KEY", "")
if not chave:
raise SystemExit("ANTHROPIC_API_KEY ausente: a bancada local está pronta, a autenticação fica pendente.")
teto = Decimal(os.environ.get("COURSE_BUDGET_USD", "1.00"))
reserva = Decimal(os.environ.get("COURSE_TEST_RESERVATION_USD", "0.05"))
arquivo = raiz / "custos/testes-api.json"
registros = json.loads(arquivo.read_text(encoding="utf-8")) if arquivo.exists() else []
if any(r["estado"] == "pendente" for r in registros):
raise SystemExit("Há tentativa pendente. Confira o consumo no painel antes de outra chamada.")
gasto = sum((Decimal(r["custo_usd"]) for r in registros), Decimal("0"))
if gasto + reserva > teto:
raise SystemExit(f"Teto local de US$ {teto} atingido (gasto US$ {gasto}).")
print(f"Modelo {modelo}; reserva US$ {reserva}; já gasto US$ {gasto} de US$ {teto}.")
if input("Digite AUTORIZO para uma única chamada paga: ").strip() != "AUTORIZO":
raise SystemExit("Chamada cancelada.")
tentativa = {"id": str(uuid.uuid4()), "estado": "pendente", "reserva_usd": str(reserva)}
registros.append(tentativa)
def salvar():
temporario = arquivo.with_suffix(".tmp")
temporario.write_text(json.dumps(registros, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
temporario.replace(arquivo)
salvar() # grava como pendente ANTES de enviar: queda no meio não libera nova tentativa
pedido = Request(URL, method="POST", data=json.dumps({
"model": modelo,
"max_tokens": 256,
"messages": [{"role": "user", "content": "Responda apenas: bancada pronta."}],
}).encode("utf-8"), headers={
"content-type": "application/json",
"x-api-key": chave,
"anthropic-version": "2023-06-01",
})
try:
with urlopen(pedido, timeout=60) as resposta:
dados = json.load(resposta)
except HTTPError as erro:
try: # se o corpo do erro for JSON com um tipo, guarda só o tipo
tipo = json.loads(erro.read().decode("utf-8")).get("error", {}).get("type")
except (ValueError, AttributeError):
tipo = None
registrar(erro.code, False, orientar(erro.code), tipo)
raise SystemExit("Tentativa mantida pendente até você conferir o consumo.")
except (URLError, TimeoutError, OSError):
registrar("sem_resposta", False, "Resultado desconhecido: conferir consumo, não repetir.")
raise SystemExit("Tentativa mantida pendente até você conferir o consumo.")
uso = dados.get("usage", {})
entrada, saida = uso.get("input_tokens"), uso.get("output_tokens")
if not isinstance(entrada, int) or not isinstance(saida, int):
registrar(200, False, "Resposta sem uso de tokens: conferir no painel.")
raise SystemExit("Tentativa mantida pendente.")
preco_in, preco_out = PRECO[modelo]
custo = (entrada * preco_in + saida * preco_out) / Decimal(1_000_000)
tentativa.update(estado="confirmado", input_tokens=entrada, output_tokens=saida, custo_usd=str(custo))
salvar()
registrar(200, False, "Autenticação aceita e consumo registrado.")
print(f"Custo desta chamada pela tabela do script: US$ {custo:.6f}")
Rode as três simulações e abra logs/api-seguro.jsonl: uma linha JSON por evento, com data, status, a marca de simulado e a ação sugerida. Só depois, se tiver chave e orçamento, rode python scripts/testar_api.py --online. Para abrir o Claude Code já com o modelo padrão do curso, use claude --model opus na pasta video-ia.
Montar e testar a bancada
Sete passos na pasta video-ia. Só o sexto pode custar alguns centavos de dólar.
Passo 1: Confirme a pasta e os caminhos
Deu certo quando: pwd mostra a pasta video-ia e config/catalogo.json está nela.
Erro comum: Rodar em Downloads e procurar os arquivos no projeto.
Passo 2: Rode o diagnóstico do seu sistema
Deu certo quando: Todas as ferramentas aparecem como ENCONTRADO, com Node 22+ e Python 3.12+.
Erro comum: Reinstalar tudo antes de olhar o PATH.
Passo 3: Abra o Claude Code e o Codex, sem pedir tarefa
Deu certo quando: Cada um mostra a tela de login ou a sessão já autenticada.
Erro comum: Concluir que a API funciona só porque a CLI abriu.
Passo 4: Crie o .env com o script
Deu certo quando: O terminal diz OK e nenhum valor de chave apareceu na tela.
Erro comum: Colar a chave no prompt, no código ou num comando que fica no histórico.
Passo 5: Rode as três simulações
Deu certo quando: O log tem três eventos com simulado: true e ações diferentes.
Erro comum: Passar um erro simulado ao agente como se fosse incidente real.
Passo 6: Autorize uma chamada online, se tiver chave e orçamento
Deu certo quando: O log mostra status 200 e o custo fica registrado em custos/testes-api.json.
Erro comum: Repetir depois de um timeout sem conferir a tentativa pendente.
Passo 7: Entregue ao agente só o log mínimo
Deu certo quando: O agente separa evidência, hipótese e próximo teste.
Erro comum: Mandar .env, headers ou a saída inteira do terminal sem revisar segredos.
No fim você tem: Uma bancada com ferramentas encontradas, chaves protegidas, teto local e um log que qualquer agente lê.
Quatro sinais pedem decisões diferentes. Se aparecer command not found ou "não é reconhecido", o problema é de instalação ou de PATH, e as chaves ficam como estão. Se aparecer Permission denied num script seu, confira o caminho e dê chmod +x só àquele arquivo, nunca permissão ampla a pastas inteiras. Se uma tentativa ficar pendente, confira o consumo antes de repetir e não apague o registro para liberar o envio. Se o teste online não for possível hoje, anote "bancada local pronta, autenticação pendente" em vez de declarar sucesso.
O curso "LLM FinOps" mostra que teto de gasto ligar já nesta semana quando os testes virarem rotina. Para pedir a leitura do log, cole o pedido abaixo no Claude Code aberto na pasta video-ia.
Guia prático: fotografar a bancada e ler o calendário de versões
O diagnóstico da aula diz se cada ferramenta existe. Este guia acrescenta a foto datada: um JSON com a versão de cada uma, comparada com o mínimo do curso, que você entrega ao agente no lugar de prints de tela. Mostra também o que mudou no calendário do Node.js e do Python em outubro de 2026 e como pôr na chave da ElevenLabs uma cota de créditos, a camada de teto do fornecedor que a aula pede para ligar.
Funções, casos de uso e aplicações
Funções
O calendário de versões e as chaves com limite em outubro de 2026
| Função ou recurso | O que faz | Quando usar | Desde |
|---|---|---|---|
| Python 3.15.0 | Nova versão estável, com suporte até 10/2031 | Testar num ambiente à parte; o curso segue pedindo 3.12 ou superior | 09/10/2026 |
| Fim do suporte do Python 3.10 | A série 3.10 saiu de suporte; a última versão é a 3.10.22 | Atualizar máquina ou servidor que ainda roda 3.10 | 01/10/2026 |
| Node.js 26 (Current) | Linha mais nova, ainda sem suporte longo; 26.11.1 em 07/10/2026 | Testar; para a bancada, prefira uma linha LTS | 05/05/2026 |
| Node.js 24 Krypton e 22 Jod (LTS) | Linhas de suporte longo (LTS); 24.21.0 em 07/09/2026 e 22.23.3 em 23/09/2026 | Bancada do curso, que pede Node 22 ou superior | 07/09/2026 e 23/09/2026 |
| Node.js 20 Iron fora de suporte | Linha encerrada; a última versão é a 20.20.2 | Trocar onde ainda estiver: o HyperFrames pede 22 ou superior | 24/03/2026 |
| Chave restrita da ElevenLabs | Limita a chave por rota da API, por cota de créditos e por IP; IP fora da lista recebe 403 | Toda chave usada por script ou agente | Na documentação em 12/10/2026 |
| Chaves pessoais e de conta de serviço no Claude Console | Separam a chave de uma pessoa da chave de um processo automático | Em pipeline agendado, no lugar da chave pessoal | 27/08/2026 |
LTS (Long Term Support) é a linha que recebe correções por mais tempo; Current é a linha nova, que muda mais.
Casos de uso
Professor de um curso técnico de audiovisual em Goiânia, com uma turma em que cada aluno usa o próprio notebook
Educação, ensino técnico
Dor
Metade da primeira aula ia em descobrir por que o script rodava numa máquina e não na outra.
Solução
Os alunos rodaram o registrar_bancada.py e entregaram o JSON da foto. O professor agrupou as falhas por ferramenta e resolveu PATH e versão em grupo, na frente da turma.
Resultado
Observar se a aula seguinte começa com todos os JSON sem linha abaixo do mínimo e quanto tempo sobra para o conteúdo.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Analista de marketing de uma rede de academias em Salvador que gera narrações para anúncios em vídeo
Marketing digital, rede de academias
Dor
A mesma chave da ElevenLabs servia ao site, ao pipeline de vídeo e a um teste antigo, e não dava para saber quem consumia os créditos.
Solução
Ela criou uma chave restrita só para o pipeline, com acesso às rotas de voz e cota de créditos própria, e deixou a antiga ativa apenas até migrar os outros usos.
Resultado
Acompanhar no painel de uso, chave por chave, se o consumo do pipeline fica dentro da cota e se a cota barra o excesso antes do fim do mês.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Na prática
Salve como scripts/registrar_bancada.py e rode com o .venv ativo: assim a linha do Python mostra a versão do ambiente virtual, que pode diferir da do sistema. O script procura cada programa no PATH (no Windows, acha também os atalhos .cmd que o npm instala), roda o comando de versão sem passar pelo shell e grava logs/bancada-AAAA-MM-DD.json. Sai com código 1 se algo faltar ou estiver abaixo do mínimo, então serve também como primeiro passo de qualquer script maior.
"""Fotografa as versões da bancada e compara com o mínimo do curso.
Rode na pasta video-ia: python scripts/registrar_bancada.py (macOS e Linux: python3)
Grava logs/bancada-AAAA-MM-DD.json: o arquivo que você entrega ao agente no lugar de prints.
"""
import json, re, shutil, subprocess, sys
from datetime import date
from pathlib import Path
# Ferramenta: (comando de versão, versão mínima do curso ou None para só registrar)
MINIMOS = {
"node": (["node", "--version"], (22, 0)),
"python": ([sys.executable, "--version"], (3, 12)),
"ffmpeg": (["ffmpeg", "-version"], (8, 0)),
"codex": (["codex", "--version"], None),
"claude": (["claude", "--version"], None),
}
foto, problemas = {"data": str(date.today())}, []
for nome, (cmd, minimo) in MINIMOS.items():
caminho = shutil.which(cmd[0]) # no Windows acha também o .cmd e o .exe
if not caminho:
foto[nome] = "AUSENTE"
problemas.append(f"{nome}: não está no PATH")
continue
# shell=False e lista de argumentos: nada do texto vira comando
saida = subprocess.run([caminho, *cmd[1:]], capture_output=True, text=True, timeout=30).stdout.splitlines()
linha = saida[0].strip() if saida else "sem saída"
foto[nome] = linha
achou = re.search(r"(\d+)\.(\d+)", linha)
if minimo and achou and tuple(map(int, achou.groups())) < minimo:
problemas.append(f"{nome}: {linha} abaixo de {'.'.join(map(str, minimo))}")
Path("logs").mkdir(exist_ok=True)
destino = Path(f"logs/bancada-{date.today()}.json")
destino.write_text(json.dumps(foto, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps(foto, ensure_ascii=False, indent=2))
print("\n".join(problemas) if problemas else f"OK: bancada dentro do mínimo; foto em {destino}")
sys.exit(1 if problemas else 0)Da foto da bancada à chave com cota
Cinco passos; só o último mexe numa conta de fornecedor.
Passo 1: Ative o .venv e rode o script
python scripts/registrar_bancada.py
Deu certo quando: O JSON mostra node, python, ffmpeg, codex e claude, e a última linha diz OK.
Erro comum: Rodar fora do .venv e registrar o Python do sistema.
Passo 2: Compare a foto com a de outra máquina
Abra os dois JSON lado a lado ou peça ao agente só a diferença entre eles.
Deu certo quando: Você aponta a ferramenta e a versão que divergem.
Erro comum: Mandar prints de tela, que o agente lê pior do que o JSON.
Passo 3: Escolha a linha do Node para a equipe
Deu certo quando: Todas as máquinas na mesma linha LTS, 22 ou 24.
Erro comum: Atualizar uma só máquina para a 26 e ver o comportamento mudar entre colegas.
Passo 4: Teste o Python 3.15 num ambiente separado
python3.15 -m venv .venv-teste, instale os pacotes e rode os scripts das aulas.
Deu certo quando: O ambiente de teste instala os pacotes do curso e os scripts passam; só então o principal muda.
Erro comum: Trocar o .venv principal no dia do lançamento e descobrir um pacote sem versão para a 3.15 no meio da semana.
Passo 5: Crie a chave restrita da ElevenLabs
No painel, limite as rotas que o pipeline usa e defina a cota de créditos; grave a chave nova no .env, sem passar pelo chat.
Deu certo quando: O .env do projeto aponta para a chave restrita, e a antiga deixa de ser usada pelo pipeline.
Erro comum: Restringir demais e só descobrir na hora da narração; faça um teste curto de voz logo depois.
No fim você tem: Uma bancada descrita por um JSON datado, a mesma linha de Node na equipe e uma chave de voz com teto do próprio fornecedor.
Armadilhas
Montar a bancada para durar
Evite
Coluna a evitar
- Instalar a versão mais nova de tudo no dia em que sai
- Uma chave só para site, pipeline e testes
- Descrever a bancada ao agente de memória
- Node diferente em cada máquina da equipe
- Registrar o Python do sistema no lugar do .venv
Faça assim
Coluna recomendada
- Seguir uma linha LTS e testar a nova num ambiente à parte
- Uma chave restrita por uso, com cota de créditos
- Entregar o JSON datado de logs/bancada-*.json
- A mesma linha LTS em todas as máquinas
- Rodar o registro com o .venv ativo
Antes de automatizar os três vídeos por semana, a Cozinha da Rafa roda a chamada pequena e sabe onde ficam os registros. Quando a voz do vídeo da tapioca falhar no meio da produção, a Rafa não pede ao agente que rode tudo de novo: entrega o trecho do log da etapa de narração, aponta a tentativa pendente e preserva o roteiro e as imagens já aprovados.
Os termos novos desta aula ficam reunidos abaixo.
Glossário rápido
terminal
Janela onde você digita comandos em vez de clicar, como pedir no balcão em vez de procurar na prateleira.
CLI
Interface de linha de comando: programa que você opera pelo terminal, como claude, codex e ffmpeg.
PATH
Lista de pastas onde o terminal procura um programa quando você digita o nome dele, como uma agenda de endereços.
caminho relativo
Endereço de um arquivo a partir da pasta atual, como audio/narracao.mp3; o absoluto parte da raiz do disco.
variável de ambiente
Recado que o sistema entrega ao programa quando ele começa, como a ficha que acompanha o pedido na cozinha.
.env
Arquivo de texto local com as variáveis de ambiente do projeto; não é criptografia e nunca vai para o Git nem para o chat.
ambiente virtual
Pasta .venv onde ficam os pacotes Python de um projeto, isolados do resto da máquina.
código HTTP
Número com que o serviço responde a um pedido, como a senha do balcão que diz se ele foi aceito.
retry
Repetir uma tentativa; sem saber se a primeira foi processada, pode duplicar trabalho e custo.
teto de gasto
Limite de dinheiro que um script ou uma conta pode consumir antes de parar de enviar pedidos.
Rode o diagnóstico, crie o .env, faça as três simulações e, se puder, a chamada autorizada. Está pronto quando as ferramentas aparecem como ENCONTRADO com Node 22 ou superior e Python 3.12 ou superior, o .env está no .gitignore e nunca apareceu na tela, as simulações estão no log com simulado: true e o teste online está confirmado ou anotado como pendente.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code CLI: Programação com IA
- CursoAstra profundosugerido pelo grafoA quinta parte do Astra planeja o vídeo e edita o material bruto com o modelo dirigindo a ferramenta. O curso de vídeo com IA aprofunda esse trabalho com Claude Code, Codex e ElevenLabs, do roteiro à publicação. O grafo já sugeria esta ordem pela regra de entrada da trilha; com a ordem anterior curada, ela passa a ser declarada (Etapa 4, wave 3).
- CursoSetup Completo: do zero ao Claude Codesugerido pelo grafo7 capítulos de “Vídeo com IA: Claude Code, Codex e ElevenLabs” usam conceitos apresentados em “Setup Completo: do zero ao Claude Code”.
Depois, siga para
- CursoFrontends com Vibecodingsugerido pelo grafo21 capítulos de “Frontends com Vibecoding” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoDo Agile ao Agentic Operating Modelsugerido pelo grafo5 capítulos de “Do Agile ao Agentic Operating Model” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoAgentes de IA Autônomos: Do Conceito à Produçãosugerido pelo grafo7 capítulos de “Agentes de IA Autônomos: Do Conceito à Produção” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoLLM FinOps: o custo da IA para quem assina o orçamentosugerido pelo grafo4 capítulos de “LLM FinOps: o custo da IA para quem assina o orçamento” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
O mesmo assunto em outros cursos
- Claude Code CLI: Programação com IAInstalar o Claude Code e fazer o primeiro acesso sem o TIExaminar conexões de Instalar o Claude Code e fazer o primeiro acesso sem o TI
- MCP para quem decideInventariar o que já roda nas máquinas do timeExaminar conexões de Inventariar o que já roda nas máquinas do time
- Frontends com VibecodingConfigurar ambiente, skills e o contêiner de contextoExaminar conexões de Configurar ambiente, skills e o contêiner de contexto
- Python: Programação do ZeroAmbientes virtuais e pipExaminar conexões de Ambientes virtuais e pip
Voltar ao capítulo anterior: Desenhar o pipeline de vídeo do briefing à publicação
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
MediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Grave a cena em tempo real e veja os quadros que se perdem
Suba as partículas, force um bloqueio de 300 ms e grave seis segundos; compare com o render quadro a quadro desta aula.
Pacote
Abrir no capítuloMontar vídeo em HTML com HyperFrames e escolher entre ele e o Remotionsem pacoteMotion
Ver agentes em paralelo trocando mensagens numa linha do tempo
Reproduza a cena, percorra o tempo pelo controle e compare o tempo de parede com a soma das barras de cada agente.
Pacote
Abrir no capítuloParalelizar cenas com subagentes sem estourar o limite das APIsmotionReact (sem dependência extra), com as APIs do Veo e do fal.ai
Prompt de vídeo em cinco camadas, pronto para a API
Escolha plano, câmera, luz, ação e áudio e copie o prompt e o JSON para o Veo ou para o fal.ai.
Pacote
Abrir no capítuloEscrever prompt de vídeo em cinco camadas e manter o personagem consistentereactReact (sem dependência extra), com o comando para o FFmpeg
Corte o vídeo apagando palavras da transcrição
Aperte as palavras para removê-las, ligue a remoção de pausas e copie o comando FFmpeg e a legenda SRT gerados.
Pacote
Abrir no capítuloRemover pausas e reenquadrar o vídeo de 16:9 para 9:16 com legenda por palavrareactReact (sem dependência extra)
Quanto custa cada etapa do seu pipeline de vídeo
Troque a ferramenta de cada etapa e o percentual de b-roll e veja qual etapa pesa no custo por minuto e por vídeo.
Pacote
Abrir no capítuloOrquestrar o pipeline com etapas idempotentes e teto de gastoreact
Capítulos vizinhos em Vídeo com IA: Claude Code, Codex e ElevenLabs
- 01Escolher uma arquitetura de vídeo com IA que funciona em outubro de 2026
- 02Desenhar o pipeline de vídeo do briefing à publicação
- 03Montar a bancada de vídeo com IA mesmo sem nunca ter usado o terminal
- 04Cortar, juntar, mixar e exportar vídeo com FFmpeg sem abrir editor
- 05Montar vídeo em React com Remotion e renderizar na sua máquina ou na AWS