Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import json | |
| import uuid | |
| from dataclasses import asdict, is_dataclass | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| from typing import Any | |
| _CANONICAL_INPUT_KEYS = ( | |
| 'inputs', | |
| 'input', | |
| 'pack', | |
| 'pack_id', | |
| 'pack_name', | |
| 'pack_path', | |
| 'project', | |
| 'scenario_id', | |
| 'scenario_count', | |
| 'query', | |
| 'prompt', | |
| 'transcript', | |
| 'text', | |
| ) | |
| _MODEL_HINT_KEYS = ( | |
| 'model_name', | |
| 'base_model_id', | |
| 'base_model', | |
| 'model_id', | |
| 'adapter_name', | |
| 'loaded_from', | |
| 'adapter_path', | |
| ) | |
| def utc_now() -> str: | |
| return datetime.now(timezone.utc).isoformat(timespec='seconds') | |
| def _json_safe(value: Any) -> Any: | |
| if is_dataclass(value): | |
| return _json_safe(asdict(value)) | |
| if isinstance(value, Path): | |
| return str(value) | |
| if isinstance(value, dict): | |
| return {str(key): _json_safe(item) for key, item in value.items()} | |
| if isinstance(value, (list, tuple)): | |
| return [_json_safe(item) for item in value] | |
| return value | |
| def _nonempty(value: Any) -> bool: | |
| return value not in (None, '', [], {}, ()) | |
| def _infer_input_payload(payload: dict[str, Any]) -> Any: | |
| existing_inputs = payload.get('inputs') | |
| if _nonempty(existing_inputs): | |
| return existing_inputs | |
| inputs: dict[str, Any] = {} | |
| for key in _CANONICAL_INPUT_KEYS: | |
| if key in payload and key != 'inputs' and _nonempty(payload[key]): | |
| inputs[key] = payload[key] | |
| if inputs: | |
| return inputs | |
| for key in ('project', 'pack_id', 'pack_name', 'pack_path', 'pack'): | |
| if key in payload and _nonempty(payload[key]): | |
| inputs[key] = payload[key] | |
| return inputs | |
| def _infer_model_name(value: Any) -> str | None: | |
| if isinstance(value, dict): | |
| for key in _MODEL_HINT_KEYS: | |
| candidate = value.get(key) | |
| if isinstance(candidate, str) and candidate.strip(): | |
| return candidate.strip() | |
| for item in value.values(): | |
| candidate = _infer_model_name(item) | |
| if candidate: | |
| return candidate | |
| elif isinstance(value, list): | |
| for item in value: | |
| candidate = _infer_model_name(item) | |
| if candidate: | |
| return candidate | |
| return None | |
| def canonicalize_trace_payload(payload: dict[str, Any]) -> dict[str, Any]: | |
| normalized = _json_safe(payload) | |
| timestamp = normalized.get('timestamp') or normalized.get('finished_at') or normalized.get('started_at') or utc_now() | |
| parsed_outputs = normalized.get('parsed_outputs') | |
| if not _nonempty(parsed_outputs): | |
| parsed_outputs = normalized.get('result') | |
| if not _nonempty(parsed_outputs): | |
| parsed_outputs = normalized.get('results') | |
| if not _nonempty(parsed_outputs): | |
| parsed_outputs = normalized.get('output') | |
| if not _nonempty(parsed_outputs): | |
| parsed_outputs = {} | |
| model_name = normalized.get('model_name') | |
| if not _nonempty(model_name): | |
| model_name = _infer_model_name(parsed_outputs) or _infer_model_name(normalized) | |
| if not _nonempty(model_name): | |
| model_name = 'unknown' | |
| normalized['timestamp'] = str(timestamp) | |
| normalized['inputs'] = _infer_input_payload(normalized) | |
| normalized['parsed_outputs'] = parsed_outputs | |
| normalized['model_name'] = str(model_name) | |
| return normalized | |
| def write_trace_artifact(artifact_dir: str | Path, payload: dict[str, Any]) -> Path: | |
| artifact_dir = Path(artifact_dir) | |
| trace_dir = artifact_dir / 'traces' | |
| trace_dir.mkdir(parents=True, exist_ok=True) | |
| run_id = str(payload.get('run_id') or uuid.uuid4().hex) | |
| kind = str(payload.get('kind', 'trace')).strip().replace('/', '_').replace(' ', '_') or 'trace' | |
| trace_path = trace_dir / f'{kind}-{run_id}.json' | |
| normalized = canonicalize_trace_payload(payload) | |
| normalized['run_id'] = run_id | |
| normalized['trace_path'] = str(trace_path) | |
| trace_path.write_text(json.dumps(normalized, indent=2, ensure_ascii=False, sort_keys=True, default=str), encoding='utf-8') | |
| return trace_path | |