---
name: comfyui_build_portrait_avatar_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_portrait_avatar_workflow(character: str, *, style: str = \"character portrait\", ref_face: str | None = None, checkpoint: str = \"IMG_dreamshaper_8.safetensors\", size: int = 512, facedetailer: bool = True, seed: int = 0, lora: str | None = None, lora_strength: float = 1.0, weight: float = 0.85, negative: str | None = None, steps: int = 28, cfg: float = 7.0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", fd_denoise: float = 0.45, bbox_model: str = \"face_yolov8m.pt\", filename_prefix: str = \"portrait\") -> dict"
description: "Construye el dict (API format) del workflow de UN retrato/avatar de personaje 2D (busto centrado, cara al espectador, fondo simple con vinheta) para dialogo, perfil o seleccion de personaje. Con ref_face encadena IPAdapter-FaceID para rostro consistente entre retratos; con facedetailer regenera la cara con detalle (Impact-Pack). Compone comfyui_build_ipadapter_workflow / comfyui_build_txt2img_workflow + comfyui_inject_lora + comfyui_build_facedetailer_workflow. Hermano de comfyui_build_sprite_sheet/item_icon_workflow. Pura, sin red ni I/O. class_types verificados contra /object_info (8GB lowvram)."
tags: [comfyui, ml, gamedev-2d, portrait, avatar, character, faceid, ipadapter, facedetailer, workflow]
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_build_ipadapter_workflow_py_ml, comfyui_inject_lora_py_ml, comfyui_build_facedetailer_workflow_py_ml]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: character
    desc: "Descripcion del personaje (ej. 'a young knight woman with red hair', 'an old wizard with a long white beard'). Se inserta en un prompt scaffold de retrato. No puede estar vacio."
  - name: style
    desc: "Descriptor de estilo que mantiene consistentes los retratos de un set (ej. 'character portrait', 'anime portrait', 'realistic RPG portrait', 'oil painting portrait'). Pasa el MISMO style + checkpoint + lora a todos los retratos para coherencia visual. keyword-only."
  - name: ref_face
    desc: "Nombre de una imagen de rostro de referencia en input/ del servidor. Si se pasa, encadena IPAdapter-FaceID para que el retrato tenga el MISMO rostro (identidad consistente entre retratos). None = identidad solo por prompt + seed. keyword-only."
  - name: checkpoint
    desc: "Checkpoint del servidor. 'IMG_dreamshaper_8.safetensors' (SD1.5, holgado en 8GB lowvram) por defecto. FaceID solo instalado para SD1.5: con checkpoint SDXL deja ref_face=None. keyword-only."
  - name: size
    desc: "Lado del cuadrado en px (width = height = size). 512 SD1.5 por defecto, encuadre tipico de avatar. keyword-only."
  - name: facedetailer
    desc: "Si True encadena FaceDetailer (Impact-Pack) para regenerar la cara con detalle y descarta el SaveImage base (el unico PNG guardado es el refinado). False deja la imagen tal cual sale del VAEDecode. keyword-only."
  - name: seed
    desc: "Semilla del KSampler (y del sampler del FaceDetailer). Misma seed + mismo character/ref_face -> mismo retrato. keyword-only."
  - name: lora
    desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_anime_lineart.safetensors'). None = sin LoRA. keyword-only."
  - name: lora_strength
    desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
  - name: weight
    desc: "Peso del IPAdapter-FaceID (solo si ref_face). 0.85 = parecido alto; baja para mas libertad del prompt, sube para mas parecido. keyword-only."
  - name: negative
    desc: "Prompt negativo. None usa el negativo por defecto pensado para retratos (una cara bien formada, sin texto/recorte). keyword-only."
  - name: steps
    desc: "Pasos del KSampler. keyword-only."
  - name: cfg
    desc: "CFG del KSampler (y del sampler del FaceDetailer). keyword-only."
  - name: sampler_name
    desc: "Sampler del KSampler. keyword-only."
  - name: scheduler
    desc: "Scheduler del KSampler. keyword-only."
  - name: fd_denoise
    desc: "Fuerza de re-difusion de la cara en el FaceDetailer (0.45: refina sin perder la identidad que aporta FaceID). Solo si facedetailer=True. keyword-only."
  - name: bbox_model
    desc: "Modelo de deteccion de caras de Ultralytics para el FaceDetailer ('face_yolov8m.pt'). Solo si facedetailer=True. keyword-only."
  - name: filename_prefix
    desc: "Prefijo del PNG en output/. keyword-only."
