HiAPI
Blogue

Tutorial

Como usar kling-4.0/text-to-video através da API HiAPI: curl, Python e um exemplo de requisição executável

Guia prático para desenvolvedores: prompts cinematográficos, áudio sincronizado, polling assíncrono e download da saída

Nov 3, 2026
深炭底色上一条宽大的琥珀色光带斜扫而过,下方配一条细窄的暗棕平行条带,整体用于文章封面。

Funcionalidades e cenários de uso do kling-4.0/text-to-video

kling-4.0/text-to-video é um modelo de vídeo generativo disponibilizado através da API unificada HiAPI. Você fornece um prompt de texto e ele retorna um clipe de vídeo — movimento, movimento de câmera e composição da cena são totalmente determinados pela sua descrição. Este é um endpoint de texto para vídeo: não há imagem de origem para animar, portanto o modelo tem total autonomia sobre o enquadramento e a aparência do sujeito.

Cenários de uso:

  • Você precisa gerar clipes cinematográficos curtos a partir de um roteiro ou modelo de prompt — b-roll, trailers, concept boards, vídeos para redes sociais.
  • Você deseja que áudio sincronizado seja gerado junto com o vídeo, em vez de obter um arquivo silencioso que precisa de trilha sonora na pós-produção.
  • Você está construindo um pipeline no qual a geração de vídeo é apenas uma entre várias etapas (escrita de roteiro, preparação de materiais, publicação), portanto precisa de uma API HTTP em vez de uma interface Web.

No entanto, se você precisa de controle preciso quadro a quadro sobre um sujeito real específico (modelos de imagem para vídeo ou edição têm melhor desempenho nisso), ou se precisa de resposta síncrona na requisição do usuário, este modelo não é adequado — a geração de vídeo leva tempo, então este endpoint é assíncrono por design.

Como todas as requisições passam pela HiAPI, as credenciais, o formato de requisição/resposta e o ciclo de vida da tarefa são os mesmos independentemente do modelo usado na plataforma. Essa consistência é a razão prática para construir sobre ela: adicionar ou substituir modelos no futuro não exige reescrever a camada de autenticação ou polling.

Pré-requisitos e autenticação na HiAPI

Antes de enviar a primeira requisição, certifique-se de ter:

  • Uma conta HiAPI e uma chave de API de projeto. Trate-a como confidencial — nunca a envie para repositórios de código, nunca a coloque no código do cliente.
  • O cliente HTTP de sua escolha. Os exemplos abaixo usam curl e requests do Python 3.
  • O identificador do modelo, exatamente como aparece no catálogo: kling-4.0/text-to-video. Erros de digitação no nome do modelo são a causa mais comum de falha na primeira chamada.

As credenciais são enviadas como cabeçalho HTTP em cada requisição (incluindo as de polling). O padrão usual na HiAPI é o bearer token:

export HIAPI_API_KEY="your-api-key-here"

E então na requisição:

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

Guarde a URL base e a chave em variáveis de ambiente ou em um gerenciador de segredos, em vez de codificá-las diretamente. Para desenvolvimento local, um arquivo .env com consulta via os.environ no Python é suficiente. Para serviços implantados, injete os segredos em tempo de execução.

Um hábito de configuração que vale a pena adquirir cedo: construa primeiro uma pequena chamada do tipo "quem sou eu" — qualquer requisição leve de autenticação — para confirmar que a chave e a URL base estão corretas antes de depurar tarefas de vídeo. Isolar a autenticação da lógica do modelo economiza tempo no futuro.

Uma requisição curl executável

A chamada mínima cria uma tarefa e retorna o identificador da tarefa. A estrutura é:

curl -X POST "$HIAPI_BASE_URL/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-4.0/text-to-video",
    "prompt": "A slow aerial push over a rain-soaked Tokyo alley at night, neon signs reflecting in puddles, steam rising from vents, shallow depth of field, cinematic color grading",
    "generate_audio": true
  }'

Interpretação campo a campo do corpo da requisição:

  • model — o identificador do modelo. Obrigatório.
  • prompt — a descrição da sua cena. A maior parte do seu orçamento de qualidade está aqui; consulte a seção sobre prompts.
  • generate_audio — solicita a geração de áudio sincronizado junto com o vídeo. Se você só precisa da faixa visual, omita ou defina como false.

A resposta é um objeto de tarefa, não o vídeo concluído. Espere um campo de status e um id que você usará para o polling — por exemplo, status queued ou processing, mais um id de tarefa. Armazene esse id imediatamente; se o seu processo terminar, o id é a única credencial do trabalho em andamento.

