File size: 14,055 Bytes
aac350d 23d337e aac350d 23d337e aac350d 23d337e aac350d 23d337e 9bd3ee0 23d337e 9bd3ee0 7e25f7a aac350d 23d337e aac350d 23d337e 9bd3ee0 7e25f7a aac350d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | """Report domain models — the unified output of a face-intelligence job."""
from __future__ import annotations
import uuid
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
class Evidence(BaseModel):
"""Preserved raw provider output — never discarded.
Every result from every provider is preserved as Evidence, regardless
of success. This is the foundation of evidence-first design.
"""
provider: str
capability: str
timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
raw: Any = None # verbatim provider response
normalized: dict = Field(default_factory=dict)
elapsed_ms: float = 0.0
success: bool = True
error: Optional[str] = None
error_type: Optional[str] = None
metadata: dict = Field(default_factory=dict)
retry_count: int = 0
limitations: List[str] = Field(default_factory=list)
class ConfidenceScore(BaseModel):
"""Explainable confidence — decomposed into weighted sub-scores."""
overall: float # 0.0 – 1.0
components: Dict[str, float] = Field(default_factory=dict)
explanation: str = ""
method: str = "weighted_average"
class FaceDetection(BaseModel):
"""One detected face, with cross-provider consensus."""
box: Dict[str, int] # {x, y, w, h}
confidence: ConfidenceScore
landmarks: Optional[Dict[str, List[int]]] = None
detected_by: List[str] = Field(default_factory=list)
embedding: Optional[List[float]] = None
embedding_provider: Optional[str] = None
class FaceMatch(BaseModel):
"""A recognition match against the reference gallery."""
query_face_index: int
best_match: Optional[str] = None
confidence: ConfidenceScore
distances: Dict[str, float] = Field(default_factory=dict)
class ImageAnalysisResult(BaseModel):
"""Output of an image-analysis provider (quality, properties, features)."""
provider: str
quality_score: Optional[float] = None
brightness: Optional[float] = None
contrast: Optional[float] = None
sharpness: Optional[float] = None
noise_level: Optional[float] = None
width: Optional[int] = None
height: Optional[int] = None
channels: Optional[int] = None
color_profile: Optional[str] = None
dominant_colors: List[str] = Field(default_factory=list)
aspects: dict = Field(default_factory=dict)
confidence: Optional[ConfidenceScore] = None
class MetadataResult(BaseModel):
"""Output of a metadata-extraction provider (EXIF, XMP, IPTC)."""
provider: str
format: Optional[str] = None
exif: dict = Field(default_factory=dict)
xmp: dict = Field(default_factory=dict)
iptc: dict = Field(default_factory=dict)
gps: Optional[dict] = None
camera_make: Optional[str] = None
camera_model: Optional[str] = None
software: Optional[str] = None
capture_time: Optional[str] = None
confidence: Optional[ConfidenceScore] = None
class ForensicsResult(BaseModel):
"""Output of a forensics provider (integrity, duplicates, manipulation)."""
provider: str
integrity_score: Optional[float] = None
is_duplicate: Optional[bool] = None
duplicate_of: Optional[str] = None
similarity_score: Optional[float] = None
manipulation_indicators: List[str] = Field(default_factory=list)
ela_score: Optional[float] = None # error-level analysis
noise_inconsistency: Optional[float] = None
details: dict = Field(default_factory=dict)
confidence: Optional[ConfidenceScore] = None
class OCRResult(BaseModel):
"""Output of an OCR provider."""
provider: str
text_blocks: List[dict] = Field(default_factory=list)
full_text: str = ""
language: Optional[str] = None
confidence: Optional[ConfidenceScore] = None
class ObjectDetectionResult(BaseModel):
"""Output of an object-detection provider."""
provider: str
objects: List[dict] = Field(default_factory=list)
model: Optional[str] = None
confidence: Optional[ConfidenceScore] = None
class SceneResult(BaseModel):
"""Output of a scene-classification provider."""
provider: str
labels: List[dict] = Field(default_factory=list)
confidence: Optional[ConfidenceScore] = None
class NSFWResult(BaseModel):
"""Output of an NSFW-detection provider."""
provider: str
is_nsfw: bool = False
labels: List[str] = Field(default_factory=list)
confidence: Optional[ConfidenceScore] = None
class AIDetectionResult(BaseModel):
"""Output of an AI-generated-image-detection provider."""
provider: str
is_ai_generated: bool = False
confidence: Optional[ConfidenceScore] = None
class EmbeddingResult(BaseModel):
"""Output of an embedding provider."""
provider: str
embedding: List[float] = Field(default_factory=list)
model: Optional[str] = None
dimensions: int = 0
# --------------------------------------------------------------------------- #
# OSINT models (Phase 10-15)
# --------------------------------------------------------------------------- #
class OSINTMatch(BaseModel):
"""One merged reverse-image-search match with source classification."""
image_url: str = ""
source_page: str = ""
title: str = ""
snippet: str = ""
thumbnail: str = ""
source_type: str = "unknown"
platform: Optional[str] = None
root_domain: str = ""
is_cdn: bool = False
confidence: float = 0.0
first_seen: Optional[str] = None
found_by: List[str] = Field(default_factory=list)
class OSINTResult(BaseModel):
"""Output of the OSINT reverse-search orchestrator."""
providers_invoked: List[str] = Field(default_factory=list)
providers_succeeded: List[str] = Field(default_factory=list)
providers_failed: List[str] = Field(default_factory=list)
total_matches: int = 0
matches: List[OSINTMatch] = Field(default_factory=list)
source_type_breakdown: dict = Field(default_factory=dict)
elapsed_ms: float = 0.0
class FaceQualityMetrics(BaseModel):
"""Quality metrics for a single detected face."""
quality_score: float = 0.0
blur_score: float = 0.0
is_blurry: bool = False
face_size: int = 0 # width * height of bbox
face_size_label: str = "" # "small" | "medium" | "large"
pose_yaw: float = 0.0 # degrees; 0 = frontal
pose_pitch: float = 0.0
pose_roll: float = 0.0
pose_label: str = "" # "frontal" | "profile" | "extreme"
orientation: str = "" # "upright" | "tilted" | "rotated"
is_best_face: bool = False
class FaceCluster(BaseModel):
"""A cluster of faces that appear to be the same person."""
cluster_id: int
face_indices: List[int] = Field(default_factory=list)
representative_index: int = 0
num_faces: int = 0
avg_similarity: float = 0.0
class FaceIntelligenceResult(BaseModel):
"""Output of the face intelligence service."""
total_faces: int = 0
best_face_index: Optional[int] = None
quality_metrics: List[FaceQualityMetrics] = Field(default_factory=list)
clusters: List[FaceCluster] = Field(default_factory=list)
duplicate_face_indices: List[int] = Field(default_factory=list)
elapsed_ms: float = 0.0
class ForensicMetadataReport(BaseModel):
"""Forensic metadata intelligence — expanded EXIF/XMP/IPTC/ICC."""
provider: str = "forensic_metadata"
format: Optional[str] = None
exif: dict = Field(default_factory=dict)
xmp: dict = Field(default_factory=dict)
iptc: dict = Field(default_factory=dict)
icc_profile: Optional[dict] = None
gps: Optional[dict] = None
camera_make: Optional[str] = None
camera_model: Optional[str] = None
lens_model: Optional[str] = None
software: Optional[str] = None
capture_time: Optional[str] = None
capture_time_iso: Optional[str] = None
timezone_estimate: Optional[str] = None
editing_history: List[str] = Field(default_factory=list)
thumbnail_extracted: bool = False
embedded_preview: bool = False
camera_fingerprint: Optional[str] = None # hash of camera-specific noise pattern
compression_analysis: Optional[dict] = None
confidence: Optional[ConfidenceScore] = None
class DetectedObjectIntelligence(BaseModel):
"""One detected object with intelligence metadata."""
class_label: str
confidence: float = 0.0
box: dict = Field(default_factory=dict)
crop_base64: Optional[str] = None
is_vehicle: bool = False
is_screen: bool = False
is_document: bool = False
is_phone: bool = False
is_laptop: bool = False
is_watch: bool = False
is_logo: bool = False
is_text_region: bool = False
is_license_plate: bool = False
is_qr_code: bool = False
is_barcode: bool = False
searchable_metadata: dict = Field(default_factory=dict)
class ObjectIntelligenceResult(BaseModel):
"""Output of the object intelligence service."""
total_objects: int = 0
objects: List[DetectedObjectIntelligence] = Field(default_factory=list)
vehicles: List[DetectedObjectIntelligence] = Field(default_factory=list)
license_plates: List[DetectedObjectIntelligence] = Field(default_factory=list)
qr_codes: List[DetectedObjectIntelligence] = Field(default_factory=list)
barcodes: List[DetectedObjectIntelligence] = Field(default_factory=list)
documents: List[DetectedObjectIntelligence] = Field(default_factory=list)
screens: List[DetectedObjectIntelligence] = Field(default_factory=list)
phones: List[DetectedObjectIntelligence] = Field(default_factory=list)
laptops: List[DetectedObjectIntelligence] = Field(default_factory=list)
watches: List[DetectedObjectIntelligence] = Field(default_factory=list)
logos: List[DetectedObjectIntelligence] = Field(default_factory=list)
text_regions: List[DetectedObjectIntelligence] = Field(default_factory=list)
elapsed_ms: float = 0.0
class LocationEvidence(BaseModel):
"""One piece of evidence for a location estimate."""
source: str = "" # "gps" | "ocr" | "language" | "scene" | "license_plate" | "logo"
value: str = ""
confidence: float = 0.0
details: dict = Field(default_factory=dict)
class LocationEstimate(BaseModel):
"""Output of the location intelligence service."""
candidate_countries: List[dict] = Field(default_factory=list) # [{"country": "France", "confidence": 0.8}]
candidate_cities: List[dict] = Field(default_factory=list)
gps: Optional[dict] = None
evidence: List[LocationEvidence] = Field(default_factory=list)
conflicting_evidence: List[str] = Field(default_factory=list)
overall_confidence: float = 0.0
elapsed_ms: float = 0.0
class CorrelationNode(BaseModel):
"""A node in the correlation graph."""
id: str
node_type: str # "face" | "object" | "location" | "metadata" | "image" | "embedding"
label: str = ""
properties: dict = Field(default_factory=dict)
class CorrelationEdge(BaseModel):
"""An edge in the correlation graph — a deterministic relationship."""
source: str
target: str
edge_type: str # "same_face" | "same_object" | "same_location" | "same_camera" | "same_hash" | "same_embedding" | "same_metadata" | "same_timestamp"
confidence: float = 1.0
evidence: str = ""
class CorrelationGraph(BaseModel):
"""Output of the correlation engine."""
nodes: List[CorrelationNode] = Field(default_factory=list)
edges: List[CorrelationEdge] = Field(default_factory=list)
num_nodes: int = 0
num_edges: int = 0
elapsed_ms: float = 0.0
class ConflictReport(BaseModel):
"""Cross-provider disagreement."""
kind: str # e.g. "face_count_mismatch"
providers: List[str]
description: str
severity: str = "info" # info | warning | error
class ReportMetadata(BaseModel):
"""Job/report metadata."""
job_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
image_hash: Optional[str] = None
total_elapsed_ms: float = 0.0
providers_invoked: List[str] = Field(default_factory=list)
providers_succeeded: List[str] = Field(default_factory=list)
providers_failed: List[str] = Field(default_factory=list)
limitations: List[str] = Field(default_factory=list)
class UnifiedFaceReport(BaseModel):
"""The final unified report consumed by API + UI."""
metadata: ReportMetadata
detections: List[FaceDetection] = Field(default_factory=list)
matches: List[FaceMatch] = Field(default_factory=list)
scraped_images: List[dict] = Field(default_factory=list)
reverse_matches: List[dict] = Field(default_factory=list)
image_analyses: List[ImageAnalysisResult] = Field(default_factory=list)
metadata_extractions: List[MetadataResult] = Field(default_factory=list)
forensics: List[ForensicsResult] = Field(default_factory=list)
ocr_results: List[OCRResult] = Field(default_factory=list)
object_detections: List[ObjectDetectionResult] = Field(default_factory=list)
scene_results: List[SceneResult] = Field(default_factory=list)
nsfw_results: List[NSFWResult] = Field(default_factory=list)
ai_detection_results: List[AIDetectionResult] = Field(default_factory=list)
embedding_results: List[EmbeddingResult] = Field(default_factory=list)
# OSINT (Phase 10-15)
osint: Optional[OSINTResult] = None
face_intelligence: Optional[FaceIntelligenceResult] = None
forensic_metadata: Optional[ForensicMetadataReport] = None
object_intelligence: Optional[ObjectIntelligenceResult] = None
location_estimate: Optional[LocationEstimate] = None
correlation_graph: Optional[CorrelationGraph] = None
evidence: List[Evidence] = Field(default_factory=list)
conflicts: List[ConflictReport] = Field(default_factory=list)
overall_confidence: Optional[ConfidenceScore] = None
|