"""genconfig_load_json — carga un GenerationConfig desde un archivo JSON.""" from __future__ import annotations import json import os import sys sys.path.insert(0, os.path.dirname(__file__)) from generation_config import GenerationConfig def genconfig_load_json(path: str) -> GenerationConfig: """Carga y valida un GenerationConfig desde un archivo JSON en disco. Usa GenerationConfig.model_validate(data) si pydantic esta disponible (version con validacion completa de tipos y literales). En caso de fallback a dataclass, construye la instancia manualmente mapeando los campos conocidos. Args: path: Ruta al archivo JSON. Puede ser relativa o absoluta. Returns: Instancia de GenerationConfig cargada y validada. Raises: FileNotFoundError: Si el archivo no existe. json.JSONDecodeError: Si el contenido no es JSON valido. pydantic.ValidationError: Si los datos no cumplen el schema (version pydantic). KeyError / TypeError: Si faltan campos obligatorios (version dataclass). """ abs_path = os.path.abspath(path) with open(abs_path, "r", encoding="utf-8") as f: data = json.load(f) # Intentar deserializacion pydantic (version canonica con validacion) try: return GenerationConfig.model_validate(data) except AttributeError: pass # Fallback: dataclass — construir manualmente desde el dict from lora_ref import LoraRef from model_ref import ModelRef model_data = data["model"] model = ModelRef( name=model_data["name"], model_type=model_data["model_type"], quantization=model_data.get("quantization", "fp16"), path=model_data.get("path"), ) loras = [ LoraRef( path=lr["path"], weight=lr.get("weight", 1.0), scale=lr.get("scale"), ) for lr in data.get("loras", []) ] return GenerationConfig( prompt=data["prompt"], negative_prompt=data.get("negative_prompt"), seed=data["seed"], steps=data["steps"], cfg_scale=data["cfg_scale"], sampler=data["sampler"], width=data["width"], height=data["height"], model=model, loras=tuple(loras), clip_skip=data.get("clip_skip"), )