File size: 1,935 Bytes
19de729
 
 
 
 
 
 
cf9b3dc
19de729
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""
telemetry/logger.py — append-only JSONL logging for Q&A turns.

Usage:
    from analyzer.telemetry.logger import QALogger
    log = QALogger("logs/chat.jsonl")
    log.write(user="find farming grants", intent="search", args={"keyword":"farming"},
              answer_md="...", ok=True, latency_ms=321, meta={"model":"gpt-4.1-mini"})
"""
from __future__ import annotations
from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Any, Dict, Optional
import json, os, time, threading, uuid, datetime as dt

@dataclass
class QATurn:
    ts: str
    session_id: str
    turn_id: str
    user: str
    intent: str
    args: Dict[str, Any] = field(default_factory=dict)
    answer_md: str = ""
    ok: bool = True
    latency_ms: Optional[int] = None
    meta: Dict[str, Any] = field(default_factory=dict)

class QALogger:
    def __init__(self, path: str | Path):
        self.path = Path(path)
        self.path.parent.mkdir(parents=True, exist_ok=True)
        self._lock = threading.Lock()
        self._session = os.getenv("CHAT_SESSION_ID") or str(uuid.uuid4())

    def write(self, *, user: str, intent: str, args: Dict[str, Any],
              answer_md: str, ok: bool, latency_ms: Optional[int],
              meta: Optional[Dict[str, Any]] = None) -> None:
        turn = QATurn(
            ts=dt.datetime.utcnow().isoformat(timespec="seconds") + "Z",
            session_id=self._session,
            turn_id=str(uuid.uuid4()),
            user=str(user),
            intent=str(intent),
            args=args or {},
            answer_md=str(answer_md or ""),
            ok=bool(ok),
            latency_ms=int(latency_ms) if latency_ms is not None else None,
            meta=meta or {},
        )
        line = json.dumps(asdict(turn), ensure_ascii=False)
        with self._lock:
            with open(self.path, "a", encoding="utf-8") as fh:
                fh.write(line + "\n")