Nueva capacidad del grupo comfyui: dado el id/URL de una imagen de Civitai, extrae cómo se generó (prompt, modelo, sampler, LoRAs) vía los endpoints tRPC image.getGenerationData + image.get (la API v1 da meta=null), reconstruye el workflow y lo replica en nuestro ComfyUI, sustituyendo el checkpoint ausente por el más parecido instalado y reportando lo que falta en missing_models sin bajar nada a ciegas. Respeta SFW. Funciones nuevas (registry-first, componen 8 funciones existentes): - comfyui_fetch_civitai_image_meta_py_ml (impura): observa la receta por id/URL. - comfyui_map_a1111_params_py_ml (pura): traduce meta A1111 -> params ComfyUI, familia del modelo y LoRAs. - comfyui_replicate_civitai_oneshot_py_pipelines: orquesta fetch_meta -> map_a1111_params -> build/embebido -> run_foreign_workflow_oneshot -> judge. Probado en vivo (imagen SFW 23526611): receta extraída + réplica 1024x1024 generada + panel de jueces. 12 tests unitarios verdes. Capability page comfyui.md actualizada. Report 0127. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
37 KiB
ComfyUI — Generación de imágenes por API HTTP y por la UI (CDP)
Tag: comfyui. Grupo de funciones para controlar ComfyUI
(motor de Stable Diffusion basado en grafos de nodos) de dos formas complementarias:
- Por su API HTTP (
/prompt,/history,/object_info): construir un workflow en "API format", encolarlo, esperar el resultado. Headless, scriptable, sin navegador. - Por su UI web vía CDP: operar la pestaña de ComfyUI ya abierta en el navegador diario
(cargar un workflow en el grafo visual, editar widgets en vivo, encolar como si pulsaras
"Queue Prompt", exportar el grafo, refrescar combos). Lo que el usuario ve, el agente lo
toca. Todas las funciones de UI componen la primitiva de transport
cdp_eval_py_browser— no reinventan CDP.
Filtro MCP: mcp__registry__fn_search query="" tag="comfyui".
Dos caminos, mismo motor
API HTTP (dominio ml) UI web vía CDP (dominio browser)
────────────────────── ───────────────────────────────
build_txt2img_workflow (dict API format) load_workflow_ui (dict -> grafo visual)
│ set_node_widget_ui (tuning en vivo)
▼ queue_prompt_ui (= botón Queue Prompt)
submit_workflow (POST /prompt -> id) export_workflow_ui (grafo -> dict API format)
▼ refresh_nodes_ui (recarga combos)
wait_result (poll /history -> PNG)
object_info (catálogo de nodos) download_model (dominio ml) -> baja checkpoints
El API format (dict de nodos numerados que produce build_txt2img_workflow y consume
submit_workflow) es el puente entre ambos mundos: load_workflow_ui lo carga en la UI y
export_workflow_ui lo recupera de la UI, así que puedes mezclar libremente API y navegador.
Funciones del grupo
Lifecycle del server — dominio infra
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_ensure_server_py_infra | ensure_server(*, port=8188, lowvram=None, health_timeout=60, comfyui_dir='~/ComfyUI', unit_name='comfyui', runner=None) -> dict |
Garantiza que ComfyUI corre como servicio systemd-user resiliente y sano: genera/instala el unit (Restart=always, --lowvram autodetectado en GPUs ≤ 8 GB), daemon-reload + enable + start, y verifica salud por GET /system_stats. Idempotente; migra limpio un ComfyUI lanzado a mano (SIGTERM, nunca SIGKILL). Solo stdlib, no lanza excepciones → dict de estado. Prerequisito de todas las funciones HTTP. Impura. |
Por API HTTP — dominio ml
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_txt2img_workflow_py_ml | build_txt2img_workflow(ckpt_name, positive, negative='', *, steps, cfg, width, height, seed, ...) -> dict |
Construye el dict del workflow txt2img básico (Checkpoint → CLIPTextEncode×2 + EmptyLatent → KSampler → VAEDecode → SaveImage) en API format. Pura. |
| comfyui_build_flux_workflow_py_ml | build_flux_workflow(prompt, *, unet='flux1-schnell-fp8-e4m3fn.safetensors', clip_l, t5xxl, vae='ae.safetensors', width=1024, height=1024, steps=4, guidance=3.5, seed, weight_dtype='fp8_e4m3fn', ...) -> dict |
Builder txt2img para Flux (schnell/dev): UNETLoader + DualCLIPLoader (clip_l + t5xxl, type flux) + VAELoader → CLIPTextEncode → FluxGuidance + EmptySD3LatentImage → KSampler (cfg fijo 1.0) → VAEDecode → SaveImage. La guía va por FluxGuidance, no por el cfg. fp8 + ~4 pasos para 8 GB. Pura. |
| comfyui_object_info_py_ml | object_info(server='127.0.0.1:8188', node_class=None, timeout) -> dict |
Catálogo de nodos del server: inputs, tipos y enums (lista de checkpoints/samplers visibles). Para validar antes de enviar. Impura. |
| comfyui_submit_workflow_py_ml | submit_workflow(workflow, server, client_id, timeout) -> dict |
Encola un workflow API format vía POST /prompt; devuelve prompt_id + posición en cola. HTTP 400 propaga la validación por nodo. Impura. |
| comfyui_wait_result_py_ml | wait_result(prompt_id, server, timeout, poll_interval) -> dict |
Sondea GET /history/{prompt_id} hasta que termina; devuelve los outputs (PNGs con filename/subfolder/type). Impura. |
| comfyui_download_model_py_ml | download_model(url, dest_subdir='checkpoints', *, comfyui_dir, filename, token, overwrite, timeout_s) -> dict |
Descarga un checkpoint/LoRA/VAE a models/<dest_subdir>/. Soporta Civitai (token) y HuggingFace. Valida que no sea HTML de error ni .safetensors corrupto. Impura. |
| comfyui_interrupt_queue_py_ml | interrupt_queue(server='127.0.0.1:8188') -> dict |
Corta la generación en curso (POST /interrupt) y lee la cola (GET /queue) → {ok, interrupted, queue_running, queue_pending, error}. Freno de mano; degrada limpio en fallo de red. Impura. |
| comfyui_batch_generate_py_ml | batch_generate(workflow, *, seeds=None, server='127.0.0.1:8188') -> dict |
Encola N variantes (una por seed), parcheando el campo de semilla de los nodos sampler sin mutar el original → {ok, prompt_ids, count, error}. Re-roll en una llamada. Compone submit_workflow. Impura. |
| comfyui_queue_manage_py_ml | queue_manage(action, *, server='127.0.0.1:8188', prompt_id=None) -> dict |
API de cola completa que complementa a interrupt_queue: action='status' (GET /queue), 'clear' (vacía pendientes), 'delete' (borra un prompt, requiere prompt_id), 'history' (cuenta /history) → {ok, action, queue_running, queue_pending, history_count, error}. Degrada limpio en fallo de red. Impura. |
| comfyui_stream_progress_py_ml | stream_progress(prompt_id, *, server='127.0.0.1:8188', client_id=None, timeout=300) -> dict |
Progreso en vivo por WebSocket /ws (alternativa a wait_result): cuenta pasos del sampler (steps_seen), último nodo, y detecta el fin → {ok, completed, steps_seen, last_node, method, error}. Para ver progreso comparte el client_id con el submit. Cae a polling si falta websocket-client. Impura. |
Builders, validación e import — dominio ml (P0, issue 0064)
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_img2img_workflow_py_ml | build_img2img_workflow(ckpt_name, init_image, positive, negative='', *, denoise=0.6, steps, cfg, seed, ...) -> dict |
Builder img2img (Checkpoint + LoadImage → VAEEncode → KSampler con denoise → VAEDecode → SaveImage). Pura. |
| comfyui_build_upscale_workflow_py_ml | build_upscale_workflow(image, *, model_name='4x-UltraSharp.pth', method='model') -> dict |
Builder upscale: method='model' (ESRGAN: UpscaleModelLoader + ImageUpscaleWithModel) o method='latent' (ImageScaleBy x2 sin modelo). Pura. |
| comfyui_inject_lora_py_ml | inject_lora(workflow, lora_name, *, strength_model=1.0, strength_clip=1.0, model_node=None, clip_node=None) -> dict |
Inserta un LoraLoader en un workflow ya construido, reconectando model/clip de la fuente a sus consumidores. Encadenable. Pura (no muta la entrada). |
| comfyui_validate_workflow_py_ml | validate_workflow(workflow, server='127.0.0.1:8188', timeout) -> dict |
Cruza class_type y nombres de modelo contra /object_info; devuelve {valid, missing_nodes, missing_models} ANTES de encolar. Compone object_info. Impura. |
| comfyui_import_workflow_json_py_ml | import_workflow_json(source, *, server, timeout) -> dict |
Lee un workflow JSON de URL o path local; normaliza UI graph → API format (widgets vía object_info); passthrough si ya es API. Impura. |
| comfyui_import_workflow_png_py_ml | import_workflow_png(png_path_or_url, *, timeout) -> dict |
Extrae el workflow embebido en los chunks prompt (API) / workflow (UI) de un PNG de ComfyUI (tEXt/zTXt/iTXt, stdlib). Path o URL. Impura. |
| comfyui_download_workflow_py_ml | download_workflow(source, dest=None, *, server, civitai_token, hf_token, timeout) -> dict |
Dispatcher: descarga un workflow de CUALQUIER fuente (Google Drive, GitHub, Civitai, HuggingFace, URL directa o path local) y lo normaliza a API format. Detecta el tipo por la URL y delega; tras bajar compone import_workflow_json/import_workflow_png. Catálogo de fuentes: reports/0080. Impura. |
| comfyui_read_png_metadata_py_ml | read_png_metadata(png_path) -> dict |
Lee los parámetros de generación (modelo, seed, steps, cfg, sampler, prompts) de un PNG generado por ComfyUI. Impura (I/O disco). |
| comfyui_fetch_output_image_py_ml | fetch_output_image(filename, *, subfolder='', type_='output', server, dest_dir='.', timeout) -> dict |
Descarga el PNG generado vía GET /view a disco local (wait_result solo da metadata). Impura. |
| comfyui_fetch_output_video_py_ml | fetch_output_video(prompt_id, *, server, dest=None, outputs=None, timeout) -> dict |
Localiza y descarga el output de vídeo/animación (.mp4/.webp/.webm/.gif) de /history vía GET /view. Cubre SaveAnimatedWEBP/SaveVideo (bajo "images") y VHS_VideoCombine (bajo "gifs"). Hermana de fetch_output_image/fetch_output_mesh. Acepta outputs= de wait_result para evitar re-consultar /history. Impura. |
Potencia y assets de internet — dominio ml (P1, issue 0064)
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_inpaint_workflow_py_ml | build_inpaint_workflow(ckpt_name, image, mask, positive, negative='', *, denoise=1.0, steps, cfg, seed, ...) -> dict |
Builder inpaint: CheckpointLoaderSimple + LoadImage + LoadImageMask → VAEEncodeForInpaint → KSampler → VAEDecode → SaveImage. Regenera solo la zona enmascarada. Pura. |
| comfyui_build_controlnet_workflow_py_ml | build_controlnet_workflow(ckpt_name, control_image, cn_name, positive, negative='', *, strength=1.0, steps, cfg, seed, width, height) -> dict |
Builder ControlNet: ControlNetLoader + ControlNetApply inyectan el mapa de control sobre el condicionamiento positivo. Pura. |
| comfyui_build_sdxl_refiner_workflow_py_ml | build_sdxl_refiner_workflow(base_ckpt, refiner_ckpt, positive, negative='', *, base_steps=20, refiner_steps=5, cfg, seed, width=1024, height=1024) -> dict |
SDXL base+refiner: dos KSamplerAdvanced encadenados (base con return_with_leftover_noise, refiner termina). Pura. |
| comfyui_search_civitai_models_py_ml | search_civitai_models(query, *, types='Checkpoint', base_model=None, sort, limit=20, token=None) -> dict |
Busca modelos/LoRAs en la API pública de Civitai → {ok, items:[{name, type, base_model, version_id, download_url, nsfw}], count, error}. Sin token funciona. Impura. |
| comfyui_install_custom_node_py_ml | install_custom_node(repo_url, *, comfyui_dir, pip_install=True, restart=False) -> dict |
git clone en custom_nodes/ + pip/uv install de requirements en el venv de ComfyUI. NO reinicia el server (restart=False). Impura. |
| comfyui_resolve_workflow_deps_py_ml | resolve_workflow_deps(workflow, server='127.0.0.1:8188') -> dict |
Para un workflow ajeno: valida y traduce lo que falta en acciones ({missing_nodes, missing_models, suggestions}). Compone validate_workflow. Impura. |
| comfyui_run_foreign_workflow_oneshot_py_pipelines | run_foreign_workflow_oneshot(source, *, server, dest=None, output_kind='auto', install_nodes=False, node_repos=None, wait_timeout, civitai_token, hf_token) -> dict |
Pipeline para ejecutar un workflow ComfyUI ajeno end-to-end en una llamada: import (cualquier fuente) → resolve deps → (instala solo nodos confiables opt-in) → validate → submit → wait → fetch (imagen/vídeo/malla). Gate de seguridad: si faltan deps NO encola y las reporta en missing; nunca descarga modelos a ciegas. Compone download_workflow + resolve_workflow_deps + install_custom_node + submit/wait + fetch_output_image/video/mesh. Promoción del roadmap 0064/0087. Impuro. |
| comfyui_list_installed_models_py_ml | list_installed_models(folder=None, comfyui_dir='~/ComfyUI') -> dict |
Lista modelos por carpeta resolviendo la ruta real de extra_model_paths.yaml (/mnt/2tb/comfyui_models/) + la nativa. Escaneo de FS, no depende del server. Impura. |
Cosecha de Civitai → skills candidatas — dominio ml + pipelines (issue 0087)
Cosechar de Civitai imágenes con su workflow+receta embebidos para clonar su calidad y alimentar
la librería de skills (grupo comfyui-skill). En vez de reconstruir a mano una
receta que ya existe en una imagen pública, se cosecha y se guarda como candidata (score_n=0,
provenance.source='civitai') para que el bucle de juicio/bump la valide. Política: NSFW
permitido pero SIEMPRE segregado en carpeta marcada. Gotcha clave: la API de Civitai ya no
expone meta (viene null) — la receta real sale del workflow ComfyUI embebido en el PNG, no
de la meta inline.
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_search_civitai_images_py_ml | search_civitai_images(*, query=None, model_version_id=None, nsfw='None', sort='Most Reactions', limit=20, token=None) -> dict |
Busca imágenes en Civitai (GET /api/v1/images) → items con url (PNG con workflow embebido). El endpoint no admite query textual (HTTP 500): resuelve query→versión de modelo via search_civitai_models. Token de pass civitai/api-token. Reintenta 503. Impura. |
| comfyui_fetch_civitai_image_py_ml | fetch_civitai_image(image_url, *, dest_dir, nsfw=False, nsfw_subdir='nsfw', token=None, prefer_original=True, timeout_s=120) -> dict |
Descarga el PNG original (reescribe /width=N/→/original=true/ para conservar el workflow), segregando NSFW a <dest_dir>/nsfw/. Misma validación no-HTML que download_model; nombra por UUID. Impura. |
| comfyui_extract_recipe_from_png_py_ml | extract_recipe_from_png(png_path, *, slug=None, civitai_meta=None, image_url='', nsfw=False) -> dict |
Destila un PNG cosechado en receta de skill candidata (schema comfyui-skill, source='civitai', score_n=0). Compone import_workflow_png + read_png_metadata + fallback de prompts/ckpt para flux. Sin workflow → usa civitai_meta (degradación honesta). Impura. |
| comfyui_harvest_civitai_skill_oneshot_py_pipelines | harvest_civitai_skill_oneshot(*, query=None, model_version_id=None, nsfw='None', dest_dir, library_dir='~/ComfyUI/skills_library', comfyui_dir='~/ComfyUI', token=None, ...) -> dict |
Pipeline Civitai→skill candidata: search → fetch (segrega NSFW) → extract → save_skill. Itera items hasta uno con receta destilable (2º pase al feed global si filtró por modelo). NO baja modelos a ciegas: checkpoint/LoRA ausente → missing_models. Impuro. |
Replicación desde un link de Civitai — dominio ml + pipelines (issue C5, report 0127)
"Te paso un link de Civitai: entra, observa cómo lo hicieron, y construye un workflow que lo
replique." Dado el id/URL de una imagen de Civitai → extrae la receta (prompt, modelo, sampler,
LoRAs) → reconstruye el workflow → lo genera y lo juzga. Gotcha clave: la API v1 /images
devuelve meta=null; la receta por id sale de los endpoints tRPC image.getGenerationData +
image.get (los que usa la web). Como casi nunca tendrás el checkpoint/LoRA exacto, se sustituye
por el más parecido instalado (misma familia) y lo ausente se reporta en missing_models (NUNCA
se descarga a ciegas). El parecido es aproximado cuando falta el modelo exacto — esperado. SFW
estricto: una imagen NSFW devuelve ok=False sin generar.
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_fetch_civitai_image_meta_py_ml | fetch_civitai_image_meta(image_ref, *, token=None, timeout=15.0) -> dict |
"Entra al link y observa": resuelve UNA imagen Civitai por id/URL vía tRPC image.getGenerationData + image.get → {meta, resources, comfy_workflow, nsfw, ...}. Donde search_civitai_images da meta=null, esta sí trae prompt/modelo/sampler. Impura. |
| comfyui_map_a1111_params_py_ml | map_a1111_params(meta, resources=None) -> dict |
Pura: traduce meta A1111/Civitai a params ComfyUI (sampler DPM++ 2M Karras→dpmpp_2m/karras, dims, seed), infiere familia (sd15/sdxl/flux) y extrae LoRAs (de resources y tags <lora:..> del prompt). |
| comfyui_replicate_civitai_oneshot_py_pipelines | replicate_civitai_oneshot(url_or_id, *, server, dest=None, judge=True, token=None, wait_timeout=600) -> dict |
Pipeline link Civitai→réplica: fetch_meta → map_a1111_params → workflow embebido tal cual O reconstruido (build_txt2img + inject_lora, sustituye checkpoint ausente por el más parecido instalado, omite LoRAs ausentes) → run_foreign_workflow_oneshot → judge_image. Acepta también modelVersionId o un workflow ajeno (PNG/.json/dict). Impuro. |
Retoque pro y oneshot — dominio ml + pipelines (P0, lote report 0093)
Builders que envuelven custom-nodes "pro" ya instalados (Impact-Pack, UltimateSDUpscale) y la
promoción del flujo txt2img a una sola llamada. Los class_types se verificaron contra el
/object_info del server vivo (FaceDetailer, UltralyticsDetectorProvider, UltimateSDUpscale).
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_facedetailer_workflow_py_ml | build_facedetailer_workflow(base_workflow_or_image, ckpt_name, positive, negative='', *, bbox_model='face_yolov8m.pt', denoise=0.5, ...) -> dict |
Builder FaceDetailer (Impact-Pack): detecta caras con UltralyticsDetectorProvider (YOLO bbox) y las regenera para recuperar detalle (el pain #1 de retratos). Acepta el nombre de una imagen en input/ (str) o un workflow base (dict): toma la imagen del VAEDecode y reutiliza el CheckpointLoaderSimple. No usa SAM (no instalado). Pura. |
| comfyui_build_hires_fix_workflow_py_ml | build_hires_fix_workflow(ckpt_name, positive, negative='', *, first_pass=(768,768), upscale_by=1.5, denoise=0.4, steps=20, ...) -> dict |
Builder hires fix de 2 pasadas: genera base (KSampler) y la amplía re-difundiéndola por tiles con UltimateSDUpscale + Remacri (denoise<1 = añade detalle real). Distinto de build_upscale_workflow (ESRGAN puro, sin re-difusión). Pura. |
| comfyui_txt2img_oneshot_py_pipelines | txt2img_oneshot(prompt, *, ckpt='dreamshaper_8.safetensors', negative='', server, dest=None, wait_timeout, **gen) -> dict |
Pipeline texto → PNG en disco en una llamada: build_txt2img + submit + wait + fetch_output_image → {ok, image_path, prompt_id, error}. Promoción de la secuencia (issue 0087). Impuro. |
| comfyui_build_grid_py_ml | build_grid(image_paths, *, cols=None, cell=512, out_path=None, labels=None) -> dict |
Monta un grid / contact-sheet PIL de N imágenes para comparar de un vistazo (p.ej. el output de batch_generate con varios seeds). Celdas que conservan aspect ratio, rejilla casi cuadrada por defecto, rótulos opcionales → {ok, out_path, rows, cols, error}. Post-proceso local de imagen (no toca el server). Impura (I/O disco, PIL). |
Vídeo (txt2video) — dominio ml (tag video-generation)
ComfyUI ≥ 0.26.0 trae soporte nativo para vídeo por difusión. build_video_workflow cubre
los dos modelos que caben en 8 GB: LTX-Video 2B v0.9.5 (model='ltx', checkpoint todo-en-uno +
VAE temporal + scheduler propio — validado end-to-end en reports/0084, clip real de 65 frames,
pico ~7.7 GB) y Wan2.1 T2V 1.3B (model='wan', diffusion + umt5 + vae aparte — plantilla nativa
canónica). El resultado es un .mp4 vía CreateVideo → SaveVideo.
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_video_workflow_py_ml | build_video_workflow(prompt, *, model='ltx', negative='', width=512, height=320, num_frames=65, steps=20, seed=0, fps=24) -> dict |
Builder txt2video para LTX-Video 2B (model='ltx', 12 nodos LTXV*) o Wan2.1 1.3B (model='wan', UNETLoader+VAELoader+ModelSamplingSD3). Nombres de modelo reales, defaults conservadores 8 GB. Pura. |
| comfyui_build_img2vid_workflow_py_ml | build_img2vid_workflow(image, *, ckpt='svd.safetensors', width=1024, height=576, video_frames=14, motion_bucket_id=127, fps=6, augmentation_level=0.0, steps=20, cfg=2.5, min_cfg=1.0, seed=0, sampler_name='euler', scheduler='karras', filename_prefix='comfy_svd') -> dict |
Builder img2vid (Stable Video Diffusion): anima una imagen estática a clip corto. ImageOnlyCheckpointLoader(svd.safetensors, todo-en-uno) + LoadImage → SVD_img2vid_Conditioning → VideoLinearCFGGuidance → KSampler (denoise 1.0) → VAEDecode → SaveAnimatedWEBP. SVD no usa prompt de texto: condiciona por CLIP_VISION de la imagen; movimiento vía motion_bucket_id. Pura. |
Imagen → 3D (Hunyuan3D-2 nativo) — dominio ml + pipelines (tag img-to-3d)
ComfyUI ≥ 0.26.0 trae soporte nativo de Hunyuan3D-2 (sin custom node): una imagen se
reconstruye en una malla 3D GLB con un grafo de 9 nodos (LoadImage → ImageOnlyCheckpointLoader → CLIPVisionEncode → Hunyuan3Dv2Conditioning → EmptyLatentHunyuan3Dv2 → KSampler → VAEDecodeHunyuan3D → VoxelToMeshBasic → SaveGLB). El checkpoint es self-contained (DiT de forma +
VAE 3D + encoder de imagen en un .safetensors). Salida shape-only (sin color/textura). Detalle
y benchmark en reports/0069-2026-06-23-comfyui-img-to-3d.md. Para mejorar la cara trasera/laterales,
genera vistas novel-view desde 1 imagen (generate_views_from_image, reports 0073); para VER el GLB
resultante interactivo dentro de un nodo de la UI, monta el visor Load3D (build_view_3d_workflow,
report 0079).
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_build_image_to_3d_workflow_py_ml | build_image_to_3d_workflow(image_name, ckpt_name='hunyuan3d-dit-v2-mini.safetensors', *, resolution, steps, cfg, seed, octree_resolution, num_chunks, threshold, ..., watertight=False) -> dict |
Builder del workflow imagen→3D de 9 nodos (Hunyuan3D-2 nativo) en API format. El SaveGLB produce un .glb. watertight=True usa VoxelToMesh (algorithm='surface net') en vez de VoxelToMeshBasic → malla estanca de raíz (default conserva el comportamiento histórico). Pura. |
| comfyui_generate_views_from_image_py_ml | generate_views_from_image(image_name, *, method='auto', server, azimuths=(90,180,270), elevation, dest_dir, validate_only=False, ...) -> dict |
Sintetiza vistas novel-view (back/left/right) desde 1 imagen con StableZero123/SV3D nativos, para alimentar el 3D multi-vista. Honesta: si el nodo+checkpoint no están, devuelve ok=False con la acción y NO encola. validate_only=True valida sin tocar GPU. Impura. |
| comfyui_build_view_3d_workflow_py_ml | build_view_3d_workflow(model_file, *, animation=False, width, height) -> dict |
Monta el visor 3D nativo Load3D (o Load3DAdvanced con animation=True) para VER un GLB/OBJ existente, orbitando con el ratón, sin ejecutar el grafo. model_file relativo a input/3d/. Cárgalo con load_workflow_ui. Pura. |
| comfyui_fetch_output_mesh_py_ml | fetch_output_mesh(prompt_id, *, server, dest=None, timeout) -> dict |
Localiza la malla en /history/{prompt_id} (el SaveGLB la expone bajo la clave "3d", no "images") y la baja via GET /view a disco. Hermana de fetch_output_image. Impura. |
| comfyui_install_3d_model_py_ml | install_3d_model(variant='mini', *, hf_token=None, comfyui_dir) -> dict |
Instala el checkpoint Hunyuan3D-2 (mini/standard/mv) en checkpoints/. Cascada: ya-instalado → cache de HF → descarga. Resuelve la ruta real via extra_model_paths.yaml. Impura. |
| comfyui_image_to_3d_oneshot_py_pipelines | image_to_3d_oneshot(image_path, *, server, variant='mini', dest=None, wait_timeout, **gen) -> dict |
Pipeline imagen en disco → malla GLB en una llamada: upload + build + submit + wait + fetch. Promoción de la secuencia (issue 0087). Impuro. |
| comfyui_text_to_3d_oneshot_py_pipelines | text_to_3d_oneshot(prompt, *, server, ckpt_name='v1-5-pruned-emaonly.safetensors', negative='', textured=False, variant='mini', dest=None, ...) -> dict |
Pipeline prompt de texto → malla 3D GLB en una llamada: txt2img (SD) + fetch + upload + build 3D (nativo o textured=True multi-vista PBR) + submit + wait + fetch_mesh. Promoción de la secuencia texto→imagen→3D (issue 0087). Impuro. |
| comfyui_build_textured_3d_multiview_workflow_py_ml | build_textured_3d_multiview_workflow(image_name, *, ckpt='hunyuan3d-dit-v2-mv.safetensors', views=6, octree=384, max_faces=50000, upscale_model='4x_foolhardy_Remacri.pth') -> dict |
Builder imagen→malla 3D con textura PBR vía el wrapper Hunyuan3DWrapper (kijai): 4/6 vistas + delight + sample multi-vista + upscale Remacri + bake sobre UV (19 nodos). Cobertura de atlas 32.93% (report 0082). Pura. En 8 GB ejecutar en 2 fases (shape→/free→paint). |
| comfyui_simplify_mesh_py_ml | simplify_mesh(in_path, *, target_faces=80000, weld=True, out_path=None) -> dict |
Post-proceso: decima un GLB/OBJ/PLY denso (suelda cube-soup + quadric edge collapse de pymeshlab), conservando vertex colors o textura+UV. 964k→80k caras, 34.7→1.43 MB medido (report 0090). weld=True es clave: sin él la cube-soup de VoxelToMeshBasic no decima. Impura (trimesh+pymeshlab+scipy). |
| comfyui_make_watertight_py_ml | make_watertight(in_path, *, method='voxel', pitch=None, out_path=None) -> dict |
Post-proceso: hace estanca una malla. method='voxel' (voxeliza+fill+marching cubes) garantiza is_watertight=True a costa de más caras y de descartar la apariencia; method='repair' (fill_holes+fix_normals) conserva detalle pero no garantiza estanqueidad. La vía de raíz es VoxelToMesh surface net (report 0088). Impura. |
| comfyui_mesh_cleanup_oneshot_py_pipelines | mesh_cleanup_oneshot(in_path, *, target_faces=80000, watertight=True, method='repair', out_path=None) -> dict |
Pipeline de limpieza en una llamada: simplify_mesh → (si watertight) make_watertight. Capitaliza el "80k caras + estanco" del report 0088. method='voxel' garantiza estanqueidad; method='repair' conserva caras. Reporta {in_faces, simplified_faces, final_faces, is_watertight}. Impuro. |
Por la UI web (CDP) — dominio browser
| ID | Firma corta | Qué hace |
|---|---|---|
| comfyui_load_workflow_ui_py_browser | load_workflow_ui(workflow, *, port=9222, server_url_substr='8188', filename, timeout_s) -> dict |
Carga un workflow API format en el grafo visual (app.loadApiJson). Impura (CDP + muta UI). |
| comfyui_set_node_widget_ui_py_browser | set_node_widget_ui(node, widget_name, value, *, match='type', port, server_url_substr, timeout_s) -> dict |
Edita en vivo un widget de un nodo (texto del CLIPTextEncode, steps/seed/cfg del KSampler). Localiza por type/id/title. Impura. |
| comfyui_queue_prompt_ui_py_browser | queue_prompt_ui(*, port, server_url_substr, timeout_s) -> dict |
Encola el grafo actual (app.queuePrompt(0)), = botón "Queue Prompt". Impura (dispara GPU). |
| comfyui_export_workflow_ui_py_browser | export_workflow_ui(*, port, server_url_substr, api_format=True, save_path, timeout_s) -> dict |
Exporta el grafo actual: API format (graphToPrompt().output) o UI graph (graph.serialize()); opcional a disco. Impura. |
| comfyui_refresh_nodes_ui_py_browser | refresh_nodes_ui(*, port, server_url_substr, timeout_s) -> dict |
Refresca los combos (checkpoints/loras/vae) sin recargar la página (app.refreshComboInNodes). Impura. |
Ejemplo canónico end-to-end (build → load → tune → queue → resultado)
Combina API + UI: construyes el workflow por API, lo cargas en la UI del usuario, ajustas el
prompt y los pasos en vivo, encolas y esperas el PNG. Requiere el server en 127.0.0.1:8188
y la pestaña de ComfyUI abierta en un Chrome con --remote-debugging-port=9222.
import sys, os, time, glob
sys.path.insert(0, os.path.join("python", "functions"))
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow
from browser.comfyui_load_workflow_ui import comfyui_load_workflow_ui
from browser.comfyui_set_node_widget_ui import comfyui_set_node_widget_ui
from browser.comfyui_queue_prompt_ui import comfyui_queue_prompt_ui
# 1. Construir (API format, función pura) con un prefijo de salida localizable.
prefix = f"demo_{int(time.time())}"
wf = comfyui_build_txt2img_workflow(
ckpt_name="dreamshaper_8.safetensors",
positive="placeholder",
steps=8, seed=111, filename_prefix=prefix,
)
# 2. Cargar el grafo en la UI del navegador del usuario.
comfyui_load_workflow_ui(wf) # {'ok': True, 'loaded': True}
# 3. Tuning en vivo: prompt (widget de texto) + pasos (widget numérico).
comfyui_set_node_widget_ui("CLIPTextEncode", "text",
"a green glass bottle on a marble shelf", match="type")
comfyui_set_node_widget_ui("KSampler", "steps", 12, match="type")
# 4. Encolar (= pulsar "Queue Prompt") y localizar el PNG nuevo en output/.
comfyui_queue_prompt_ui() # {'ok': True, 'queued': True}
before = set(glob.glob(os.path.expanduser("~/ComfyUI/output/*.png")))
while True:
new = [p for p in set(glob.glob(os.path.expanduser("~/ComfyUI/output/*.png"))) - before
if prefix in os.path.basename(p)]
if new:
print("PNG generado:", new[0]); break
time.sleep(1.5)
Variante 100% headless (sin navegador): cambia los pasos 2-4 por
comfyui_submit_workflow(wf) → comfyui_wait_result(prompt_id). Misma capacidad, sin UI.
Ejemplo canónico imagen → 3D (Hunyuan3D-2 nativo)
Una imagen de un objeto → su malla GLB, en una sola llamada. Requiere el server en
127.0.0.1:8188 y el checkpoint mini instalado (lo hace install_3d_model la primera vez,
reutilizando la cache de HF; ~60 s de GPU por reconstrucción en una RTX 3070).
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from ml.comfyui_install_3d_model import comfyui_install_3d_model
from pipelines.comfyui_image_to_3d_oneshot import comfyui_image_to_3d_oneshot
# 1. Asegurar el checkpoint (instantáneo si ya está; reused_cache=True).
comfyui_install_3d_model("mini")
# 2. Imagen en disco -> malla GLB en /tmp/meshes.
res = comfyui_image_to_3d_oneshot(
os.path.expanduser("~/ComfyUI/input/3d_src_robot_00001_.png"),
dest="/tmp/meshes", variant="mini", seed=42,
)
print(res["mesh_path"], res["faces"]) # /tmp/meshes/3d_mesh_00001_.glb 1668040
Para tunear nodo a nodo en vez del oneshot: build_image_to_3d_workflow(image_name) →
submit_workflow → wait_result → fetch_output_mesh(prompt_id, dest=...).
Fronteras
- No es un grupo de generación genérica de imágenes: cubre ComfyUI concretamente (su API y su frontend litegraph). Para otros backends (Automatic1111, diffusers) harían falta otras funciones.
- Los builders cubren txt2img, img2img, upscale (ESRGAN y hires-fix con re-difusión), LoRA
stacks, inpaint, ControlNet, SDXL refiner, FaceDetailer, vídeo (LTX/Wan) y 3D texturizado
multi-vista (
build_txt2img_workflow,build_img2img_workflow,build_upscale_workflow,build_hires_fix_workflow,inject_lora,build_inpaint_workflow,build_controlnet_workflow,build_sdxl_refiner_workflow,build_facedetailer_workflow,build_video_workflow,build_textured_3d_multiview_workflow). Lo que aún NO tiene builder propio (IPAdapter, multi-ControlNet avanzado) se monta en la UI a mano y se captura conexport_workflow_ui, o se importa de internet conimport_workflow_json/import_workflow_png, se resuelven sus dependencias conresolve_workflow_deps(instala nodos coninstall_custom_node, descubre modelos consearch_civitai_models) y se valida convalidate_workflowantes de encolar. - Los 13 builders puros tienen tests de estructura (
python/functions/ml/tests/test_comfyui_build_*.pytest_comfyui_inject_lora.py): verifican losclass_typeesperados, que los parámetros se reflejan en los nodos, la validez de las conexiones[node_id, output_index]y la pureza deinject_lora. Son tests offline (no tocan GPU ni server); las funciones impuras del grupo (todo lo que habla con el server, el navegador o Civitai/HuggingFace) no se cubren con unit tests por diseño — se validan con el server vivo.
- Control de cola:
interrupt_queuecorta la generación en curso + lee/queue;batch_generateencola N variantes por seed (re-roll). No vacían la cola entera (eso esPOST /queue {"clear": true}). - Las funciones
*_uirequieren la pestaña abierta y el navegador con CDP (puerto 9222 por defecto). Sin target que matcheeserver_url_substr, devuelvenok=False. Para automatización desatendida sin navegador, usa el camino API (submit_workflow+wait_result). download_modelno gestiona el catálogo del server: tras bajar un modelo, llamarefresh_nodes_ui(o recarga la página) para que ComfyUI lo vea en los combos.- El camino imagen→3D nativo es shape-only: los nodos nativos de Hunyuan3D-2
(
build_image_to_3d_workflow,fetch_output_mesh,install_3d_model,image_to_3d_oneshot) reconstruyen la FORMA, sin color ni textura horneada. Para textura PBR estábuild_textured_3d_multiview_workflow, que usa el wrapper de kijai (requierecustom_rasterizerCUDA +ComfyUI_essentials+ el upscaler Remacri) y debe ejecutarse en 2 fases en 8 GB (shape→/free→paint). Detalle y cobertura medida enreports/0082; shape-only y comparación vs la app local enreports/0069-2026-06-23-comfyui-img-to-3d.md. - Estanqueidad de la malla: el default de
build_image_to_3d_workflow(VoxelToMeshBasic) da malla NO estanca; conwatertight=True(VoxelToMesh surface-net) sale estanca de raíz. Si ya tienes el GLB en disco,mesh_cleanup_oneshotdecima + cierra en una llamada (method='voxel'garantizais_watertight=True;method='repair'conserva caras sin garantía). Verreports/0088. - La primitiva de transport CDP es
cdp_eval(grupo navegador): si necesitas leer/escribir algo del grafo que estas funciones no cubren, compóncdp_evaldirectamente antes de inventar nada.