recognizer-api / apps /usage_log.py
Sathya-UM's picture
Deploy headless recognizer API (Docker)
c25f760 verified
Raw
History Blame Contribute Delete
2.89 kB
"""Aggregate, privacy-preserving usage logging.
Logs the RESULT of each identification (predicted raaga + confidence + tonic + whether a
prediction was made) to a private Hugging Face Dataset. It NEVER logs the audio, an IP, or any
user identifier — just anonymous per-identification result metadata, so we can see how much the
app is used and what it's recognising in the wild (the passive real-world signal).
Robustness:
- Disabled unless HF_TOKEN is set (a write token, as a Space secret). Without it the app runs
exactly as before, just without logging.
- Every call is wrapped so a logging failure can NEVER break recognition.
- Uses huggingface_hub.CommitScheduler: appends locally, flushes to the dataset every few minutes
(one commit per identification would be far too many).
"""
from __future__ import annotations
import json
import os
from pathlib import Path
DATASET = "twelveswaras/usage-logs"
LOG_DIR = Path("usage_logs")
LOG_FILE = LOG_DIR / "identifications.jsonl"
_scheduler = None
_tried = False
def _scheduler_or_none():
global _scheduler, _tried
if _scheduler is not None or _tried:
return _scheduler
_tried = True
if not os.environ.get("HF_TOKEN"):
return None # logging off; app still works
try:
from huggingface_hub import CommitScheduler
LOG_DIR.mkdir(exist_ok=True)
_scheduler = CommitScheduler(repo_id=DATASET, repo_type="dataset", private=True,
folder_path=str(LOG_DIR), path_in_repo="data", every=5)
except Exception: # noqa: BLE001 (bad token / no access -> stay disabled)
_scheduler = None
return _scheduler
def record(*, top1=None, confidence=None, top3=None, tonic_hz=None,
heard_seconds=None, no_prediction=False, elapsed_s=None) -> None:
"""Append one identification's RESULT metadata. No audio, no PII. Never raises."""
try:
sch = _scheduler_or_none()
if sch is None:
return
from datetime import datetime, timezone
row = {
"ts": datetime.now(timezone.utc).isoformat(timespec="seconds"),
"top1": top1,
"confidence": round(float(confidence), 3) if confidence is not None else None,
"top3": top3,
"tonic_hz": round(float(tonic_hz)) if tonic_hz else None,
"heard_s": round(float(heard_seconds), 1) if heard_seconds is not None else None,
"no_prediction": bool(no_prediction),
"elapsed_s": round(float(elapsed_s), 2) if elapsed_s is not None else None,
}
with sch.lock:
with open(LOG_FILE, "a", encoding="utf-8") as fh:
fh.write(json.dumps(row, ensure_ascii=False) + "\n")
except Exception: # noqa: BLE001 (logging must never break recognition)
pass