#!/usr/bin/env python3 """Render and verify all client-facing profile data from one matrix.""" from __future__ import annotations import argparse import json import pathlib import re def load(path: pathlib.Path) -> dict: data = json.loads(path.read_text(encoding="utf-8")) if data.get("version") != 1 or not isinstance(data.get("profiles"), list): raise SystemExit("Unsupported profile matrix schema") ids: set[str] = set() aliases: set[str] = set() for item in data["profiles"]: required = {"id", "alias", "context", "model_env", "description"} missing = required - item.keys() if missing: raise SystemExit(f"Profile entry missing: {sorted(missing)}") if item["id"] in ids or item["alias"] in aliases: raise SystemExit(f"Duplicate profile or alias: {item['id']}") if not isinstance(item["context"], int) or item["context"] < 8192: raise SystemExit(f"Invalid context for {item['id']}") ids.add(item["id"]) aliases.add(item["alias"]) if data.get("default_profile") not in ids: raise SystemExit("default_profile is not defined") return data def write_if_changed(path: pathlib.Path, content: str) -> None: if path.exists() and path.read_text(encoding="utf-8") == content: return path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content, encoding="utf-8") def render_router(data: dict) -> str: payload = { "profiles": { item["id"]: { "context": item["context"], "model_alias": item["alias"], } for item in data["profiles"] } } return json.dumps(payload, indent=2, ensure_ascii=False) + "\n" def render_docs(data: dict) -> str: lines = [ "# Profilmatrix", "", "Diese Datei wird aus `config/profile-matrix.json` erzeugt. Änderungen gehören nur in die JSON-Matrix.", "", f"Standardprofil: **{data['default_profile']}** · globales Ausgabelimit: **{data['max_output_tokens']} Token**", "", "| Profil | API-Alias | Kontext | Modell | GPU-Verteilung | Vision | MTP |", "|---|---|---:|---|---|---|---:|", ] for item in data["profiles"]: lines.append( f"| {item['id']} | `{item['alias']}` | {item['context']:,} | " f"{item.get('model_family', '')} | {item.get('gpu_split', '')} | " f"{'ja' if item.get('vision') else 'nein'} | {item.get('mtp', '')} |" ) lines.extend(["", "## Zweck", ""]) for item in data["profiles"]: lines.append(f"- **{item['id']}**: {item['description']}") return "\n".join(lines) + "\n" def verify_compose(data: dict, compose: pathlib.Path) -> None: text = compose.read_text(encoding="utf-8") expected_cap = f'MAX_GENERATION_TOKENS: "{int(data["max_output_tokens"])}"' if expected_cap not in text: raise SystemExit("Router output-token cap drift") for item in data["profiles"]: block_match = re.search( rf"(?ms)^ llama-{re.escape(item['id'])}:\n(?P.*?)(?=^ [a-zA-Z0-9_-]+:|\Z)", text, ) if not block_match: raise SystemExit(f"Compose service llama-{item['id']} is missing") block = block_match.group("body") if f"- {item['alias']}" not in block: raise SystemExit(f"Compose alias drift for {item['id']}") env_prefix = item["id"].upper() if f"${{{env_prefix}_CONTEXT:-{item['context']}}}" not in block: raise SystemExit(f"Compose context drift for {item['id']}") def main() -> None: root = pathlib.Path(__file__).resolve().parents[2] parser = argparse.ArgumentParser() parser.add_argument("--matrix", type=pathlib.Path, default=root / "config/profile-matrix.json") parser.add_argument("--router", type=pathlib.Path, default=root / "router/router_profiles.json") parser.add_argument("--docs", type=pathlib.Path, default=root / "docs/STANDARD_PROFILE_MATRIX.md") parser.add_argument("--compose", type=pathlib.Path, default=root / "compose.yaml") parser.add_argument("--check", action="store_true") args = parser.parse_args() data = load(args.matrix) router = render_router(data) docs = render_docs(data) verify_compose(data, args.compose) if args.check: if args.router.read_text(encoding="utf-8") != router: raise SystemExit("router_profiles.json is not generated from the matrix") if args.docs.read_text(encoding="utf-8") != docs: raise SystemExit("profile documentation is not generated from the matrix") else: write_if_changed(args.router, router) write_if_changed(args.docs, docs) print("PROFILE_MATRIX_OK") if __name__ == "__main__": main()