Files
fn_registry/python/functions/ml/sdcpp_python_generate.py
egutierrez aec5d82011 feat(ml): auto-commit con 14 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 01:22:02 +02:00

104 lines
3.3 KiB
Python

"""sdcpp_python_generate — genera una imagen con stable-diffusion-cpp-python a partir de GenerationConfig."""
from __future__ import annotations
import sys
import os
import time
from typing import Any
sys.path.insert(0, os.path.dirname(__file__))
from generation_config import GenerationConfig
from image_gen_result import ImageGenResult
# Mapa de sampler del registry al nombre que espera stable-diffusion-cpp-python
_SAMPLER_MAP: dict[str, str] = {
"euler": "euler",
"euler_a": "euler_a",
"dpm++2m": "dpmpp2m",
"dpm++2m_v2": "dpmpp2mv2",
"heun": "heun",
"dpm2": "dpm2",
"lcm": "lcm",
}
def sdcpp_python_generate(sd: Any, cfg: GenerationConfig) -> ImageGenResult:
"""Genera una imagen con un objeto StableDiffusion usando GenerationConfig como contrato.
Mapea los campos del GenerationConfig canonico a los parametros de
StableDiffusion.generate_image(). Mide la duracion total de la llamada.
Retorna un ImageGenResult con la primera imagen del batch, metadata del backend
y duracion en milisegundos. VRAM no se mide (None).
Args:
sd: Instancia StableDiffusion cargada via sdcpp_python_load.
cfg: Contrato de parametros de generacion. Todos los campos son leidos.
cfg.sampler debe ser uno de los valores del SamplerName del registry.
Returns:
ImageGenResult con image=PIL.Image, meta con backend/modelo/sampler/seed/wtype,
duration_ms medido via time.perf_counter(), vram_peak_mb=None.
Raises:
KeyError: Si cfg.sampler no tiene correspondencia en _SAMPLER_MAP.
ImportError: Si stable_diffusion_cpp no esta instalado.
RuntimeError: Si generate_image retorna lista vacia o None.
"""
try:
from stable_diffusion_cpp import StableDiffusion # noqa: F401 — verifica disponibilidad
except ImportError as exc:
raise ImportError(
"sdcpp_python_generate requiere stable-diffusion-cpp-python. "
"Instalar con: pip install stable-diffusion-cpp-python"
) from exc
sample_method = _SAMPLER_MAP.get(cfg.sampler)
if sample_method is None:
raise KeyError(
f"Sampler '{cfg.sampler}' no tiene correspondencia en sdcpp_python_generate. "
f"Valores soportados: {list(_SAMPLER_MAP.keys())}"
)
# wtype del objeto sd (para metadata)
wtype = getattr(sd, "wtype", "unknown")
t0 = time.perf_counter()
images = sd.generate_image(
prompt=cfg.prompt,
negative_prompt=cfg.negative_prompt or "",
cfg_scale=cfg.cfg_scale,
sample_method=sample_method,
sample_steps=cfg.steps,
seed=cfg.seed,
width=cfg.width,
height=cfg.height,
clip_skip=cfg.clip_skip if cfg.clip_skip is not None else -1,
batch_count=1,
)
duration_ms = int((time.perf_counter() - t0) * 1000)
if not images:
raise RuntimeError(
"sdcpp_python_generate: generate_image retorno lista vacia o None."
)
meta: dict[str, Any] = {
"backend": "sdcpp_python",
"model": cfg.model.name,
"sampler": cfg.sampler,
"actual_steps": cfg.steps,
"seed": cfg.seed,
"wtype": wtype,
}
return ImageGenResult(
image=images[0],
meta=meta,
duration_ms=duration_ms,
vram_peak_mb=None,
)