""" Kompakte Zahlen- und JSON-Aufbereitung für KI-Platzhalter (Token sparen). - Floats: sinnvolle Nachkommastellen je nach Größenordnung (kleine Werte <0,1 mehr Präzision). - ≥10 meist ganzzahlig; Prozent/Verhältnisse über denselben Mechanismus lesbar. - Rekursiv auf dict/list-Strukturen vor json.dumps in _safe_json anwendbar. """ from __future__ import annotations import math from decimal import Decimal from typing import Any def compact_float_for_prompt(x: float) -> float | int: """ Reduziert unnötige Nachkommastellen; erhält kleine Beträge (<0,1) mit mehr Stellen. """ if not math.isfinite(x): return x ax = abs(x) if ax == 0.0: return 0 if ax >= 100.0: return int(round(x)) if ax >= 10.0: return int(round(x)) if ax >= 1.0: r = round(x, 2) return int(r) if abs(r - int(round(r))) < 1e-6 else r if ax >= 0.1: r = round(x, 2) return int(r) if abs(r - int(round(r))) < 1e-6 else r if ax >= 0.01: return round(x, 3) return round(x, 4) def normalize_prompt_number(x: Any) -> Any: """int/Decimal/float kompakt; Rest unverändert.""" if x is None: return None if isinstance(x, bool): return x if isinstance(x, int) and not isinstance(x, bool): return x if isinstance(x, Decimal): try: xf = float(x) except Exception: return x return compact_float_for_prompt(xf) if isinstance(x, float): return compact_float_for_prompt(x) return x def compact_json_payload_for_prompts(obj: Any) -> Any: """ Tiefe Kopie mit kompakten Zahlen (dicts/list/tuples rekursiv). Strings und dict-Keys werden nicht verändert. """ if obj is None: return None if isinstance(obj, dict): return {k: compact_json_payload_for_prompts(v) for k, v in obj.items()} if isinstance(obj, (list, tuple)): t = [compact_json_payload_for_prompts(v) for v in obj] return tuple(t) if isinstance(obj, tuple) else t return normalize_prompt_number(obj) def session_metrics_list_to_key_value_compact(metrics: list[Any] | None) -> dict[str, Any]: """ Session-Metriken für KI-JSON: nur key → Wert (keine wiederholten Namen/Beschreibungen). Semantik: {{training_parameters_glossary_md}} im Prompt ergänzen. """ out: dict[str, Any] = {} for m in metrics or []: if not isinstance(m, dict): continue k = m.get("key") if not k: continue v = m.get("value") dt = (m.get("data_type") or "").lower() if v is None: out[str(k)] = None continue if dt == "integer": try: out[str(k)] = int(v) except (TypeError, ValueError): out[str(k)] = normalize_prompt_number(v) elif dt == "boolean": out[str(k)] = bool(v) elif dt == "string": out[str(k)] = str(v) else: out[str(k)] = normalize_prompt_number(v) return out