---
name: comfyui_image_to_3d_oneshot
kind: pipeline
lang: py
domain: pipelines
purity: impure
version: "1.0.0"
signature: "def comfyui_image_to_3d_oneshot(image_path: str, *, server: str = \"127.0.0.1:8188\", variant: str = \"mini\", dest: str | None = None, wait_timeout: float = 600.0, **gen) -> dict"
description: "Pipeline imagen en disco -> malla 3D GLB en una sola llamada. Sube la imagen al input/ de ComfyUI (POST /upload/image), construye el workflow Hunyuan3D-2 nativo de 9 nodos, lo encola, espera y descarga la malla. Compone comfyui_build_image_to_3d_workflow + comfyui_submit_workflow + comfyui_wait_result + comfyui_fetch_output_mesh. Promocion de secuencia (issue 0087). Impuro: HTTP + disco."
tags: [comfyui, ml, img-to-3d, hunyuan3d, mesh, pipeline]
uses_functions:
  - comfyui_build_image_to_3d_workflow_py_ml
  - comfyui_submit_workflow_py_ml
  - comfyui_wait_result_py_ml
  - comfyui_fetch_output_mesh_py_ml
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "python/functions/pipelines/comfyui_image_to_3d_oneshot.py"
params:
  - name: image_path
    desc: "Ruta local de la imagen de entrada (PNG/JPG). Se sube al input/ del servidor."
  - name: server
    desc: "host:port del servidor ComfyUI sin esquema. keyword-only."
  - name: variant
    desc: "'mini' (default), 'standard' o 'mv'; elige el checkpoint Hunyuan3D-2. El modelo debe estar ya instalado (comfyui_install_3d_model). keyword-only."
  - name: dest
    desc: "Ruta destino de la malla (None = cwd; dir = dentro; archivo = ahi). keyword-only."
  - name: wait_timeout
    desc: "Segundos maximos esperando a que el server termine la reconstruccion 3D (carga del modelo + difusion + decode). keyword-only."
  - name: gen
    desc: "Parametros de generacion pasados a comfyui_build_image_to_3d_workflow (resolution, steps, cfg, seed, octree_resolution, num_chunks, threshold, sampler_name, scheduler, filename_prefix). **kwargs."
output: "dict {ok, mesh_path, faces, prompt_id, error}. mesh_path = ruta local de la malla descargada; faces = numero de caras si trimesh esta disponible (si no, None); prompt_id = id del trabajo en ComfyUI. Si falla, ok=False y error explica en que paso."
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from pipelines.comfyui_image_to_3d_oneshot import comfyui_image_to_3d_oneshot

# Una imagen en disco -> un .glb en /tmp/meshes, en una sola llamada.
res = comfyui_image_to_3d_oneshot(
    os.path.expanduser("~/ComfyUI/input/3d_src_robot_00001_.png"),
    dest="/tmp/meshes",
    variant="mini",
    seed=42,
)
# res == {"ok": True, "mesh_path": "/tmp/meshes/3d_mesh_00001_.glb",
#         "faces": 1668040, "prompt_id": "....", "error": ""}
```

CLI directo (el modelo mini debe estar instalado):

```bash
$HOME/fn_registry/python/.venv/bin/python3 \
  python/functions/pipelines/comfyui_image_to_3d_oneshot.py \
  ~/ComfyUI/input/3d_src_robot_00001_.png
```

## Cuando usarla

Cuando tengas una imagen de un objeto (idealmente aislado sobre fondo plano) y
quieras su malla 3D GLB sin montar el grafo de nodos ni encadenar submit/wait/fetch
a mano. Es la operacion de un solo paso del flujo imagen->3D nativo de ComfyUI;
ideal para scripts y agentes. Para tunear el workflow nodo a nodo, usa las
funciones sueltas (`comfyui_build_image_to_3d_workflow` + submit/wait/fetch).

## Gotchas

- Impuro: sube la imagen (HTTP), dispara la GPU del servidor y escribe la malla en
  disco. Requiere el server ComfyUI vivo en `server` y el checkpoint de la variante
  ya instalado (`comfyui_install_3d_model` antes; este pipeline NO lo instala).
- La reconstruccion 3D tarda ~60 s en una RTX 3070 (carga del modelo entero a GPU +
  difusion + decode de voxel). Sube `wait_timeout` si el server arranca en frio o si
  usas `resolution`/`octree_resolution` altos.
- Si el server esta ocupado con otro trabajo, el wait puede agotar el timeout:
  reintenta o sube `wait_timeout`. No reinicia ni desencola nada.
- `faces` es best-effort: solo se calcula si `trimesh` esta en el venv. Si no, sale
  `None` (la malla igual se descarga bien; comprueba `mesh_path`/`bytes`).
- Salida **shape-only** (sin color/textura): es el camino nativo de Hunyuan3D-2.
- El upload usa POST /upload/image con `overwrite=true`: si subes dos imagenes con
  el mismo basename, la segunda pisa a la primera en el input/ del servidor.
