---
name: comfyui_inject_ipadapter
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_inject_ipadapter(workflow: dict, ref_image: str, *, mode: str = \"style\", weight: float = 0.8, preset: str | None = None, weight_type: str | None = None, start_at: float = 0.0, end_at: float = 1.0, weight_faceidv2: float = 1.0, lora_strength: float = 0.6, combine_embeds: str = \"concat\", embeds_scaling: str = \"V only\", provider: str = \"CPU\", model_node: str | None = None) -> dict"
description: "Inyecta una rama IPAdapter (LoadImage + UnifiedLoader + IPAdapter, modo style o faceid) en un workflow ComfyUI ya construido (API format), repuntando el KSampler.model al MODEL condicionado por una imagen de referencia. La fuente del MODEL es la que hoy alimenta el KSampler (tras las LoRAs, no el checkpoint crudo). Version ENCADENABLE-sobre-dict del builder comfyui_build_ipadapter_workflow; reutiliza sus defaults de preset/weight_type. Pensada para componerse con inject_lora/inject_controlnet/inject_hires_fix. Pura: no muta el dict de entrada."
tags: [comfyui, comfyui-skill, ml, ipadapter, faceid, stable-diffusion, workflow]
uses_functions: [comfyui_build_ipadapter_workflow_py_ml]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: workflow
    desc: "dict en API format (ej. salida de comfyui_build_txt2img_workflow, posiblemente con LoRAs). No se muta; se devuelve una copia."
  - name: ref_image
    desc: "Nombre del archivo de imagen de referencia en input/ del servidor. En faceid debe contener una cara nitida; en style es la imagen de estilo. No puede estar vacio (raise ValueError)."
  - name: mode
    desc: "'style' (transfiere estilo/composicion) o 'faceid' (rostro consistente via insightface + FaceID). keyword-only."
  - name: weight
    desc: "Peso de la influencia IPAdapter (0..1+). 0.8 buen punto de partida. keyword-only."
  - name: preset
    desc: "Preset del UnifiedLoader. None = default del modo ('STANDARD (medium strength)' style, 'FACEID PLUS V2' faceid). keyword-only."
  - name: weight_type
    desc: "Tipo de ponderacion del nodo IPAdapter/FaceID. None = default del modo ('standard' style, 'linear' faceid). keyword-only."
  - name: start_at
    desc: "Fraccion del sampling donde empieza a aplicar IPAdapter (0..1). keyword-only."
  - name: end_at
    desc: "Fraccion del sampling donde deja de aplicar (0..1). keyword-only."
  - name: weight_faceidv2
    desc: "Peso del embedding FaceID v2 (solo mode='faceid'). keyword-only."
  - name: lora_strength
    desc: "Fuerza de la LoRA FaceID que carga el UnifiedLoaderFaceID (solo faceid). keyword-only."
  - name: combine_embeds
    desc: "Como combinar embeddings si hay varias caras ('concat'|'add'|...). Solo faceid. keyword-only."
  - name: embeds_scaling
    desc: "Escalado de embeddings ('V only'|'K+V'|...). Solo faceid. keyword-only."
  - name: provider
    desc: "Backend de insightface ('CPU'|'CUDA'|...). CPU por defecto para no competir por VRAM. Solo faceid. keyword-only."
  - name: model_node
    desc: "node_id cuya salida MODEL (slot 0) alimentara la rama IPAdapter. None = detecta la fuente del KSampler.model (CheckpointLoader como fallback). keyword-only."
output: "copia del workflow con LoadImage + (UnifiedLoader|UnifiedLoaderFaceID) + (IPAdapter|IPAdapterFaceID) insertados y el KSampler.model repuntado a la salida MODEL de la rama IPAdapter. node_ids = max id numerico + 1/2/3."
tested: true
tests: ["mode style inyecta IPAdapterUnifiedLoader + IPAdapter y repunta KSampler.model", "mode faceid inyecta IPAdapterUnifiedLoaderFaceID + IPAdapterFaceID", "la rama toma el MODEL actual del KSampler (tras loras, no el checkpoint)", "respeta weight/preset/weight_type", "no muta el dict de entrada (pureza)", "mode invalido lanza ValueError", "ref_image vacio lanza ValueError", "api format valido"]
test_file_path: "python/functions/ml/tests/test_comfyui_inject_ipadapter.py"
file_path: "python/functions/ml/comfyui_inject_ipadapter.py"
---

## Ejemplo

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

base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "portrait of a knight")
wf = comfyui_inject_multi_lora(base, [{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5}])
wf = comfyui_inject_ipadapter(wf, "hero_face.png", mode="faceid", weight=0.9)
# KSampler.model viene de IPAdapterFaceID(model=ultimo LoraLoader, image=hero_face)
```

## Cuando usarla

Cuando quieras condicionar un workflow txt2img ya construido con una **imagen de
referencia** (estilo en `style`, rostro consistente en `faceid`) encadenando
sobre el mismo dict que las LoRAs, sin reconstruir el grafo. Es la pieza
IPAdapter del mixer `comfyui_compose_capabilities`. Para un workflow IPAdapter
aislado desde cero usa `comfyui_build_ipadapter_workflow`.

## Gotchas

- Pura: no muta el `workflow` de entrada y NO valida que los modelos IPAdapter
  esten instalados. La imagen de referencia debe estar subida al `input/` del
  servidor ANTES de submit.
- **ref_image obligatorio** y **mode in {style, faceid}**: ambos validados con
  `ValueError`. Es el error path tipico al activar la capacidad sin referencia.
- **Compatibilidad de checkpoint**: usa modelos IPAdapter SD1.5 con checkpoints
  SD1.5 (dreamshaper_8) y SDXL con SDXL. Mezclar familias da un error de shape en
  ejecucion.
- `faceid` carga insightface (provider CPU por defecto) + un FaceID .bin + su
  LoRA: es la rama mas pesada. En 8GB lowvram funciona pero apilarla con
  ControlNet + hires + facedetailer a la vez puede dar OOM — baja resolucion o
  desactiva capacidades.
- Se aplica DESPUES de las LoRAs (toma el MODEL actual del KSampler), que es el
  orden correcto del mixer.
