butler/gateway/media_telemetry.py
Rama main · réplica de lectura del repositorio original.
"""Last inbound vision/STT outcomes for /诊断 (no message content logged)."""
from __future__ import annotations
import json
import time
from pathlib import Path
from typing import Any, cast
from butler.configuration.settings import get_butler_home
import logging
logger = logging.getLogger(__name__)
_STATE_NAME = "runtime/media_telemetry.json"
def _state_path() -> Path:
return cast(Path, get_butler_home() / _STATE_NAME)
def record_media_event(
kind: str,
*,
provider: str,
ok: bool,
duration_ms: float,
detail: str = "",
) -> None:
"""Persist last event per kind (``vision`` | ``stt``)."""
path = _state_path()
path.parent.mkdir(parents=True, exist_ok=True)
from butler.gateway.media_telemetry_ops import load_json_dict_safe
data: dict[str, Any] = load_json_dict_safe(path) if path.is_file() else {}
data[kind] = {
"provider": (provider or "?")[:40],
"ok": bool(ok),
"duration_ms": round(max(0.0, duration_ms), 1),
"detail": (detail or "")[:120],
"at": time.time(),
}
path.write_text(json.dumps(data, ensure_ascii=False, indent=0), encoding="utf-8")
def load_media_telemetry() -> dict[str, Any]:
path = _state_path()
if not path.is_file():
return {}
from butler.gateway.media_telemetry_ops import load_json_dict_safe
return cast(dict[str, Any], load_json_dict_safe(path))
def format_media_diagnostic_lines() -> list[str]:
data = load_media_telemetry()
if not data:
return []
lines: list[str] = []
for kind, label in (("vision", "识图"), ("stt", "语音")):
row = data.get(kind)
if not isinstance(row, dict):
continue
status = "成功" if row.get("ok") else "失败"
ms = row.get("duration_ms", "?")
prov = row.get("provider") or "?"
extra = f" ({row['detail']})" if row.get("detail") else ""
lines.append(f" 上次{label}: {prov} {status} {ms}ms{extra}")
return lines