Spaces:
Running
Running
github-actions[bot]
Deploy from GitHub 39b3777315c11d9c8bcd39ad7bf034f2a88a7379 (filtered: code + Dockerfile + README + NOTICES only)
2e175db | """ | |
| API schemas (v1). | |
| These are the public contract for the /v1/scan/image endpoint. Treat any change | |
| to a field name, type, or required-ness as a breaking change. | |
| Forward-compatibility notes | |
| --------------------------- | |
| • `probabilities` is a fixed 4-class vector. Stage 1 only meaningfully populates | |
| `authentic` and `ai_generated`; `deepfake` and `edited` start at 0.0 until | |
| the corresponding detectors come online in Stage 2. Clients should treat 0.0 | |
| as "not assessed" for an unsigned-classifier slot — but the field is always | |
| present so the schema itself never changes. | |
| • `signals` is a list, currently with a single entry for the CLIP detector. | |
| More detectors (frequency, face-swap) append to this list in later stages. | |
| • `provenance` is always present. When C2PA is disabled or unavailable, | |
| `c2pa_present` is False and `c2pa_valid` is None. | |
| """ | |
| from __future__ import annotations | |
| from typing import Literal | |
| from pydantic import BaseModel, Field | |
| # The 4-class taxonomy. New classes must NOT be added without bumping API to v2. | |
| Verdict = Literal["authentic", "ai_generated", "deepfake", "edited", "uncertain"] | |
| class Probabilities(BaseModel): | |
| """Probability mass over the 4 mutually-exclusive classes. | |
| Sums to 1.0 (allowing for floating-point rounding within ±1e-3). | |
| """ | |
| authentic: float = Field(ge=0.0, le=1.0) | |
| ai_generated: float = Field(ge=0.0, le=1.0) | |
| deepfake: float = Field(ge=0.0, le=1.0) | |
| edited: float = Field(ge=0.0, le=1.0) | |
| class DetectorSignal(BaseModel): | |
| """Per-detector contribution, surfaced for transparency / debugging. | |
| `score` is the detector's own internal "fakeness" estimate in [0, 1]; | |
| its meaning depends on the detector. Aggregation into `probabilities` | |
| happens in the ensemble layer. | |
| """ | |
| name: str | |
| score: float = Field(ge=0.0, le=1.0) | |
| notes: str | None = None | |
| class Provenance(BaseModel): | |
| """C2PA / Content Credentials check. | |
| A trustworthy C2PA manifest from a known camera or generator can short- | |
| circuit the model — those signals are currently advisory only. | |
| """ | |
| c2pa_present: bool | |
| c2pa_valid: bool | None = None # None → not checked / unverifiable | |
| issuer: str | None = None # e.g. "Sony", "OpenAI", "Adobe" | |
| claim_generator: str | None = None # raw claim_generator string from the manifest | |
| class ScanResponse(BaseModel): | |
| """The /v1/scan/image response. This is the public contract.""" | |
| verdict: Verdict | |
| confidence: float = Field(ge=0.0, le=1.0) | |
| probabilities: Probabilities | |
| signals: list[DetectorSignal] | |
| provenance: Provenance | |
| model_version: str | |
| scan_id: str | |
| latency_ms: float | |
| class ErrorResponse(BaseModel): | |
| """Uniform error shape for non-2xx responses.""" | |
| error: str | |
| detail: str | None = None | |