Spaces:
Running
Running
sara.mesquita commited on
Commit ·
1d13722
1
Parent(s): ee32f51
feat: add trace logging for Sharing is Caring badge
Browse files- core/tracer.py +85 -0
core/tracer.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
tracer.py — Logging de traces para o badge "Sharing is Caring" do hackathon.
|
| 3 |
+
|
| 4 |
+
Salva cada interação (analyze + confirm) em data/traces.jsonl.
|
| 5 |
+
Quando quiser publicar no HF Hub, chame push_to_hub().
|
| 6 |
+
|
| 7 |
+
Variáveis de ambiente:
|
| 8 |
+
HF_TOKEN — token HuggingFace (necessário só para push)
|
| 9 |
+
HF_DATASET_ID — ex: "build-small-hackathon/animal-visto-traces"
|
| 10 |
+
TRACE_ENABLED — "0" para desabilitar completamente (default: habilitado)
|
| 11 |
+
"""
|
| 12 |
+
import json
|
| 13 |
+
import logging
|
| 14 |
+
import os
|
| 15 |
+
import threading
|
| 16 |
+
from datetime import datetime, timezone
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
|
| 19 |
+
from core.database import DATA_DIR
|
| 20 |
+
|
| 21 |
+
log = logging.getLogger(__name__)
|
| 22 |
+
|
| 23 |
+
TRACES_PATH = DATA_DIR / "traces.jsonl"
|
| 24 |
+
ENABLED = os.environ.get("TRACE_ENABLED", "1") != "0"
|
| 25 |
+
HF_DATASET = os.environ.get("HF_DATASET_ID", "")
|
| 26 |
+
|
| 27 |
+
_lock = threading.Lock()
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def log_trace(record: dict) -> None:
|
| 31 |
+
"""Appenda um trace em data/traces.jsonl (thread-safe)."""
|
| 32 |
+
if not ENABLED:
|
| 33 |
+
return
|
| 34 |
+
record = {
|
| 35 |
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
| 36 |
+
**record,
|
| 37 |
+
}
|
| 38 |
+
# Remove campos sensíveis
|
| 39 |
+
record.pop("photo_path", None)
|
| 40 |
+
record.pop("temp_path", None)
|
| 41 |
+
coords = record.get("gps", {})
|
| 42 |
+
if coords:
|
| 43 |
+
# Arredonda para 2 casas (~1km de precisão) para preservar privacidade
|
| 44 |
+
record["gps"] = {
|
| 45 |
+
"lat": round(coords["lat"], 2) if coords.get("lat") else None,
|
| 46 |
+
"lng": round(coords["lng"], 2) if coords.get("lng") else None,
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
try:
|
| 50 |
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
| 51 |
+
with _lock:
|
| 52 |
+
with open(TRACES_PATH, "a", encoding="utf-8") as f:
|
| 53 |
+
f.write(json.dumps(record, ensure_ascii=False) + "\n")
|
| 54 |
+
except Exception as e:
|
| 55 |
+
log.warning("Trace não salvo: %s", e)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def push_to_hub() -> None:
|
| 59 |
+
"""
|
| 60 |
+
Publica traces.jsonl como dataset no HF Hub.
|
| 61 |
+
Só chamar quando estiver pronto para publicar.
|
| 62 |
+
|
| 63 |
+
Requer: HF_TOKEN e HF_DATASET_ID definidos.
|
| 64 |
+
"""
|
| 65 |
+
if not HF_DATASET:
|
| 66 |
+
log.error("HF_DATASET_ID não definido — abortando push.")
|
| 67 |
+
return
|
| 68 |
+
if not TRACES_PATH.exists():
|
| 69 |
+
log.warning("Nenhum trace para publicar.")
|
| 70 |
+
return
|
| 71 |
+
|
| 72 |
+
try:
|
| 73 |
+
from huggingface_hub import HfApi
|
| 74 |
+
api = HfApi(token=os.environ.get("HF_TOKEN", ""))
|
| 75 |
+
api.create_repo(repo_id=HF_DATASET, repo_type="dataset", exist_ok=True)
|
| 76 |
+
api.upload_file(
|
| 77 |
+
path_or_fileobj=str(TRACES_PATH),
|
| 78 |
+
path_in_repo="traces.jsonl",
|
| 79 |
+
repo_id=HF_DATASET,
|
| 80 |
+
repo_type="dataset",
|
| 81 |
+
commit_message="chore: update traces",
|
| 82 |
+
)
|
| 83 |
+
log.info("Traces publicados em %s", HF_DATASET)
|
| 84 |
+
except Exception as e:
|
| 85 |
+
log.error("Erro ao publicar traces: %s", e)
|