---
name: comfyui_extract_recipe_from_png
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_extract_recipe_from_png(png_path: str, *, slug: str | None = None, civitai_meta: dict | None = None, image_url: str = \"\", nsfw: bool = False) -> dict"
description: "Destila un PNG cosechado de Civitai en una receta de skill CANDIDATA (schema comfyui-skill, score_n=0, provenance.source='civitai'). Compone comfyui_import_workflow_png (workflow API format embebido) + comfyui_read_png_metadata (params del KSampler) y, como fallback para samplers no-KSampler (flux/SamplerCustomAdvanced), extrae checkpoint del UNETLoader y prompts de los nodos CLIPTextEncode. Degradacion honesta: si el PNG no trae workflow embebido, usa la meta de Civitai (civitai_meta); si tampoco hay nada utilizable, ok=False sin inventar. Impura: lectura de disco."
tags: [comfyui, civitai, ml, recipe, png, metadata, comfyui-skill]
uses_functions: ["comfyui_import_workflow_png_py_ml", "comfyui_read_png_metadata_py_ml"]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["os", "re", "sys"]
params:
  - name: png_path
    desc: "Ruta del PNG descargado de Civitai."
  - name: slug
    desc: "Slug de la skill candidata. Si None se deriva del prompt positivo (fallback 'civitai_import'). keyword-only."
  - name: civitai_meta
    desc: "dict meta del item de comfyui_search_civitai_images. Fallback si el PNG no trae workflow embebido, y para rellenar campos ausentes. keyword-only."
  - name: image_url
    desc: "URL de origen (se guarda en provenance). keyword-only."
  - name: nsfw
    desc: "Marca provenance.nsfw. keyword-only."
output: "dict {ok, recipe, slug, has_workflow, error}. recipe sigue el schema minimo de comfyui_save_skill con provenance.source='civitai' y score_n=0. ok=False solo si no hay ni workflow embebido ni civitai_meta utilizable."
tested: false
tests: []
test_file_path: ""
file_path: "python/functions/ml/comfyui_extract_recipe_from_png.py"
---

## Ejemplo

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

# PNG cosechado de Civitai (con comfyui_fetch_civitai_image).
res = comfyui_extract_recipe_from_png("/home/me/ComfyUI/civitai_harvest/abc.png",
                                      image_url="https://civitai.com/...", nsfw=False)
print(res["ok"], res["has_workflow"], res["recipe"]["provenance"]["source"])  # True True civitai

# Round-trip: la receta candidata la acepta save_skill tal cual.
if res["ok"]:
    comfyui_save_skill(res["recipe"], library_dir="/tmp/skills_test")

# Sin workflow embebido pero con meta de Civitai (degradacion honesta):
# comfyui_extract_recipe_from_png(png, civitai_meta={"prompt": "...", "Model": "x.safetensors", "steps": 25})
```

## Cuando usarla

Tras descargar un PNG de Civitai, para convertirlo en una receta de skill
candidata lista para `comfyui_save_skill` (score_n=0) sin reconstruirla a mano. El
pipeline `comfyui_harvest_civitai_skill_oneshot` la encadena con el search y el
fetch.

## Gotchas

- **El prompt cosechado es CONCRETO, no un scaffold con `{subject}`**: se guarda
  verbatim en `prompt_scaffold.positive` como punto de partida. Sustituye partes
  por `{subject}` a mano si quieres reutilizar la skill para otros sujetos.
- **Degradacion honesta**: si el PNG no trae workflow ComfyUI (chunks tEXt) y no
  pasas `civitai_meta` con al menos prompt o modelo, devuelve `ok=False`. NO
  inventa una receta.
- **Civitai casi siempre da `meta` null hoy**: el camino principal es el workflow
  embebido en el PNG. La `meta` es fallback que en la practica rara vez ayuda.
- **Heuristica de prompt en samplers no-KSampler** (flux/SamplerCustomAdvanced):
  el positivo se asume el CLIPTextEncode mas largo y el negativo el que contenga
  terminos tipicos (blurry, bad anatomy, ...). Puede no acertar en workflows con
  muchos encoders — es best-effort, por eso la skill nace como CANDIDATA a juzgar.
- **El checkpoint puede salir vacio** si el workflow usa un loader exotico; la
  receta se guarda igual (slug/base_workflow/version bastan para save_skill) pero
  conviene completarla antes de generar.
- **base_workflow se detecta** (txt2img/flux) por los class_type; revisalo si vas a
  compilar con `comfyui_build_skill_workflow`.
- El PNG puede traer prompts NSFW: marca `nsfw=True` para que quede en
  `provenance.nsfw`.
- Impura: lee disco (via las dos funciones que compone).
