O que Meshy 3D — Geração + Impressão faz?
Comunique-se diretamente com a API do Meshy AI para gerar e imprimir ativos 3D. Abrange o ciclo de vida completo: configuração de chave API, criação de tarefas, polling com backoff exponencial, download, pipelines de várias etapas e preparação para impressão 3D com integração de slicer.
MANIFESTO DE SEGURANÇA
Variáveis de ambiente acessadas:
MESHY_API_KEY— Token de autenticação da API enviado apenas no cabeçalho HTTPAuthorization: Bearer. Nunca registrado em log, nunca gravado em nenhum arquivo, exceto.envno diretório de trabalho atual quando explicitamente solicitado pelo usuário.
Endpoints de rede externos:
https://api.meshy.ai— API do Meshy AI (criação de tarefas, polling de status, downloads de modelo/imagem)
Acesso ao sistema de arquivos:
- Leitura:
.envno diretório de trabalho atual apenas (consulta de chave API) - Escrita:
.envno diretório de trabalho atual apenas (armazenamento de chave API, somente por solicitação do usuário) - Escrita:
./meshy_output/no diretório de trabalho atual (arquivos de modelo baixados, metadados) - Leitura: arquivos fornecidos explicitamente pelo usuário (ex.: imagens locais passadas para conversão imagem-para-3D), acessados apenas no caminho exato especificado pelo usuário
- Sem acesso a diretórios home, perfis de shell ou qualquer caminho fora dos listados acima
Dados que saem desta máquina:
- Requisições de API para
api.meshy.aiincluem oMESHY_API_KEYno cabeçalho Authorization e prompts de texto fornecidos pelo usuário ou URLs de imagem. Nenhum outro dado local é transmitido. Arquivos de modelo baixados são salvos apenas localmente.
IMPORTANTE: Aviso de Primeiro Uso na Sessão
Quando este skill for ativado pela primeira vez em uma sessão, informe o usuário:
Todos os arquivos gerados serão salvos em
meshy_output/no diretório de trabalho atual. Cada projeto terá sua própria pasta ({YYYYMMDD_HHmmss}_{prompt}_{id}/) com arquivos de modelo, texturas, miniaturas e metadados. O histórico é rastreado emmeshy_output/history.json.
Isso só precisa ser dito uma vez por sessão.
IMPORTANTE: Organização de Arquivos
Todos os arquivos baixados DEVEM ir para um diretório estruturado meshy_output/ no diretório de trabalho atual. NÃO espalhe arquivos aleatoriamente.
- Cada projeto:
meshy_output/{YYYYMMDD_HHmmss}_{prompt_slug}_{task_id_prefix}/ - Tarefas em cadeia (preview → refine → rig) reutilizam o mesmo
project_dir - Rastreie tarefas em
metadata.jsonpor projeto e globalmente emhistory.json - Baixe miniaturas automaticamente junto com os modelos
IMPORTANTE: Regras de Comando Shell
Use apenas ferramentas POSIX padrão. NÃO use rg, fd, bat, exa/eza.
IMPORTANTE: Execute Tarefas Longas Corretamente
A geração do Meshy leva de 1 a 5 minutos. Escreva todo o fluxo create → poll → download como UM script Python e execute em uma única chamada Bash. Use python3 -u script.py para saída sem buffer. Tarefas paradas em 99% por 30–120s é uma finalização normal — NÃO interrompa.
Passo 0: Detecção de Chave API (SEMPRE EXECUTE PRIMEIRO)
Verifique apenas o ambiente da sessão atual e o arquivo .env no diretório de trabalho atual. NÃO escaneie diretórios home ou arquivos de perfil de shell.
echo "=== Detecção de Chave API Meshy ==="
# 1. Verificar variável de ambiente atual
if [ -n "$MESHY_API_KEY" ]; then
echo "ENV_VAR: ENCONTRADA (${MESHY_API_KEY:0:8}...)"
else
echo "ENV_VAR: NÃO_ENCONTRADA"
fi
# 2. Verificar .env no diretório de trabalho atual apenas
if [ -f ".env" ] && grep -q "MESHY_API_KEY" ".env" 2>/dev/null; then
echo "DOTENV(.env): ENCONTRADA"
export MESHY_API_KEY=$(grep "^MESHY_API_KEY=" ".env" | head -1 | cut -d'=' -f2- | tr -d '"\''" )
fi
# 3. Status final
if [ -n "$MESHY_API_KEY" ]; then
echo "PRONTO: key=${MESHY_API_KEY:0:8}..."
else
echo "PRONTO: NENHUMA_CHAVE_ENCONTRADA"
fi
# 4. Verificar requests do Python
python3 -c "import requests; print('PYTHON_REQUESTS: OK')" 2>/dev/null || echo "PYTHON_REQUESTS: AUSENTE (execute: pip install requests)"
echo "=== Detecção Completa ==="
Decisão Após Detecção
- Chave encontrada → Prossiga para o Passo 1.
- Chave NÃO encontrada → Vá para o Passo 0a.
- Requests do Python ausentes → Execute
pip install requests.
Passo 0a: Configuração de Chave API (Apenas Se Nenhuma Chave For Encontrada)
Diga ao usuário:
Para usar a API do Meshy, você precisa de uma chave de API:
- Vá para https://www.meshy.ai/settings/api
- Clique em "Create API Key", dê um nome, e copie a chave (começa com
msy_)- A chave é mostrada apenas uma vez — guarde-a em um local seguro
Nota: O acesso à API requer um plano Pro ou superior. Contas do plano gratuito não podem criar chaves de API.
Quando o usuário fornecer a chave, configure-a para a sessão atual e, opcionalmente, persista no .env:
# Configurar apenas para a sessão atual
export MESHY_API_KEY="msy_COLE_A_CHAVE_AQUI"
# Verificar a chave
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $MESHY_API_KEY" \
https://api.meshy.ai/openapi/v1/balance)
if [ "$STATUS" = "200" ]; then
BALANCE=$(curl -s -H "Authorization: Bearer $MESHY_API_KEY" https://api.meshy.ai/openapi/v1/balance)
echo "Chave válida. $BALANCE"
else
echo "Chave inválida (HTTP $STATUS). Verifique a chave e tente novamente."
fi
Para persistir a chave (apenas no projeto atual):
# Escrever no .env no diretório de trabalho atual
echo 'MESHY_API_KEY=msy_COLE_A_CHAVE_AQUI' >> .env
echo "Salva em .env"
# IMPORTANTE: adicione .env ao .gitignore para evitar vazamento da chave
grep -q "^\.env" .gitignore 2>/dev/null || echo ".env" >> .gitignore
echo ".env adicionado ao .gitignore"
Lembrete de segurança: A chave é armazenada apenas em
.envno diretório do seu projeto atual. Nunca comprometa este arquivo no controle de versão. O.envfoi adicionado automaticamente ao.gitignore.
Passo 1: Confirmar Plano com o Usuário Antes de Gastar Créditos
CRÍTICO: Antes de criar qualquer tarefa, apresente ao usuário um resumo de custos e aguarde confirmação:
Vou gerar um modelo 3D de "<prompt>" usando o seguinte plano:
1. Preview (geração de malha) — 20 créditos
2. Refinar (texturização com PBR) — 10 créditos
3. Download como .glb
Custo total: 30 créditos
Saldo atual: <N> créditos
Devo prosseguir?
Para pipelines de várias etapas (texto-para-3d → rig → animar), mostre o custo TOTAL do pipeline antecipadamente.
Nota: A rigging inclui automaticamente animações de caminhada e corrida sem custo extra. Adicione
Animate(3 créditos) apenas para animações personalizadas além dessas.
Mapeamento Intenção → API
| O usuário deseja... | API | Endpoint | Créditos |
|---|---|---|---|
| Modelo 3D a partir de texto | Texto para 3D | POST /openapi/v2/text-to-3d | 5–20 (preview) + 10 (refine) |
| Modelo 3D a partir de uma imagem | Imagem para 3D | POST /openapi/v1/image-to-3d | 5–30 |
| Modelo 3D a partir de múltiplas imagens | Multi-Imagem para 3D | POST /openapi/v1/multi-image-to-3d | 5–30 |
| Novas texturas em modelo existente | Retexturizar | POST /openapi/v1/retexture | 10 |
| Alterar formato/topologia da malha | Remalhar | POST /openapi/v1/remesh | 5 |
| Converter um modelo para outros formatos (sem remalhagem) | Converter | POST /openapi/v1/convert | 1 |
| Redimensionar um modelo para tamanho real | Redimensionar | POST /openapi/v1/resize | 1 |
| Gerar UVs novas (GLB, ≤40k faces) antes de texturização externa | UV Unwrap | POST /openapi/v1/uv-unwrap | 5 |
| Adicionar esqueleto a personagem | Auto-Rigging | POST /openapi/v1/rigging | 5 |
| Animar um personagem com rig | Animação | POST /openapi/v1/animations | 3 |
| Imagem 2D a partir de texto (pré-etapa recomendada antes de imagem-para-3d) | Texto para Imagem | POST /openapi/v1/text-to-image | 3 / 6 / 9 / 9 |
| Otimizar/editar uma imagem 2D (pré-etapa recomendada antes de imagem-para-3d) | Imagem para Imagem | POST /openapi/v1/image-to-image | 3 / 6 / 9 / 12 |
| Foto → produto físico estilizado (figura/luminária/chaveiro/imã de geladeira) | Creative Lab | POST /openapi/creative-lab/{product}/v1/prototype depois .../build | 6 + 30 |
| Verificar imprimibilidade FDM | Analisar Imprimibilidade | POST /openapi/v1/print/analyze | 0 (grátis) |
| Reparar topologia não-manifold/face degenerada/buraco | Reparar Imprimibilidade | POST /openapi/v1/print/repair | 10 |
| Impressão 3D multicolor | Impressão Multi-Color | POST /openapi/v1/print/multi-color | 10 (+ geração) |
| Imprimir em 3D um modelo (branco) | → Veja a seção Pipeline de Impressão | — | 20 |
| Verificar saldo de créditos | Saldo | GET /openapi/v1/balance | 0 |
Passo 2: Executar o Fluxo de Trabalho
Template de Script Reutilizável
Use este modelo como base para TODOS os fluxos de trabalho. Ele carrega a chave API com segurança do ambiente ou do .env apenas no diretório atual:
#!/usr/bin/env python3
"""Executor de tarefas da API Meshy. Lida com create → poll → download."""
import requests, time, os, sys, re, json
from datetime import datetime
# --- Carregamento seguro da chave API ---
def load_api_key():
"""Carrega MESHY_API_KEY do ambiente e depois do .env no cwd."""
key = os.environ.get("MESHY_API_KEY", "").strip()
if key:
return key
env_path = os.path.join(os.getcwd(), ".env")
if os.path.exists(env_path):
with open(env_path) as f:
for line in f:
line = line.strip()
if line.startswith("MESHY_API_KEY=") and not line.startswith("#"):
val = line.split("=", 1)[1].strip().strip('"').strip("'")
if val:
return val
return ""
API_KEY = load_api_key()
if not API_KEY:
sys.exit("ERROR: MESHY_API_KEY não definida. Execute o Passo 0a para configurá-la.")
# Nunca registre a chave completa — apenas os primeiros 8 caracteres para rastreabilidade
print(f"Chave API carregada: {API_KEY[:8]}...")
BASE = "https://api.meshy.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
SESSION = requests.Session()
SESSION.trust_env = False # ignorar configurações de proxy do sistema
def create_task(endpoint, payload):
resp = SESSION.post(f"{BASE}{endpoint}", headers=HEADERS, json=payload, timeout=30)
if resp.status_code == 401:
sys.exit("ERROR: Chave API inválida (401). Re-execute o Passo 0a.")
if resp.status_code == 402:
try:
bal = SESSION.get(f"{BASE}/openapi/v1/balance", headers=HEADERS, timeout=10)
balance = bal.json().get("balance", "desconhecido")
sys.exit(f"ERROR: Créditos insuficientes (402). Saldo: {balance}. Recarregue em https://www.meshy.ai/pricing")
except Exception:
sys.exit("ERROR: Créditos insuficientes (402). Verifique o saldo em https://www.meshy.ai/pricing")
if resp.status_code == 429:
sys.exit("ERROR: Limite de taxa excedido (429). Aguarde e tente novamente.")
resp.raise_for_status()
task_id = resp.json()["result"]
print(f"TAREFA_CRIADA: {task_id}")
return task_id
def poll_task(endpoint, task_id, timeout=300):
"""Poll com backoff exponencial (5s→30s, fixo 15s em 95%+)."""
elapsed, delay, max_delay, backoff, finalize_delay, poll_count = 0, 5, 30, 1.5, 15, 0
while elapsed < timeout:
poll_count += 1
resp = SESSION.get(f"{BASE}{endpoint}/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
task = resp.json()
status = task["status"]
progress = task.get("progress", 0)
bar = f"[{'█' * int(progress/5)}{'░' * (20 - int(progress/5))}] {progress}%"
print(f" {bar} — {status} ({elapsed}s, poll #{poll_count})", flush=True)
if status == "SUCCEEDED":
return task
if status in ("FAILED", "CANCELED"):
msg = task.get("task_error", {}).get("message", "Desconhecido")
sys.exit(f"TAREFA_{status}: {msg}")
current_delay = finalize_delay if progress >= 95 else delay
time.sleep(current_delay)
elapsed += current_delay
if progress < 95:
delay = min(delay * backoff, max_delay)
sys.exit(f"TIMEOUT após {timeout}s ({poll_count} polls)")
def download(url, filepath):
"""Baixa um arquivo para um diretório de projeto (dentro de cwd/meshy_output/)."""
os.makedirs(os.path.dirname(filepath), exist_ok=True)
print(f"Baixando {filepath}...", flush=True)
resp = SESSION.get(url, timeout=300, stream=True)
resp.raise_for_status()
with open(filepath, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
print(f"BAIXADO: {filepath} ({os.path.getsize(filepath)/1024/1024:.1f} MB)")
# --- Auxiliares de organização de arquivos ---
OUTPUT_ROOT = os.path.join(os.getcwd(), "meshy_output")
os.makedirs(OUTPUT_ROOT, exist_ok=True)
HISTORY_FILE = os.path.join(OUTPUT_ROOT, "history.json")
def get_project_dir(task_id, prompt="", task_type="model"):
slug = re.sub(r'[^a-z0-9]+', '-', (prompt or task_type).lower())[:30].strip('-')
folder = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{slug}_{task_id[:8]}"
project_dir = os.path.join(OUTPUT_ROOT, folder)
os.makedirs(project_dir, exist_ok=True)
return project_dir
def record_task(project_dir, task_id, task_type, stage, prompt="", files=None):
meta_path = os.path.join(project_dir, "metadata.json")
meta = json.load(open(meta_path)) if os.path.exists(meta_path) else {
"project_name": prompt or task_type, "folder": os.path.basename(project_dir),
"root_task_id": task_id, "created_at": datetime.now().isoformat(), "tasks": []
}
meta["tasks"].append({"task_id": task_id, "task_type": task_type, "stage": stage,
"files": files or [], "created_at": datetime.now().isoformat()})
meta["updated_at"] = datetime.now().isoformat()
json.dump(meta, open(meta_path, "w"), indent=2)
history = json.load(open(HISTORY_FILE)) if os.path.exists(HISTORY_FILE) else {"version": 1, "projects": []}
folder = os.path.basename(project_dir)
entry = next((p for p in history["projects"] if p["folder"] == folder), None)
if entry:
entry.update({"task_count": len(meta["tasks"]), "updated_at": meta["updated_at"]})
else:
history["projects"].append({"folder": folder, "prompt": prompt, "task_type": task_type,
"root_task_id": task_id, "created_at": meta["created_at"],
"updated_at": meta["updated_at"], "task_count": len(meta["tasks"])})
json.dump(history, open(HISTORY_FILE, "w"), indent=2)
def save_thumbnail(project_dir, url):
path = os.path.join(project_dir, "thumbnail.png")
if os.path.exists(path): return
try:
r = SESSION.get(url, timeout=15); r
…
Pipeline Completo de Geração
M.1: Texto para 3D com Refinamento
- Crie um preview de texto para 3D (
POST /openapi/v2/text-to-3dcommode=preview). - Faça polling até
SUCCEEDED, capturemodel_urls(glb,obj,usdz,stl,fbx). - Baixe para
project_dir/model.glb, etc. Salve a miniatura. - Crie uma tarefa de refinamento (
POST /openapi/v2/text-to-3dcommode=refine).- Defina
preview_task_idpara o ID do preview. - Defina
texture_qualitycomoultra(padrão a menos que o usuário peça menor). - Defina
pbrcomotruepara iluminação realista (padrão).
- Defina
- Faça polling até
SUCCEEDEDe baixe o.glbPBR refinado. - Atualize
metadata.json; registre ambos os IDs de tarefa.
M.2: Imagem para 3D
- Determine se o usuário forneceu uma imagem local ou URL.
- Se o arquivo de imagem for local, leia-o, codifique em base64 e defina na solicitação.
- Se o arquivo de imagem for uma URL, use a URL como
image_url. - Para multi-imagem, forneça
image_urls.
- Crie a tarefa de imagem para 3D (
POST /openapi/v1/image-to-3d).- Defina
enable_pbrcomotrue(padrão para texturas PBR).
- Defina
- Faça polling até
SUCCEEDEDe baixe os modelos. - Para refinamento, re-texturize com
POST /openapi/v1/retexture.
M.3: Retexturização
- Crie uma tarefa de retexturização (
POST /openapi/v1/retexture) commodel_urle um novo prompt de textura. - Faça polling até
SUCCEEDEDe baixe o modelo retexturizado.
M.4: Remalhagem
- Crie uma tarefa de remalhagem (
POST /openapi/v1/remesh) commodel_urle configuração de destino (ex.:target_count=20000). - Faça polling até
SUCCEEDEDe baixe o modelo remalhado.
M.5: Rigging de Personagem
- Crie uma tarefa de rigging (
POST /openapi/v1/rigging) commodel_url. - Faça polling até
SUCCEEDEDe baixe o.glbcom rig.
M.6: Animação
- Crie uma tarefa de animação (
POST /openapi/v1/animations) commodel_url. - Defina animações como uma lista (ex.:
["walk", "run"]). - Faça polling até
SUCCEEDEDe baixe o.glbanimado.
M.7: UV Unwrap
- Crie uma tarefa de UV Unwrap (
POST /openapi/v1/uv-unwrap) commodel_url. - Faça polling até
SUCCEEDEDe baixe o.glbcom UVs frescas.
M.8: Conversão de Formato
- Crie uma tarefa de conversão (
POST /openapi/v1/convert) commodel_urleformatalvo (ex.:"obj","stl","glb"). - Faça polling até
SUCCEEDEDe baixe o modelo convertido.
M.9: Redimensionamento para Tamanho Real
- Crie uma tarefa de redimensionamento (
POST /openapi/v1/resize) commodel_urlescale_factorou dimensão alvo. - Faça polling até
SUCCEEDEDe baixe o modelo redimensionado.
Pipeline de Impressão 3D
P.1: Pipeline de Impressão 3D Completo (20 créditos)
Este skill suporta o pipeline completo de impressão:
- Solicite o prompt do usuário para o que eles querem imprimir.
- Gere um preview 3D (Modo de Malha) — 20 créditos.
- Baixe o modelo e salve na pasta do projeto.
- Ofereça ao usuário três opções de download:
- Opção A: Baixar modelo 3D para slicer externo (Cura, PrusaSlicer, Bambu Studio, etc.)
- Opção B: Usar o serviço de impressão do Meshy (modelo branco, 20 créditos) — construído, impresso e enviado para você.
- Opção C: Impressão multicolor do Meshy (gera um modelo 3D colorido, 10 créditos + custos de geração).
Nota: Se o usuário escolher
modelo para download(Opção A), baixe como.stlpara impressão FDM padrão.
P.2: Análise de Imprimibilidade (grátis)
- Crie uma tarefa de análise (
POST /openapi/v1/print/analyze) commodel_url. - Faça polling até
SUCCEEDEDe exiba:- Status de análise (imprimível/não imprimível)
- Erros de topologia
- Avisos
P.3: Reparo de Imprimibilidade (10 créditos)
- Crie uma tarefa de reparo (
POST /openapi/v1/print/repair) commodel_url. - Faça polling até
SUCCEEDEDe baixe o modelo reparado.
P.4: Impressão Multicolor (10 créditos + geração)
- Crie uma tarefa de impressão multicolor (
POST /openapi/v1/print/multi-color) commodel_url. - Faça polling até
SUCCEEDEDe mostre ao usuário o resultado da pré-visualização. - Se o usuário aprovar, prossiga com a impressão.
Tratamento de Erros
Erros Comuns de API
| Código | Significado | Ação do Agente |
|---|---|---|
401 | Chave API inválida | Informe o usuário para verificar a chave e executar o Passo 0a |
402 | Créditos insuficientes | Informe o saldo e o link para recarga; pare |
429 | Limite de taxa excedido | Aguarde 60s e tente novamente (até 3 tentativas) |
5xx | Erro do servidor Meshy | Aguarde 30s e tente novamente (até 3 tentativas) |
| Falha de rede | Conectividade de rede | Verifique a conexão de internet do usuário e o acesso ao api.meshy.ai |
Erros de Tarefa
Quando status == "FAILED", o campo task_error.message normalmente contém detalhes. Causas comuns:
- Seu prompt não gerou um resultado utilizável (tente com um prompt mais descritivo)
- A imagem de entrada não se parece com um objeto 3D (use imagens com fundo limpo e assunto claro)
- O modelo de entrada para pós-processamento está corrompido ou em formato não suportado
Timeout
Se uma tarefa exceder 300s, o script irá parar. O polling será retomado se você verificar a tarefa diretamente via API. Mantenha o task_id e o project_dir nos metadados para referência posterior.
Informações de Preços e Planos
- API Keys: Apenas planos Pro ($24/mês) ou superiores podem criar chaves de API.
- Créditos: 1 crédito ≈ $0,01 (os preços podem variar). O saldo atual pode ser verificado via
GET /openapi/v1/balance. - Recarga: Adicione créditos em https://www.meshy.ai/pricing
- Limites de taxa: Dependem do plano. A maioria dos endpoints aceita ~10 solicitações concorrentes.
Exemplos
Exemplo 1: Gema de Dragão
Usuário: "Gere e faça o download de uma gema de dragão"
- Detectar chave API
- Confirmar: "Preview de texto-para-3D (20 créditos) + Refinamento PBR (10 créditos) = 30 créditos. Prosseguir?"
- Criar preview de texto-para-3D com prompt="gema de dragão"
- Polling até SUCCEEDED (45s), baixar glb, obj, stl, fbx
- Criar refinamento com o preview_task_id
- Polling até SUCCEEDED (60s), baixar modelo PBR
- Estrutura de diretório:
meshy_output/ └─ 20250315_120500_gema-de-dragao_a1b2c3d4/ ├─ thumbnail.png ├─ model.glb ├─ model_pbr.glb ├─ model.obj ├─ model.stl └─ metadata.json