Criar um vídeo narrado

Um passo a passo de ponta a ponta que escreve um roteiro com um LLM, gera clipes, sintetiza uma narração e combina tudo — usando uma única chave de API.

Este tutorial encadeia três tipos de modelo em um mesmo script: um modelo de linguagem escreve a narração, um modelo de vídeo gera as imagens e um modelo de fala lê o roteiro em voz alta. É um exemplo realista de por que ter uma única API e um saldo comum entre tipos de modelo é útil.

O que você precisa: Python 3.9+, uma chave de API e o ffmpeg, se quiser juntar áudio e vídeo no final.

Isto executa tarefas de geração reais e consome créditos reais. O vídeo é a parte cara — comece com uma duração curta enquanto estiver iterando e use a estimativa de preços se quiser um número exato antes.

Preparação

pip install requests
export ATLASCLOUD_API_KEY="your-api-key"

Passo 1 — Funções auxiliares compartilhadas

Toda tarefa de mídia segue o mesmo formato de enviar e depois consultar, então defina isso uma vez só.

import os, time, requests

API_KEY = os.environ["ATLASCLOUD_API_KEY"]
BASE = "https://api.atlascloud.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
TERMINAL = {"completed", "succeeded", "failed", "timeout"}


def submit(endpoint: str, model: str, **params) -> str:
    """Envia uma tarefa. Atenção: os parâmetros ficam no nível superior, não dentro de input."""
    r = requests.post(f"{BASE}/model/{endpoint}",
                      headers=HEADERS, json={"model": model, **params}, timeout=60)
    r.raise_for_status()
    return r.json()["data"]["id"]


def wait(prediction_id: str, timeout: int = 900) -> dict:
    """Consulta até o estado final, com o intervalo crescendo aos poucos."""
    deadline, delay = time.time() + timeout, 2.0
    while time.time() < deadline:
        r = requests.get(f"{BASE}/model/prediction/{prediction_id}",
                         headers=HEADERS, timeout=30)
        r.raise_for_status()
        data = r.json()["data"]
        if data.get("status") in TERMINAL:
            if data["status"] in ("failed", "timeout"):
                raise RuntimeError(f"A tarefa falhou: {data.get('error') or data['status']}")
            return data
        time.sleep(delay)
        delay = min(delay * 1.5, 10.0)
    raise TimeoutError(prediction_id)


def download(url: str, path: str) -> str:
    r = requests.get(url, timeout=300)
    r.raise_for_status()
    with open(path, "wb") as f:
        f.write(r.content)
    return path

Passo 2 — Escrever o roteiro com um LLM

Modelos de linguagem usam uma base URL diferente e são síncronos, então não passam por submit/wait.

def write_narration(topic: str) -> str:
    r = requests.post(
        "https://api.atlascloud.ai/v1/chat/completions",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={
            "model": "deepseek-ai/deepseek-v3.2",
            "messages": [
                {"role": "system",
                 "content": "You write narration for short videos. "
                            "Reply with two sentences of spoken narration and nothing else."},
                {"role": "user", "content": f"Topic: {topic}"},
            ],
            "max_tokens": 200,
        },
        timeout=120,
    )
    r.raise_for_status()
    return r.json()["choices"][0]["message"]["content"].strip()


narration = write_narration("how ocean waves shape a coastline")
print(narration)

Passo 3 — Gerar as imagens

video_id = submit(
    "generateVideo",
    "alibaba/wan-2.5/text-to-video",
    prompt="slow aerial shot of waves breaking against a rocky coastline at golden hour",
    duration=5,
)
video = wait(video_id)
download(video["outputs"][0], "footage.mp4")

A geração de vídeo leva minutos, não segundos. Em produção, registre um webhook e deixe a tarefa chamar você de volta, em vez de manter um laço de polling aberto.

Passo 4 — Sintetizar a narração

A narração do passo 2 vira a entrada aqui. Fala, música e transcrição compartilham o mesmo endpoint — é o modelo que decide qual delas você obtém.

audio_id = submit(
    "generateAudio",
    "bytedance/seed-audio-1.0",
    text=narration,
    format="mp3",
    sample_rate=44100,
    speech_rate=-5,   # Um pouco mais devagar, a narração fica mais fácil de entender
)
audio = wait(audio_id)
download(audio["outputs"][0], "voiceover.mp3")

Veja Modelos de áudio para o conjunto completo de parâmetros, incluindo vozes de referência.

Passo 5 — Combinar

ffmpeg -i footage.mp4 -i voiceover.mp3 \
  -c:v copy -c:a aac -shortest narrated.mp4

Opcional — Gerar legendas

Passe a narração por um modelo de transcrição para obter marcações de tempo por palavra e montar legendas.

stt_id = submit(
    "generateAudio",
    "bytedance/seed-asr-2.0",
    audio_url=audio["outputs"][0],   # Atenção: o campo se chama audio_url
    enable_punc=True,
    show_utterances=True,
)
stt = wait(stt_id)

# Em modelos de transcrição, outputs[0] é o próprio texto, não uma URL de arquivo
print(stt["outputs"][0])
for word in stt.get("stt_result", {}).get("words", [])[:10]:
    print(word["start"], word["end"], word["text"])

Modelos de transcrição recebem audio_url, mas alguns outros modelos de fala para texto recebem audio. Consulte a referência de API do modelo — passar o nome de campo errado falha na validação.

Para onde ir agora

  • Troque o modelo de vídeo por um que aceite uma imagem de referência e conduza o visual a partir de um quadro que você fornecer
  • Migre do polling para webhooks, para que tarefas longas não bloqueiem o seu processo
  • Execute vários clipes em paralelo e concatene-os em uma sequência mais longa
  • Adicione o tratamento de novas tentativas de Erros e limites de taxa

Relacionado

Last updated on

On this page