feat(ml): grupo comfyui-styles — catálogo curado + merge/dedup + generador LLM de estilos WAS

Tres funciones para gestionar y ampliar el repositorio de estilos del selector
WAS de ComfyUI (Prompt Styles Selector / Prompt Multiple Styles Selector):

- comfyui_curated_styles_catalog (pure): catálogo curado de 190 estilos en 13
  categorías (photography, render3d, painting, anime, pixel, illustration,
  comic, lighting, camera, material, scifi, fantasy, mood), formato WAS exacto.
- comfyui_append_styles (impure): merge+dedup no destructivo sobre el styles.json
  real, con backup atómico, validación de entradas y preservación de existentes.
- comfyui_generate_styles_llm (impure): genera estilos de una categoría vía
  ask_llm (grupo claude-direct); robusta (devuelve {} ante 429/JSON corrupto).

Aplicado en vivo: styles.json 269 -> 503 estilos (+190 curados +44 LLM),
backup hecho, selector verifica 503 en /object_info. Tests offline verdes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
agent
2026-06-27 13:50:25 +02:00
parent a5748cb147
commit d3d846f748
9 changed files with 1197 additions and 0 deletions
@@ -0,0 +1,73 @@
---
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.)