Spaces:
Running
Running
github-actions[bot]
Deploy from GitHub 1af737237f5d10dfa9cf12849d98f47c3b30ce37 (filtered: code + Dockerfile + README + NOTICES only)
a2f55b2 Download src/deepfake_scanner/config.py from Veridicate/scanner: direct link, hf CLI and curl.
- Browser
- Download file 7.07 kB
-
https://huggingface.co/spaces/Veridicate/scanner/resolve/main/src/deepfake_scanner/config.py
- Command line
-
hf download hf://spaces/Veridicate/scanner/src/deepfake_scanner/config.py
-
curl -L -o config.py https://huggingface.co/spaces/Veridicate/scanner/resolve/main/src/deepfake_scanner/config.py
7.07 kB
| """ | |
| Central configuration for DeepFakeScanner. | |
| All runtime knobs are read from environment variables with sensible defaults | |
| so the service can run unchanged from local dev β HF Spaces β Cloud Run. | |
| Read this once at import; do NOT scatter os.getenv() calls throughout the code. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from dataclasses import dataclass | |
| def _env_bool(name: str, default: bool) -> bool: | |
| raw = os.getenv(name) | |
| if raw is None: | |
| return default | |
| return raw.strip().lower() in {"1", "true", "yes", "on"} | |
| def _env_int(name: str, default: int) -> int: | |
| raw = os.getenv(name) | |
| if raw is None: | |
| return default | |
| try: | |
| return int(raw) | |
| except ValueError: | |
| return default | |
| class Settings: | |
| # ------------------------------------------------------------------ API | |
| api_title: str = "DeepFakeScanner" | |
| api_version: str = "0.2.0" | |
| # Build identifier for the deployed service. Three versions travel in the | |
| # API response and they answer different questions: | |
| # api_version β the response CONTRACT. Bump only on a breaking change. | |
| # model_version β which trained head is serving (see below). | |
| # service_version β which BUILD of the application code is live. | |
| # The third exists because a deploy can change behaviour without touching | |
| # either of the other two: the 2026-08-13 release fixed a dead C2PA reader, | |
| # so provenance fields went from always-absent to populated, with an | |
| # identical contract and an identical model. Bump this on every deploy that | |
| # changes runtime behaviour, and note it in CHANGELOG.md. | |
| # v0.5.0 β C2PA provenance reading repaired (2026-08-13) | |
| # v0.6.0 β validated provenance now overrides the model, one-directionally | |
| # (68% -> 100% on the 100-image closed-generator benchmark) | |
| # v0.7.0 β EXIF orientation applied on decode; portrait phone photos were | |
| # being scanned rotated 90 degrees | |
| # v0.8.0 β C2PA validity fails closed (Untrusted/Unknown no longer read as | |
| # valid); refuse to start without a trained head; /v1/info | |
| # reports head_loaded | |
| service_version: str = os.getenv("SERVICE_VERSION", "v0.8.0") | |
| max_upload_bytes: int = _env_int("MAX_UPLOAD_BYTES", 10 * 1024 * 1024) # 10 MB | |
| # --------------------------------------------------------- Image policy | |
| # Privacy-by-default: visitor uploads are NEVER persisted. | |
| # Logged-in paid users will be able to opt in later via a separate flag. | |
| store_uploads: bool = _env_bool("STORE_UPLOADS", False) | |
| # ---------------------------------------------------------- Detectors | |
| # Stage 1: only the CLIP-based classifier is wired up. | |
| # Stage 2 will flip these on as the detectors are trained / verified. | |
| enable_clip_detector: bool = _env_bool("ENABLE_CLIP_DETECTOR", True) | |
| enable_frequency_detector: bool = _env_bool("ENABLE_FREQUENCY_DETECTOR", False) | |
| enable_face_swap_detector: bool = _env_bool("ENABLE_FACE_SWAP_DETECTOR", False) | |
| # The CLIP backbone we use for feature extraction. | |
| # OpenAI CLIP ViT-B/32 weights are MIT-licensed (commercially safe). | |
| clip_model_name: str = os.getenv("CLIP_MODEL_NAME", "openai/clip-vit-base-patch32") | |
| # Path to the trained classifier-head checkpoint. ClipClassifier auto- | |
| # loads this in __init__ if the file exists. The same env var works | |
| # locally (dev machine) and inside the inference Docker image. | |
| # Stage 3A: head_v3a.pt (multi-generator: Flux+SDXL+SD3.5+AuraFlow). | |
| head_checkpoint_path: str = os.getenv( | |
| "HEAD_CHECKPOINT_PATH", "data/checkpoints/head_v3a.pt" | |
| ) | |
| # Fallback for production: if the local checkpoint file isn't present, | |
| # ClipClassifier downloads the weights from this HF Hub model repo at | |
| # startup. The repo is PRIVATE β the container authenticates with the | |
| # HF_TOKEN secret set in the HF Space settings (huggingface_hub reads | |
| # HF_TOKEN from the environment automatically). Setting this to an | |
| # empty string disables the fallback (used in tests). | |
| # Stage 3A: head_v3a.pt. The Stage 2 head_v1.pt remains in the same | |
| # private repo for rollback β set HEAD_CHECKPOINT_HF_FILENAME=head_v1.pt | |
| # (and MODEL_VERSION=v0.3.0-stage2) to revert without a redeploy. | |
| head_checkpoint_hf_repo: str = os.getenv( | |
| "HEAD_CHECKPOINT_HF_REPO", "Veridicate/scanner-head-v1" | |
| ) | |
| head_checkpoint_hf_filename: str = os.getenv( | |
| "HEAD_CHECKPOINT_HF_FILENAME", "head_v3a.pt" | |
| ) | |
| # Refuse to start if the trained head cannot be loaded. Scaffold mode runs | |
| # a RANDOMLY INITIALISED head: it answers every request, reports the | |
| # configured model_version, and /health returns ok - so a failed weight | |
| # download looks exactly like a healthy service returning nonsense. That is | |
| # the same shape as the 2026-08 C2PA outage, and it is why this defaults to | |
| # True. Tests and local scaffold work set REQUIRE_TRAINED_HEAD=false | |
| # explicitly (see tests/conftest.py). | |
| require_trained_head: bool = _env_bool("REQUIRE_TRAINED_HEAD", True) | |
| # ---------------------------------------------------------- Provenance | |
| enable_c2pa_check: bool = _env_bool("ENABLE_C2PA_CHECK", True) | |
| # ------------------------------------------------------------ Storage | |
| # Postgres URL for scan records (None β in-memory fallback for local dev). | |
| database_url: str | None = os.getenv("DATABASE_URL") | |
| # S3-compatible blob storage (e.g. Cloudflare R2). Only used when | |
| # store_uploads is True AND a paid user opts in. | |
| blob_endpoint: str | None = os.getenv("BLOB_ENDPOINT") | |
| blob_bucket: str | None = os.getenv("BLOB_BUCKET") | |
| # ---------------------------------------------------- Model identifier | |
| # Surfaced in API responses so clients can pin behaviour to a version. | |
| # v0.4.0-stage3a = CLIP head trained on a multi-generator dataset | |
| # (50k Flux + 20k SDXL + 20k SD 3.5 + 10k AuraFlow + matched authentic). | |
| # In-distribution test accuracy 98.43%; +5.55 pp vs the Stage 2 head on | |
| # the SDXL hold-out (a generator never seen in training). See | |
| # docs/stage3a-implementation.md. | |
| # Previous: v0.3.0-stage2 (Flux-only, head_v1.pt) β still available in the | |
| # HF Hub repo for rollback (see head_checkpoint_hf_filename above). | |
| model_version: str = os.getenv("MODEL_VERSION", "v0.4.0-stage3a") | |
| # --------------------------------------------------------------- CORS | |
| # Browser preflight allowlist for the static-HTML frontend. The default | |
| # covers the production domain, any Cloudflare Pages preview, and | |
| # localhost (any port) for local dev. Override via env var if a new | |
| # origin needs access. | |
| cors_allow_origin_regex: str = os.getenv( | |
| "CORS_ALLOW_ORIGIN_REGEX", | |
| r"^(https://(www\.)?veridicate\.com|https://[a-z0-9-]+\.pages\.dev|https://[a-z0-9-]+\.dulipcf\.workers\.dev|http://localhost(:\d+)?|http://127\.0\.0\.1(:\d+)?)$", | |
| ) | |
| settings = Settings() | |