output: "dict en API format listo para comfyui_submit_workflow: base txt2img (o IPAdapter-FaceID si ref_face) con prompt scaffold de retrato ('portrait of {character}, {style}, bust shot, head and shoulders, looking at viewer, ...') + LoRA de estilo opcional + FaceDetailer (si facedetailer, con SaveImage base descartado). UN retrato; set coherente -> llamar por character con mismo style/checkpoint/(lora) y, para el mismo personaje, el mismo ref_face/seed."
tested: true
tests: ["golden facedetailer: clases CheckpointLoaderSimple/KSampler/VAEDecode/FaceDetailer/UltralyticsDetectorProvider; 'portrait of'+'bust shot'+'looking at viewer' en prompt; un solo SaveImage = fd_save <- FaceDetailer; FaceDetailer.image <- VAEDecode; sin IPAdapterFaceID si no ref_face", "edge facedetailer=False: sin FaceDetailer, SaveImage base <- VAEDecode", "edge ref_face: IPAdapterUnifiedLoaderFaceID/IPAdapterFaceID presentes, LoadImage con ref_face, weight reflejado, KSampler.model <- rama FaceID", "edge style en prompt", "edge size: width==height==768 (cuadrado)", "edge lora: LoraLoader con strength", "edge seed reflejado en KSampler", "error character vacio -> ValueError", "determinismo"]
test_file_path: "python/functions/ml/comfyui_build_portrait_avatar_workflow_test.py"
file_path: "python/functions/ml/comfyui_build_portrait_avatar_workflow.py"
---

## Ejemplo

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

# Retrato con cara nitida (FaceDetailer), identidad por prompt + seed.
wf = comfyui_build_portrait_avatar_workflow(
    "a young knight woman with red hair",
    style="realistic RPG portrait",
    facedetailer=True,
    seed=7,
)
# -> comfyui_submit_workflow(wf) -> comfyui_wait_result -> comfyui_fetch_output_image

# Rostro CONSISTENTE entre retratos: sube una cara de referencia a input/ del
# servidor y pasala como ref_face (IPAdapter-FaceID). Mismo ref_face -> misma cara.
#   wf = comfyui_build_portrait_avatar_workflow(
#       "a young knight woman with red hair, smiling",
#       ref_face="hero_face.png", style="realistic RPG portrait", seed=7)
#   wf = comfyui_build_portrait_avatar_workflow(
#       "a young knight woman with red hair, angry",
#       ref_face="hero_face.png", style="realistic RPG portrait", seed=8)
# Set coherente de varios personajes: mismo style/checkpoint, varia character.
```

O lanzable directo con: `./fn run comfyui_build_portrait_avatar_workflow` (imprime nodos + class_types del ejemplo).

## Cuando usarla

Cuando necesites retratos/avatares de personaje para un juego: cuadros de dialogo,
pantalla de perfil, selector de personaje, fichas de NPC. Busto centrado, cara al
espectador, fondo simple. Para que el MISMO personaje aparezca en varios retratos
(distintas expresiones/poses) sube una foto de su cara a `input/` y pasala como
`ref_face` -> IPAdapter-FaceID fija el rostro. Para un set de personajes distintos
con look uniforme, fija `style` + `checkpoint` + (`lora`) y varia solo `character`.
`facedetailer=True` (default) recupera el detalle de la cara que el render a 512px
pierde. Es UN retrato; genera cada uno y, si quieres un mosaico, monta los PNG con
`comfyui_build_grid`.

## Gotchas

- **FaceID solo SD1.5**: `ref_face` requiere los modelos IPAdapter-FaceID, que en
  este servidor solo estan para SD1.5 (IMG_dreamshaper_8). Con un checkpoint SDXL deja
  `ref_face=None` (identidad por prompt + seed) o usa un checkpoint SD1.5.
- **El detailer regenera la cara con el modelo base, no con FaceID**: FaceDetailer
  reutiliza el `CheckpointLoaderSimple` crudo (no la rama IPAdapter). Por eso
  `fd_denoise` es bajo (0.45): refina ojos/piel preservando la identidad que ya
  trae la imagen base generada con FaceID. Si notas que la cara refinada se aleja
  del parecido, baja `fd_denoise` (0.3-0.4) o sube `weight`.
- **SaveImage unico con facedetailer**: cuando `facedetailer=True` se descarta el
  SaveImage base y solo se guarda el PNG del detailer (`fd_save`) — no hay doble
  guardado. Con `facedetailer=False` el SaveImage base toma del VAEDecode.
- **Requiere custom nodes instalados**: IPAdapter_plus (cubiq) para FaceID e
  Impact-Pack para FaceDetailer/UltralyticsDetectorProvider. Si un nodo falta, el
  submit fallara; consulta `/object_info` del servidor para confirmar.
- **Coherencia del set = mismos parametros**: cambiar `style`/`checkpoint`/`lora`
  entre retratos rompe el look uniforme. Para el mismo personaje, fija ademas
  `ref_face` + `seed`.
- **8GB lowvram**: `size=512` con IMG_dreamshaper_8 va holgado; SDXL pide mas VRAM y
  resolucion mayor. Si hay OOM, baja `size` o desactiva `facedetailer`.
- Es una funcion **pura**: solo arma el dict. La generacion real (GPU) la hacen
  `comfyui_submit_workflow` + `comfyui_wait_result` + `comfyui_fetch_output_image`.
