---
name: comfyui_generate_styles_llm
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_generate_styles_llm(category: str, n: int = 8, prefix: str = '', avoid: list[str] | None = None, model: str = 'claude-haiku-4-5-20251001') -> dict"
description: "Genera N estilos para el selector WAS de ComfyUI de una CATEGORIA tematica usando el LLM via ask_llm (grupo claude-direct, API directa de Anthropic, arranque 0). Devuelve el dict en el formato exacto {nombre: {prompt, negative_prompt}}, con prompts que son MODIFICADORES de estilo (camara, lente, iluminacion, render, medio, paleta, mood), sin descripcion de sujeto y sin el placeholder {prompt}. Robusta por diseno: extrae el primer bloque JSON de la respuesta (tolera fences markdown y prosa), valida entrada por entrada (descarta sin prompt, dedup contra avoid, rellena negative por defecto, limpia {prompt} si aparece) y ante CUALQUIER fallo (429 rate-limit, JSON corrupto, respuesta vacia, ask_llm ausente) devuelve {} en vez de lanzar — asi el caller itera categorias y sigue aunque una falle. Impura: llama a la API del LLM (red); no escribe disco."
tags: [comfyui, ml, comfyui-styles, styles, was, llm, claude-direct]
uses_functions: [ask_llm_py_core]
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
params:
  - name: category
    desc: "Tema de los estilos (texto libre que dirige el contenido), ej. 'vaporwave aesthetics', 'baroque painting', 'macro insect photography'."
  - name: n
    desc: "Numero de estilos a pedir. El modelo puede devolver menos; se validan todos. Default 8."
  - name: prefix
    desc: "Prefijo para los nombres generados (ej. 'vapor-') para agrupar y reducir colisiones con estilos existentes. Vacio = sin prefijo."
  - name: avoid
    desc: "Lista de nombres ya existentes que el modelo NO debe repetir (dedup previo). Tambien se filtran a posteriori en la validacion."
  - name: model
    desc: "Id del modelo Anthropic. Default claude-haiku-4-5-20251001 (mas cuota, rapido). Otros: claude-opus-4-8, claude-sonnet-4-6."
output: "dict {nombre: {prompt, negative_prompt}} ya validado (prompt no vacio, sin {prompt}, negative rellenado). Vacio {} si el LLM falla, no hay JSON valido o no quedan entradas utilizables. NUNCA lanza: el error-path es devolver {}."
tested: true
tests: ["edge extract json plano", "edge extract json con fence markdown y prosa alrededor", "edge extract json corrupto/vacio -> None", "edge validate descarta no-dict, prompt vacio, duplicado en avoid; rellena negative por defecto", "edge validate limpia el placeholder {prompt}", "error ask_llm lanza (429) -> devuelve {} sin propagar", "error ask_llm ausente (None) -> {}", "golden respuesta JSON valida se parsea a dict de estilos"]
test_file_path: "python/functions/ml/comfyui_generate_styles_llm_test.py"
file_path: "python/functions/ml/comfyui_generate_styles_llm.py"
---

## Ejemplo

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

# Generar 8 estilos de una categoria y fusionarlos (best-effort: si el LLM falla, devuelve {})
nuevos = comfyui_generate_styles_llm("vaporwave and synthwave aesthetics", n=8, prefix="vapor-")
if nuevos:
    comfyui_append_styles(nuevos)   # merge+dedup+backup sobre el styles.json real
print("generados:", len(nuevos))
```

O por CLI: `python/.venv/bin/python3 python/functions/ml/comfyui_generate_styles_llm.py "art deco poster" 6 deco-`

## Cuando usarla

Cuando quieras AMPLIAR el repositorio de estilos WAS con estilos NUEVOS de una categoria concreta
que no estan en `comfyui_curated_styles_catalog`, generandolos con el LLM en el formato correcto.
Encadena con `comfyui_append_styles` para escribirlos (merge+dedup). Por ser best-effort (devuelve
{} ante fallo), puedes llamarla en bucle sobre varias categorias y seguir aunque alguna falle por
rate-limit. Para un set grande y fiable sin depender de la red, prefiere el catalogo curado.

## Gotchas

- **Rate limits**: ask_llm puede dar `HTTP 429` en rafagas. Esta funcion lo absorbe devolviendo {};
  espacia las llamadas o usa el modelo haiku (default, mas cuota). No reintenta sola.
- **No determinista**: el LLM puede devolver menos de `n`, nombres distintos cada vez o repetir
  modificadores. Pasa `avoid` con los nombres existentes para reducir colisiones; el dedup final
  por nombre lo cierra `comfyui_append_styles`.
- **No escribe disco**: solo genera y valida. La escritura (con backup) es de `comfyui_append_styles`.
- **Calidad variable**: revisa una muestra de lo generado antes de fusionar en lote grande; el
  catalogo curado es la fuente fiable, esto es el complemento.

## Capability growth log

(v1.0.0 — sin cambios todavia.)
