| """ |
| Centralized configuration for Face Intel. |
| |
| All settings are environment-driven via pydantic-settings so the same |
| code runs in dev, test, and production without code changes. |
| |
| After the refactor, `settings` is still importable for backward |
| compatibility with provider modules that read tuning knobs, BUT every |
| stateful service (storage, cache, orchestrator, services) receives its |
| dependencies through constructor injection — never by importing this |
| module directly. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from pathlib import Path |
| from typing import List |
|
|
| from pydantic import Field |
| from pydantic_settings import BaseSettings, SettingsConfigDict |
|
|
|
|
| BASE_DIR = Path(__file__).resolve().parent.parent |
| DATA_DIR = BASE_DIR / "data" |
| MODELS_DIR = DATA_DIR / "models" |
| GALLERY_DIR = DATA_DIR / "gallery" |
| UPLOADS_DIR = DATA_DIR / "uploads" |
| JOBS_DIR = DATA_DIR / "jobs" |
| UI_DIR = BASE_DIR / "ui" / "static" |
|
|
| |
| for _d in (DATA_DIR, MODELS_DIR, GALLERY_DIR, UPLOADS_DIR, JOBS_DIR): |
| _d.mkdir(parents=True, exist_ok=True) |
|
|
|
|
| class Settings(BaseSettings): |
| """Environment-driven settings. All fields map to FI_* env vars.""" |
|
|
| model_config = SettingsConfigDict( |
| env_file=".env", |
| env_prefix="FI_", |
| case_sensitive=False, |
| extra="ignore", |
| ) |
|
|
| |
| |
| |
| app_name: str = "Face Intel" |
| app_version: str = "1.0.0" |
| environment: str = "development" |
| host: str = "0.0.0.0" |
| port: int = 8000 |
| debug: bool = False |
|
|
| |
| |
| |
| |
| enable_haar: bool = True |
| enable_dnn: bool = False |
| |
| enable_insightface: bool = False |
| |
| enable_serpapi: bool = False |
| enable_social_lookup: bool = True |
| |
| enable_image_quality: bool = True |
| enable_image_properties: bool = True |
| |
| enable_exif: bool = True |
| |
| enable_image_integrity: bool = True |
| enable_duplicate_detector: bool = True |
| enable_ela: bool = True |
| enable_image_similarity: bool = True |
| |
| enable_ocr: bool = False |
| |
| enable_yolov8: bool = False |
| |
| enable_qr_code: bool = True |
| enable_barcode: bool = True |
| |
| enable_places365: bool = False |
| |
| enable_nudenet: bool = False |
| |
| enable_ai_image_detector: bool = False |
| |
| enable_mobilenet_embed: bool = False |
|
|
| |
| |
| |
| enable_face_index: bool = True |
| face_index_path: str = str(DATA_DIR / "face_index.db") |
| face_index_top_k: int = 10 |
| face_index_threshold: float = 0.5 |
| face_index_max_faces: int = 100_000 |
| face_index_crawler_user_agent: str = "FaceIntel/1.0" |
| face_index_crawler_seed_wikipedia: bool = False |
| face_index_crawler_seed_imdb: bool = False |
|
|
| |
| |
| |
| dnn_confidence_threshold: float = 0.7 |
| haar_scale_factor: float = 1.1 |
| haar_min_neighbors: int = 5 |
|
|
| |
| |
| |
| insightface_model_pack: str = "buffalo_s" |
| recognition_match_threshold: float = 0.5 |
|
|
| |
| |
| |
| scrape_timeout: int = 30 |
| scrape_max_images: int = 50 |
| user_agent: str = ( |
| "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " |
| "(KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" |
| ) |
|
|
| |
| |
| |
| reverse_search_max_results: int = 20 |
| serpapi_key: str = "" |
|
|
| |
| |
| |
| orchestrator_timeout_seconds: float = 90.0 |
| orchestrator_max_concurrency: int = 8 |
| retry_max_attempts: int = 3 |
| retry_initial_backoff_seconds: float = 0.5 |
| retry_max_backoff_seconds: float = 8.0 |
|
|
| |
| |
| |
| cache_enabled: bool = True |
| cache_ttl_seconds: int = 3600 |
| cache_max_entries: int = 1000 |
|
|
| |
| |
| |
| health_check_interval_seconds: int = 60 |
| circuit_breaker_failure_threshold: int = 5 |
| circuit_breaker_recovery_seconds: int = 120 |
|
|
| |
| |
| |
| db_path: str = str(DATA_DIR / "face_intel.db") |
| audit_log_path: str = str(DATA_DIR / "audit.log") |
| job_retention_days: int = 7 |
|
|
| |
| |
| |
| rate_limit_per_minute: int = 30 |
| cors_origins: List[str] = Field(default_factory=lambda: ["*"]) |
| require_consent_header: bool = True |
| consent_header_name: str = "X-Consent-Statement" |
| max_image_bytes: int = 20 * 1024 * 1024 |
| job_timeout_seconds: float = 300.0 |
| max_request_body_bytes: int = 25 * 1024 * 1024 |
|
|
| |
| |
| |
| models_dir: str = str(MODELS_DIR) |
| models_auto_download: bool = True |
| onnx_intra_op_threads: int = 2 |
|
|
| |
| |
| |
| log_level: str = "INFO" |
| log_json: bool = False |
|
|
|
|
| def make_settings(**overrides) -> Settings: |
| """Factory used by the DI container to build a Settings instance. |
| |
| Tests can override individual fields without touching env vars: |
| make_settings(environment="test", cache_enabled=False) |
| """ |
| if overrides: |
| |
| base = Settings() |
| data = base.model_dump() |
| data.update(overrides) |
| return Settings(**data) |
| return Settings() |
|
|
|
|
| |
| |
| settings = Settings() |
|
|