Spaces:
Running
Running
github-actions[bot]
Deploy from GitHub 1af737237f5d10dfa9cf12849d98f47c3b30ce37 (filtered: code + Dockerfile + README + NOTICES only)
a2f55b2 Download src/deepfake_scanner/storage/db.py from Veridicate/scanner: direct link, hf CLI and curl.
- Browser
- Download file 2.36 kB
-
https://huggingface.co/spaces/Veridicate/scanner/resolve/main/src/deepfake_scanner/storage/db.py
- Command line
-
hf download hf://spaces/Veridicate/scanner/src/deepfake_scanner/storage/db.py
-
curl -L -o db.py https://huggingface.co/spaces/Veridicate/scanner/resolve/main/src/deepfake_scanner/storage/db.py
2.36 kB
| """ | |
| Scan-record persistence. | |
| Important | |
| --------- | |
| This module persists ONLY metadata (scan_id, verdict, model_version, latency, | |
| timestamp). The image itself is NEVER stored here. Image storage is a separate, | |
| opt-in path handled by `storage.blob`. | |
| Stage 1 ships an in-memory fallback so the service runs out of the box with | |
| no database. Set DATABASE_URL to switch to Postgres (Neon, Supabase, etc.). | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import time | |
| from dataclasses import dataclass, field | |
| from ..config import settings | |
| log = logging.getLogger(__name__) | |
| class ScanRecord: | |
| scan_id: str | |
| verdict: str | |
| confidence: float | |
| model_version: str | |
| latency_ms: float | |
| c2pa_present: bool | |
| timestamp_unix: float = field(default_factory=time.time) | |
| # In-memory store — bounded to last N records to avoid leaking memory. | |
| _MEMORY_CAP = 1000 | |
| _memory_store: list[ScanRecord] = [] | |
| def record_scan(record: ScanRecord) -> None: | |
| """Persist a scan record. No-op-safe; never raises into the request path.""" | |
| try: | |
| if settings.database_url: | |
| _record_postgres(record) | |
| else: | |
| _record_memory(record) | |
| except Exception as exc: | |
| # Persistence failures must NEVER break the user-facing scan response. | |
| log.warning("Failed to persist scan record: %s", exc) | |
| def _record_memory(record: ScanRecord) -> None: | |
| _memory_store.append(record) | |
| if len(_memory_store) > _MEMORY_CAP: | |
| del _memory_store[: len(_memory_store) - _MEMORY_CAP] | |
| def _record_postgres(record: ScanRecord) -> None: # pragma: no cover - infra | |
| """Lazy import — SQLAlchemy is heavy and not needed in dev/tests.""" | |
| # Implementation intentionally deferred until Stage 2 — schema below. | |
| # | |
| # CREATE TABLE scans ( | |
| # scan_id TEXT PRIMARY KEY, | |
| # verdict TEXT NOT NULL, | |
| # confidence REAL NOT NULL, | |
| # model_version TEXT NOT NULL, | |
| # latency_ms REAL NOT NULL, | |
| # c2pa_present BOOLEAN NOT NULL, | |
| # created_at TIMESTAMPTZ NOT NULL DEFAULT now() | |
| # ); | |
| raise NotImplementedError("Postgres persistence wired up in Stage 2.") | |
| def memory_store_snapshot() -> list[ScanRecord]: | |
| """Test/debug helper — returns a copy of the in-memory store.""" | |
| return list(_memory_store) | |