CoolFace
Apppublic

drizzymedia/SynapseCore-12B

sourceHugging Faceupdated 2mo agoView on Hugging Face
1likes
params.py134 linesDownload Raw Back to root
1"""Tunable generation parameters shared by the chat API and the UI.2 3This module is the single source of truth for the generation parameters that4the frontend exposes as sliders/selects. It deliberately avoids heavy imports5(torch, transformers, gradio) so it stays cheap to import from tests and, later,6can be used to drive the frontend controls without pulling in the model.7 8The chat endpoint is a public API: clients can call it directly, bypassing the9UI controls, so the ranges here are enforced server-side rather than trusted10from the request.11"""12 13import json14from dataclasses import dataclass15 16 17@dataclass(frozen=True)18class ParamSpec:19    """Allowed range, default, and UI presentation for one generation parameter.20 21    The numeric range is what the chat API enforces; ``step`` and ``choices``22    describe how the frontend renders the control. ``validate_params`` only uses23    ``minimum``/``maximum``/``is_int``; the rest is consumed by ``ui_config``.24 25    Args:26        minimum: Smallest accepted value (inclusive).27        maximum: Largest accepted value (inclusive).28        default: Value used when the client omits the parameter.29        is_int: Whether the value is coerced to ``int`` (otherwise ``float``).30        step: Slider step for the UI control, or ``None`` for a select.31        choices: Discrete options shown in the UI as a select. The API still32            accepts any value within ``[minimum, maximum]``; these are a UI33            convenience, not an extra constraint.34    """35 36    minimum: float37    maximum: float38    default: float39    is_int: bool = False40    step: float | None = None41    choices: tuple[int, ...] | None = None42 43 44# Single source of truth for the tunable parameters. Both the chat API45# (validate_params) and the UI controls (ui_config, injected into the page)46# derive from this, so the ranges/defaults are defined in exactly one place.47PARAM_SPECS: dict[str, ParamSpec] = {48    "max_new_tokens": ParamSpec(minimum=100, maximum=4000, default=2000, is_int=True, step=10),49    "image_token_budget": ParamSpec(50        minimum=70, maximum=1120, default=280, is_int=True, choices=(70, 140, 280, 560, 1120)51    ),52    "temperature": ParamSpec(minimum=0.0, maximum=2.0, default=1.0, step=0.1),53    "top_p": ParamSpec(minimum=0.0, maximum=1.0, default=0.95, step=0.05),54    "top_k": ParamSpec(minimum=0, maximum=100, default=64, is_int=True, step=1),55    "repetition_penalty": ParamSpec(minimum=1.0, maximum=2.0, default=1.0, step=0.05),56}57 58 59def ui_config() -> dict[str, dict]:60    """Serialize the param specs for the frontend controls.61 62    Returns:63        A JSON-serializable dict, keyed by parameter name, describing each64        control's range, step, default, and discrete choices. The page injects65        this as ``window.PARAM_CONFIG`` so the UI and the API share one66        definition of the parameters.67    """68    return {69        name: {70            "min": spec.minimum,71            "max": spec.maximum,72            "step": spec.step,73            "default": spec.default,74            "choices": list(spec.choices) if spec.choices is not None else None,75        }76        for name, spec in PARAM_SPECS.items()77    }78 79 80# The page applies window.PARAM_CONFIG to its controls; this tag marks where the81# config script is inserted (just before the frontend module loads).82_APP_SCRIPT_TAG = '<script type="module" src="./app.js"></script>'83 84 85def inject_param_config(html: str) -> str:86    """Insert ``window.PARAM_CONFIG`` into the page before the app script.87 88    Lets the served page and the UI-preview stub share one definition of the89    parameters with the chat API. The injected content is fully controlled90    (numbers and parameter names), so no extra escaping is needed.91 92    Args:93        html: The page source containing the app script tag.94 95    Returns:96        The page with a ``<script>`` defining ``window.PARAM_CONFIG`` inserted97        just before the app script.98    """99    blob = f"<script>window.PARAM_CONFIG = {json.dumps(ui_config())};</script>\n    "100    return html.replace(_APP_SCRIPT_TAG, blob + _APP_SCRIPT_TAG)101 102 103def validate_params(values: dict[str, float]) -> dict[str, float]:104    """Coerce and range-check generation parameters against ``PARAM_SPECS``.105 106    Args:107        values: Raw parameter values keyed by name (one per entry in108            ``PARAM_SPECS``).109 110    Returns:111        A new dict with each value coerced to its declared numeric type.112 113    Raises:114        ValueError: If a value is non-numeric or outside its allowed range. The115            message names the parameter and its range so the API is116            self-documenting.117    """118    validated: dict[str, float] = {}119    for name, spec in PARAM_SPECS.items():120        raw = values[name]121        try:122            coerced = int(raw) if spec.is_int else float(raw)123        except (TypeError, ValueError):124            expected = "an integer" if spec.is_int else "a number"125            msg = f"{name} must be {expected}, got {raw!r}"126            raise ValueError(msg) from None127        if not spec.minimum <= coerced <= spec.maximum:128            lo = int(spec.minimum) if spec.is_int else spec.minimum129            hi = int(spec.maximum) if spec.is_int else spec.maximum130            msg = f"{name} must be between {lo} and {hi}, got {coerced}"131            raise ValueError(msg)132        validated[name] = coerced133    return validated134