---
name: comfyui_score_aesthetic
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_score_aesthetic(image_path: str, *, model_path: str = '/mnt/2tb/comfyui_models/aesthetic/sac+logos+ava1-l14-linearMSE.pth', venv_python: str = '~/ComfyUI/.venv/bin/python3', device: str = 'auto', timeout: float = 180.0) -> dict"
description: "Puntuacion estetica LAION-V2 (0-10) de una imagen. Juez objetivo del panel comfyui-judge: head MLP lineal sobre embeddings CLIP ViT-L/14 normalizados (modelo sac+logos+ava1-l14-linearMSE). Impura: delega la inferencia a un subproceso contra el python del venv de ComfyUI (torch + open_clip) porque el venv del registry no tiene torch."
tags: [comfyui-judge, ml, aesthetic, clip, quality, scoring]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
params:
  - name: image_path
    desc: "Ruta a la imagen (PNG/JPG/WebP) en disco local."
  - name: model_path
    desc: "Ruta al .pth del head estetico LAION (sac+logos+ava1-l14-linearMSE). keyword-only."
  - name: venv_python
    desc: "Python del venv de ComfyUI con torch + open_clip; se expande '~'. La inferencia corre ahi por subproceso porque el venv del registry no tiene torch. keyword-only."
  - name: device
    desc: "'auto' (cuda si hay, si no cpu), 'cuda' o 'cpu'. keyword-only."
  - name: timeout
    desc: "Timeout del subproceso en segundos (la primera vez puede descargar CLIP). keyword-only."
output: "dict {ok, score_0_10, error}. En exito ok=True y score_0_10 es el score continuo (~1-10, mayor = mejor). En error ok=False, score_0_10=0.0 y error describe la causa. Nunca lanza excepcion."
tested: true
tests: ["error: imagen inexistente (guard previo al subproceso)", "error: python del venv ComfyUI ausente", "error: .pth del modelo ausente", "nunca lanza excepcion + determinismo del error"]
test_file_path: "python/functions/ml/tests/test_comfyui_score_aesthetic.py"
file_path: "python/functions/ml/comfyui_score_aesthetic.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from ml.comfyui_score_aesthetic import comfyui_score_aesthetic

res = comfyui_score_aesthetic(os.path.expanduser("~/ComfyUI/output/comfy_sdxl_00001_.png"))
print(res)
# {'ok': True, 'score_0_10': 6.536..., 'error': ''}
```

CLI directa:

```bash
python/.venv/bin/python3 python/functions/ml/comfyui_score_aesthetic.py ~/ComfyUI/output/comfy_sdxl_00001_.png
```

## Cuando usarla

- Cuando necesites una nota objetiva de calidad visual de una imagen generada, sin pasar
  por un LLM (barato, determinista, sin coste de API).
- Como uno de los tres jueces de `comfyui_judge_image`, o suelta para comparar dos salidas
  de un skill ComfyUI y quedarte con la mejor.
- Antes de promocionar una imagen a "producto": un score bajo (~<5) es señal de descarte.

## Gotchas

- **No corre en el venv del registry.** `python/.venv` no tiene torch; la inferencia se
  ejecuta por subproceso contra `~/ComfyUI/.venv/bin/python3`. Si ese python no existe o no
  tiene `open_clip`/`torch`, devuelve `ok=False`.
- **QuickGELU obligatorio.** El modelo es `ViT-L-14-quickgelu` pretrained `openai`. Crear
  CLIP sin quick_gelu degrada los embeddings y desvirtua el score (mismatch silencioso).
- **Primera llamada lenta.** Si CLIP ViT-L/14 no esta cacheado, la primera ejecucion lo
  descarga (~900 MB) y puede acercarse al `timeout`. Cacheado, ~3-6 s en GPU.
- **Score absoluto poco interpretable.** Util sobre todo como medida RELATIVA (A vs B) o con
  umbral calibrado (~6.0 separa decente de mediocre en este modelo). Imagenes de ruido caen
  a ~3-4; fotos buenas ~6-7.
- **Necesita el .pth** en `/mnt/2tb/comfyui_models/aesthetic/`; si falta, `ok=False`.
