Spaces:
Sleeping
Sleeping
Download src/interaction_log.py from claudqunwang/fixsense: direct link, hf CLI and curl.
- Browser
- Download file 2.89 kB
-
https://huggingface.co/spaces/claudqunwang/fixsense/resolve/main/src/interaction_log.py
- Command line
-
hf download hf://spaces/claudqunwang/fixsense/src/interaction_log.py
-
curl -L -o interaction_log.py https://huggingface.co/spaces/claudqunwang/fixsense/resolve/main/src/interaction_log.py
2.89 kB
| """Append-only JSONL log of user interactions (queries, follow-ups, feedback). | |
| One line per event in ``<dir>/interactions-YYYYMMDD.jsonl``. When | |
| FIXSENSE_LOG_REPO (a *private* HF dataset repo id) and HF_TOKEN are set, a background | |
| huggingface_hub.CommitScheduler pushes the folder every FIXSENSE_LOG_PUSH_MIN minutes | |
| (default 5) -- the Space's own disk is ephemeral, so this is what makes the log durable. | |
| A crash can lose at most the last interval. | |
| Each Space replica writes under its own subfolder (``path_in_repo``) so concurrent | |
| replicas never overwrite each other's files. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import logging | |
| import os | |
| import socket | |
| import threading | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| logger = logging.getLogger(__name__) | |
| class InteractionLogger: | |
| def __init__(self, directory: str = "logs") -> None: | |
| self.dir = Path(directory) | |
| self.dir.mkdir(parents=True, exist_ok=True) | |
| self._lock = threading.Lock() | |
| self._scheduler = None | |
| repo = os.environ.get("FIXSENSE_LOG_REPO", "").strip() | |
| token = os.environ.get("HF_TOKEN", "").strip() | |
| if repo and token: | |
| try: | |
| from huggingface_hub import CommitScheduler | |
| self._scheduler = CommitScheduler( | |
| repo_id=repo, | |
| repo_type="dataset", | |
| folder_path=self.dir, | |
| path_in_repo=f"interactions/{socket.gethostname()}", | |
| every=float(os.environ.get("FIXSENSE_LOG_PUSH_MIN", "5")), | |
| private=True, | |
| token=token, | |
| ) | |
| self._lock = self._scheduler.lock # recommended: share the scheduler's lock | |
| logger.info("Interaction log will sync to private dataset %s", repo) | |
| except Exception: | |
| logger.exception("Could not start CommitScheduler; logging locally only") | |
| elif repo and not token: | |
| logger.warning("FIXSENSE_LOG_REPO is set but HF_TOKEN is not; logging locally only") | |
| def log(self, event: dict) -> None: | |
| now = datetime.now(timezone.utc) | |
| record = {"ts": now.isoformat(timespec="milliseconds"), **event} | |
| path = self.dir / f"interactions-{now:%Y%m%d}.jsonl" | |
| line = json.dumps(record, ensure_ascii=False, default=str) | |
| try: | |
| with self._lock: | |
| with open(path, "a", encoding="utf-8") as f: | |
| f.write(line + "\n") | |
| except Exception: | |
| logger.exception("Failed to write interaction log") | |
| def flush(self) -> None: | |
| """Push pending lines now (used on shutdown).""" | |
| if self._scheduler is not None: | |
| try: | |
| self._scheduler.trigger().result() | |
| except Exception: | |
| logger.exception("Final log push failed") | |