Como criar um gerador de imagens com IA em Python (passo a passo)
Escreva um script em Python que envia um prompt de texto para um modelo de imagem, aguarda o processamento e salva a imagem. Monte-o em quatro etapas e depois adicione uma linha de comando, lotes com threads, uma rota no Flask e correções para os erros que você vai encontrar.
A maioria dos tutoriais sobre imagens com IA para em "cole um prompt em um site". Isso funciona para uma imagem só. Mas deixa de funcionar quando você precisa de cinquenta fotos de produtos, um lote noturno de miniaturas para o blog ou um pequeno app em que visitantes digitam uma frase e recebem uma fotografia de volta. Para isso você precisa de código, e a boa notícia é que um gerador de imagens funcional em Python cabe em cerca de 60 linhas.
Este tutorial monta o gerador em quatro etapas pequenas: enviar um prompt para um modelo hospedado, aguardar o término do processamento, baixar o arquivo e, por fim, envolver tudo em uma ferramenta de linha de comando que roda lotes. Cada etapa termina com uma verificação rápida, para que você saiba que funciona antes de avançar.
💡 Resposta rápida: um gerador de imagens com IA em Python é um script que envia um prompt de texto para um modelo via HTTP, consulta o status até a imagem ficar pronta e então salva o arquivo. O modelo roda na GPU de outra pessoa. Seu código precisa de requests, de um token secreto e de um loop.
Antes de escrever qualquer linha
Você precisa de três coisas: Python 3.10 ou mais recente, um terminal e um token secreto para o serviço de imagens. O código abaixo conversa com a API do PicassoIA por HTTP simples, então não há driver de GPU para instalar nem arquivo de modelo para baixar.
Configure o projeto
Crie uma pasta, um ambiente virtual e instale um único pacote:
Em seguida, crie um token na página da API e guarde-o em uma variável de ambiente, e não no arquivo de código. Uma conta pode ter até dois tokens ao mesmo tempo.
No PowerShell do Windows, a mesma linha fica $env:PICASSOIA_API_TOKEN = "pia_sk_your_token_here".
⚠️ Nunca cole o token no seu script. Tudo o que vai para o git fica no histórico, mesmo depois de você apagar. Uma variável de ambiente mantém o segredo fora do repositório.
Escolha primeiro um modelo
O modelo define como suas imagens ficam e a velocidade com que chegam. O script deste tutorial chama picassoia/picassoia-image pela API. Os modelos da tabela abaixo estão todos disponíveis no navegador, no PicassoIA, o que os torna úteis para testar prompts antes de levá-los ao código.
Um modelo de difusão parte de ruído aleatório e o remove em muitas pequenas passagens, guiado pelo seu prompt em cada uma delas. Cada passagem é um cálculo pesado em uma rede neural grande. É por isso que a geração de imagens exige uma GPU potente, e por que a primeira decisão de design no seu projeto em Python é onde essa GPU vai ficar.
GPU local ou API hospedada. Rodar um modelo na sua própria máquina dá controle total, mas também significa um conjunto de drivers, dezenas de gigabytes de pesos e uma placa com bastante memória. Uma API hospedada troca parte desse controle por uma configuração que leva minutos.
Fator
GPU local
API hospedada
Tempo de configuração
Horas
Minutos
Hardware
Placa de vídeo recente com 12 GB ou mais de memória
Qualquer notebook
Escolha de modelo
O que você baixar
O que o serviço oferecer
Escalabilidade
Comprar outra placa
Aumentar sua concorrência
Dependências do Python
Pesadas
Apenas requests
Por que os trabalhos são assíncronos. Gerar uma imagem leva de menos de um segundo a cerca de um minuto, dependendo do modelo. Manter uma conexão HTTP aberta por todo esse tempo é frágil, então a API funciona em três movimentos: criar uma previsão, consultar seu status e buscar o resultado quando o status indicar succeeded. Seu código reproduz esses três movimentos na próxima seção.
Passo a passo: o primeiro script
Coloque tudo em um único arquivo chamado generate.py. As quatro etapas abaixo o constroem de cima a baixo.
Etapa 1: configure a requisição
A API segue o padrão do Replicate: uma URL base, o nome do modelo no caminho e um token Bearer no cabeçalho.
import os
import time
from pathlib import Path
import requests
API_BASE = "https://api.picassoia.com/v1"
MODEL = "picassoia/picassoia-image"
TOKEN = os.environ["PICASSOIA_API_TOKEN"]
HEADERS = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
Se a variável estiver ausente, o Python para com um erro logo aqui, que é exatamente o que você quer. Uma falha clara no topo do arquivo é melhor do que um 401 confuso mais adiante.
A função devolve um ID de trabalho, não uma imagem. Os prompts podem ter até 4.000 caracteres, bem mais do que você vai precisar.
Etapa 3: consulte até terminar
def wait_for_result(job_id: str, poll_every: float = 2.0, limit: float = 300.0) -> str:
url = f"{API_BASE}/predictions/{job_id}"
deadline = time.time() + limit
while time.time() < deadline:
response = requests.get(url, headers=HEADERS, timeout=30)
response.raise_for_status()
data = response.json()
status = data["status"]
if status == "succeeded":
output = data["output"]
return output[0] if isinstance(output, list) else output
if status in ("failed", "canceled"):
raise RuntimeError(f"Job {job_id} ended as {status}: {data.get('error')}")
time.sleep(poll_every)
raise TimeoutError(f"Job {job_id} did not finish within {limit} seconds")
💡 Dica: os nomes dos campos seguem o formato do Replicate. Se alguma resposta parecer diferente, imprima response.json() uma vez e ajuste as duas linhas que contêm status e output. O loop também define seu próprio prazo, então um trabalho travado nunca congela o script.
Etapa 4: salve o arquivo
def download(image_url: str, folder: str = "output") -> Path:
Path(folder).mkdir(exist_ok=True)
name = image_url.split("/")[-1].split("?")[0] or f"image-{int(time.time())}.png"
target = Path(folder) / name
response = requests.get(image_url, timeout=60)
response.raise_for_status()
target.write_bytes(response.content)
return target
if __name__ == "__main__":
prompt = "A misty mountain lake at sunrise, 35mm photograph, soft natural light, fine film grain"
job_id = create_prediction(prompt)
image_url = wait_for_result(job_id)
print("Saved", download(image_url))
Execute python generate.py. Depois de alguns segundos você deve ver Saved output/... e um novo arquivo na pasta output. Checkpoint: se você consegue abrir essa imagem, as etapas 1 a 4 funcionam, e tudo o que vem depois é apenas empacotamento.
Transforme o script em uma ferramenta
Adicione uma linha de comando
Substitua o final do arquivo por um ponto de entrada argparse para que você possa passar prompts pelo terminal:
import argparse
def main() -> None:
parser = argparse.ArgumentParser(description="Generate an image from a text prompt")
parser.add_argument("prompt", help="what the image should show")
parser.add_argument("--out", default="output", help="folder for saved files")
args = parser.parse_args()
image_url = wait_for_result(create_prediction(args.prompt))
print(download(image_url, args.out))
if __name__ == "__main__":
main()
Agora python generate.py "a red bicycle leaning on a brick wall, 50mm photo" --out bikes faz todo o trabalho em uma linha.
Rode lotes dentro dos limites
Um loop que espera cada imagem na sequência é lento. As threads resolvem isso, porque o script passa quase todo o tempo esperando pela rede. A API permite 5 previsões simultâneas por conta, compartilhadas entre seus tokens e quaisquer apps conectados, então cinco workers é o teto.
from multiprocessing.pool import ThreadPool
def generate(prompt: str) -> Path:
return download(wait_for_result(create_prediction(prompt)))
def run_batch(prompts: list[str]) -> list[Path]:
with ThreadPool(5) as pool:
return pool.map(generate, prompts)
Se você também usar o site enquanto um lote roda, reduza para três workers para que os dois não disputem as mesmas cinco vagas. Um prompt que falha gera um erro dentro de pool.map, então envolva generate em um bloco try que registra o prompt e devolve None quando você roda centenas de uma vez.
Mantenha um registro. Acrescente cada prompt e nome de arquivo a um arquivo log.jsonl, para que você consiga rastrear qualquer imagem até o texto que a gerou. Chame essa função auxiliar dentro de generate, logo depois de download:
Daqui a seis semanas, quando alguém perguntar qual prompt gerou a foto do nascer do sol, esse arquivo responde em segundos.
Exponha como uma rota web
Equipes raramente querem um terminal. Um pequeno app em Flask permite que qualquer pessoa envie um prompt por uma página. Repare que a rota devolve o ID do trabalho imediatamente e uma segunda rota informa o progresso, então nenhuma requisição web fica travada por um minuto.
Seu front-end chama /generate e depois consulta /status/<id> a cada dois segundos até que status seja succeeded. O token fica no servidor, nunca no código do navegador.
Escreva prompts que se comportam bem
Monte prompts a partir de partes
Prompts vagos geram imagens vagas. Um prompt com um sujeito, um lugar, uma fonte de luz e uma lente resulta em algo repetível. Coloque essa estrutura em uma função para que cada imagem de um lote siga o mesmo padrão:
def build_prompt(subject: str, setting: str, light: str, lens: str = "50mm f/1.8") -> str:
return (
f"{subject}, {setting}, {light}, shot on a {lens} lens, "
"natural skin and surface texture, fine film grain, photorealistic"
)
print(build_prompt("a ceramic mug of black coffee", "on an oak desk", "soft window light from the left"))
Três hábitos tornam os resultados mais previsíveis:
Uma cena por prompt. Dois sujeitos disputando a atenção produzem imagens confusas.
Nomeie a luz. "Luz volumétrica da manhã vinda da esquerda" supera "iluminação bonita".
Nomeie a lente. Termos como 85mm e f/1.8 empurram o modelo para uma profundidade de campo rasa.
Faça um brainstorm com um modelo de linguagem
Escrever 50 prompts à mão fica cansativo lá pelo prompt doze. Um modelo de linguagem pode rascunhá-los para você. O Claude Sonnet 5 lida bem com listas estruturadas, e o Gemini 3.5 Flash devolve rascunhos rápidos quando você só precisa de volume. Peça 20 prompts que sigam a estrutura de sujeito, cenário, luz e lente, um por linha, e salve a resposta como prompts.txt. Depois, passe o arquivo para o seu executor de lotes:
prompts = [line.strip() for line in Path("prompts.txt").read_text().splitlines() if line.strip()]
run_batch(prompts)
Como usar o P Image no PicassoIA
Antes de gastar tempo com código, teste sua redação no navegador. O P Image responde em cerca de um segundo, então você pode testar dez variações no tempo que um modelo mais lento leva para renderizar um único resultado.
Abra a página do modelo e encontre a caixa de prompt.
Cole um prompt montado com o sujeito, o cenário, a luz e a estrutura de lente da seção anterior.
Escolha a proporção 16:9 para imagens de artigos, ou 1:1 para miniaturas.
Gere três variações e mude apenas um detalhe entre elas. Isso mostra qual palavra fez o trabalho.
Copie a redação vencedora para prompts.txt ou para a sua chamada de build_prompt.
💡 Se houver um campo de seed disponível, fixe a seed enquanto compara as redações. Com a seed travada, qualquer mudança no resultado vem do seu prompt e de mais nada.
Quando o P Image der o enquadramento certo, mas não o acabamento certo, rode o mesmo prompt pelo Flux 2 Pro ou pelo Seedream 4.5 e compare os resultados lado a lado. Cada modelo tem seus próprios hábitos, e dez minutos de teste economizam horas de reescrita depois.
Corrija os erros que você vai encontrar
Erros de autenticação
Um 401 ou 403 quase sempre significa que o token nunca chegou à requisição. Verifique se PICASSOIA_API_TOKEN está definida no mesmo terminal que executa o Python, já que uma variável exportada em uma janela não existe em outra. Verifique também se há aspas sobrando ou um espaço no fim do valor.
Limites e trabalhos travados
Sintoma
Causa provável
Correção
Resposta 429
Mais de 5 trabalhos rodando ao mesmo tempo
Reduza ThreadPool para 3 ou 4 e tente de novo após uma pausa curta
Resposta 400
Prompt com mais de 4.000 caracteres ou nome de campo errado
Encurte o prompt e imprima o corpo do erro
Trabalho nunca termina
Fila pesada ou trabalho travado
Mantenha o prazo de limit e tente uma vez mais
Status failed
O modelo rejeitou o prompt
Simplifique e remova símbolos incomuns
Para as novas tentativas, espere um pouco mais após cada falha (2, 4 e depois 8 segundos) e desista após três tentativas. Bombardear a API com novas tentativas instantâneas só mantém você acima do limite.
Resultados suaves ou borrados
Se o enquadramento está certo, mas o detalhe está suave, a causa geralmente é a resolução, não o prompt. Escolha um modelo que entregue alta resolução, como o Seedream 4.5, ou passe a imagem final por um modelo de Super Resolution no PicassoIA para aumentá-la de 2x a 4x. Verifique também se o prompt nomeia uma câmera e uma lente, já que "fotografia" sozinho deixa aberto demais.
Faça sua primeira imagem hoje
Agora você tem um script que transforma uma frase em uma fotografia, um executor de lotes que respeita o limite de cinco trabalhos e um modelo de prompt que você pode reutilizar em todos os projetos. O próximo passo mais rápido é pequeno: abra o P Image no navegador, teste três prompts, cole a melhor redação em prompts.txt e rode o lote.
Quando quiser escalar, a página da API do PicassoIA lista os endpoints, e a lista completa de modelos mostra os modelos de texto para imagem, vídeo e fala que você pode testar em seguida. O mesmo loop de criar, consultar e baixar funciona também para trabalhos de vídeo, então o script que você escreveu hoje é a base de um gerador de clipes amanhã. Escolha um prompt, rode o script e veja o que aparece na sua pasta de saída.