Duas dicas práticas. Primeiro, quando os prompts ficarem longos, salve o JSON em um arquivo e use -d @payload.json — o tratamento de quoting no shell para prompts multilinha é uma fonte comum de erros. Segundo, capture separadamente o corpo da resposta e o código de status HTTP (curl -s -w "\n%{http_code}") para distinguir requisições rejeitadas de falhas de rede.

Convertendo a requisição para Python

A mesma requisição em Python, com estrutura que pode ser usada diretamente em scripts reais:

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def create_video_job(prompt: str, generate_audio: bool = True) -> dict:
    payload = {
        "model": "kling-4.0/text-to-video",
        "prompt": prompt,
        "generate_audio": generate_audio,
    }
    resp = requests.post(
        f"{BASE_URL}/video/generations",
        headers=HEADERS,
        json=payload,
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()

if __name__ == "__main__":
    job = create_video_job(
        "A slow aerial push over a rain-soaked Tokyo alley at night, "
        "neon signs reflecting in puddles, steam rising from vents, "
        "shallow depth of field, cinematic color grading"
    )
    print(job)

Por que escrever assim:

  • requests.post(..., json=payload) cuida da serialização e do content type de uma vez, evitando json.dumps manual.
  • raise_for_status() converte 4xx/5xx em exceções capturáveis, em vez de analisar silenciosamente um corpo de erro como se fosse uma tarefa.
  • timeout é obrigatório. Sem ele, uma conexão travada bloqueia o worker indefinidamente.
  • A configuração fica em constantes de módulo lidas do ambiente, de modo que a função é testável e reutilizável.

Esta função apenas cria a tarefa. Ela retorna imediatamente o handle da tarefa — que é exatamente o que você quer em um handler Web ou worker de fila. As seções seguintes mostram como aguardar o resultado.

Escrevendo prompts cinematográficos que resistem ao teste

Modelos de texto para vídeo recompensam estrutura. Um prompt que especifica sujeito, câmera, movimento e emoção sempre supera uma ideia de uma única frase, porque cada elemento elimina uma ambiguidade que o modelo decidiria aleatoriamente.

Um template útil:

[sujeito e cena], [posição da câmera e movimento],
[movimento dentro do quadro], [iluminação], [atmosfera ou color grading], [referência de estilo]

Exemplo de aplicação:

Ao amanhecer, um ciclista solitário de capa de chuva amarela atravessa uma ponte de pedra, câmera baixa acompanhando em paralelo na altura das rodas, névoa flutuando sobre a água, luz suave de hora azul com toques quentes de lanternas, calmo e levemente melancólico, textura de lente anamórfica widescreen.

O papel de cada parte:

  • Sujeito e cena — substantivos concretos são melhores que conceitos abstratos. "Um ciclista solitário de capa de chuva amarela" dá ao modelo algo para renderizar; "liberdade" não.
  • Câmera — posição (câmera baixa, aérea, no nível dos olhos) e movimento (acompanhamento, push-in lento, estática) são as alavancas mais poderosas para o valor de produção visual.
  • Movimento dentro do quadro — névoa flutuando, tecido balançando, ondulações na água. Vídeo precisa de movimento; declare-o explicitamente.
  • Iluminação e atmosfera — hora do dia, temperatura de cor, tom emocional. Mantenha-os coerentes entre si.
  • Estilo — linguagem de lente ou formato (lente anamórfica, profundidade de campo rasa, color grading cinematográfico) molda a textura de forma mais confiável do que nomear um diretor.

Mantenha o prompt como algumas frases de descrição densa, em vez de um parágrafo de ideias concorrentes. Se um plano exige duas ações claramente distintas, gere dois clipes. E itere: mude uma variável por vez — primeiro a câmera, depois a iluminação — para entender a que o modelo responde, em vez de adivinhar.

Tratando tarefas assíncronas e polling

A geração de vídeo não é instantânea, então o padrão é criar primeiro, depois fazer polling. Você já tem a parte de criação; aqui está o laço:

import time

def wait_for_job(job_id: str, timeout: int = 600) -> dict:
    deadline = time.monotonic() + timeout
    delay = 2.0
    while time.monotonic() < deadline:
        resp = requests.get(
            f"{BASE_URL}/video/generations/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        resp.raise_for_status()
        job = resp.json()
        status = job.get("status")

        if status == "succeeded":
            return job
        if status in ("failed", "cancelled"):
            raise RuntimeError(f"Job {job_id} ended with status {status}: {job}")

        time.sleep(delay)
        delay = min(delay * 1.5, 15.0)  # back off, cap at 15s

    raise TimeoutError(f"Job {job_id} did not finish in {timeout}s")

Decisões de design importantes em produção:

Faça polling com backoff, não em loop apertado

Comece com intervalo curto e aumente gradualmente — o backoff exponencial acima tem teto em um limite fixo. Polling rápido contínuo consome seu rate limit sem benefício, porque o tempo de geração não diminui só porque você perguntou mais cedo.

Sempre defina um prazo final

Todo laço de polling precisa de tempo máximo de relógio e de um erro explícito ao ultrapassá-lo. Caso contrário, uma tarefa travada ocupa um worker para sempre silenciosamente.

Trate estados terminais como definitivos

Distinga estados em andamento (queued, processing) de estados terminais (succeeded, failed, cancelled). Só retorne a saída em caso de sucesso; outros estados devem lançar exceção ou seguir para um caminho de retry, em vez de continuar o laço.

Desacople o polling do handler de requisições

Em um servidor Web, não deixe a resposta HTTP bloquear esperando o vídeo. Crie a tarefa, devolva o id ao cliente e faça o polling a partir de um worker em background ou consumidor de fila. Persista o id da tarefa e seu último estado conhecido, para que reinícios não percam o rastreamento do trabalho em andamento.

Baixando e validando a saída

Quando a tarefa atinge succeeded, a resposta traz uma referência à mídia gerada — geralmente uma URL para o arquivo concluído. Baixe prontamente e trate essa URL como temporária: obtenha, armazene e registre sua própria localização persistente, em vez de passar a URL do provedor diretamente ao usuário final.

import pathlib

def download_output(job: dict, dest: pathlib.Path) -> pathlib.Path:
    url = job["output"]["video_url"]
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        dest.parent.mkdir(parents=True, exist_ok=True)
        with open(dest, "wb") as f:
            for chunk in r.iter_content(chunk_size=1 << 20):
                f.write(chunk)
    return dest

Etapas de validação que valem a pena antes de entregar o arquivo a qualquer pessoa:

  • Verifique se a transferência foi concluída. Faça streaming em chunks, compare o tamanho gravado com o Content-Length (se presente) e falhe ruidosamente em caso de leitura insuficiente.
  • Confirme a faixa de áudio. Se você solicitou generate_audio, o arquivo deve ter um stream de áudio. Uma verificação rápida com ffprobe é o teste mais barato:
ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output.mp4

Você deve ver tanto a linha video quanto a linha audio. Se o áudio estiver ausente, verifique se a flag foi definida na chamada de criação — não é possível adicioná-lo depois.

  • Faça uma validação básica de duração e resolução em relação à sua expectativa, para capturar renders truncados ou com especificações erradas antes da publicação.
  • Armazene com chave determinística (id da tarefa mais hash), grave primeiro em um caminho temporário, renomeie após o sucesso e mantenha o id da tarefa junto ao ativo para rastreabilidade.

Se o download falhar no meio da transferência, tente novamente com backoff; se a URL tiver expirado, você precisará buscar novamente o registro da tarefa para obter uma nova referência.

Encapsulando em um cliente reutilizável

As partes acima formam naturalmente uma classe. Juntando tudo, você obtém algo importável entre projetos, sem precisar copiar:

class KlingTextToVideo:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url.rstrip("/")
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        }

    def generate(self, prompt: str, generate_audio: bool = True,
                 timeout: int = 600) -> dict:
        job = create_video_job(prompt, generate_audio)  # create half
        return wait_for_job(job["id"], timeout=timeout)  # poll half

À medida que o cliente amadurece, algumas coisas precisam ser adicionadas:

  • Logs estruturados com o id da tarefa como chave — transições de status, número de pollings, tempo decorrido e falhas. Quando um render sai errado, o id da tarefa é a chave de correlação entre os logs.
  • Retries limitados apenas para erros transitórios (rede, 5xx). Nunca repita cegamente uma requisição rejeitada; um corpo de requisição malformado falhará da mesma forma todas as vezes, apenas desperdiçando cota.
  • Idempotência na sua camada. Se o seu serviço pode enviar o mesmo prompt duas vezes, deduplique antes de chamar a criação, em vez de pagar por duas tarefas.
  • Mantenha templates de prompt como dados, não como código. Coloque os templates cinematográficos em arquivos de configuração, para que a iteração de prompts não exija deploy.
  • Contabilize custos por segundo de saída. A cobrança é baseada no uso de saída gerado, então rastreie a duração gerada por tarefa para atribuir gastos a funcionalidades ou usuários.

Com o cliente pronto, o pipeline é curto: construa o prompt a partir do template, chame generate, baixe e inspecione a saída, depois entregue o arquivo armazenado à sua aplicação. Se você adicionar outros modelos na HiAPI no futuro, os mesmos cabeçalhos de autenticação, ciclo de vida de tarefa e padrão de download se aplicam — essa é a principal razão para construir a camada de abstração uma única vez.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API