Spaces:
Sleeping
Sleeping
| """Application configuration for imageO_v3.""" | |
| from __future__ import annotations | |
| import os | |
| from typing import Optional | |
| from pydantic import Field | |
| from pydantic_settings import BaseSettings, SettingsConfigDict | |
| # Cache defaults are set only when they are not already configured. | |
| os.environ.setdefault("XDG_CACHE_HOME", "/app/.cache") | |
| os.environ.setdefault("HF_HOME", "/app/.cache/huggingface") | |
| os.environ.setdefault("NUMBA_DISABLE_CACHE", "1") | |
| class Settings(BaseSettings): | |
| """Typed settings loaded from environment variables.""" | |
| model_config = SettingsConfigDict( | |
| env_file=".env", | |
| env_file_encoding="utf-8", | |
| extra="ignore", | |
| ) | |
| app_env: str = Field(default="development", description="Runtime environment") | |
| log_level: str = Field(default="INFO", description="Logger minimum level") | |
| model_version: str = Field(default="v3.2.0", description="Service model version") | |
| redis_url: str = Field(default="", description="Redis connection URL") | |
| hf_token: str = Field(default="", description="Hugging Face token for gated model access") | |
| replay_attack_ttl_s: int = Field(default=60, description="HMAC timestamp TTL") | |
| prediction_cache_ttl_s: int = Field(default=300, description="Prediction cache TTL") | |
| max_image_size_mb: int = Field(default=3, description="Maximum upload size in MB") | |
| model_checkpoint_path: str = Field( | |
| default="", | |
| alias="MODEL_CHECKPOINT_PATH", | |
| description="Local path to ABMIL .pt when ABMIL_HF_REPO_ID is unset; ignored when Hub repo id is set", | |
| ) | |
| abmil_hf_repo_id: Optional[str] = Field( | |
| default="iamSubha16/milk_adulteration_abmil_prod", | |
| description="Hugging Face Hub repo id (e.g. org/private-repo). If set, ABMIL checkpoint is fetched via hf_hub_download.", | |
| ) | |
| abmil_hf_filename: str = Field( | |
| default="production_model_v3.pt", | |
| description=( | |
| "Checkpoint filename inside the Hub repo. This code targets the scale-aware hybrid-LSE " | |
| "ABMIL, so point this at the RETRAINED checkpoint; the old plain-attention _v2 file will " | |
| "not load under strict=True. Override via ABMIL_HF_FILENAME." | |
| ), | |
| ) | |
| abmil_hf_revision: Optional[str] = Field( | |
| default="main", | |
| description="Optional Hub revision: branch, tag, or commit SHA (pin in production)", | |
| ) | |
| abmil_hf_subfolder: Optional[str] = Field( | |
| default="", | |
| description="Optional folder inside the repo containing ABMIL_HF_FILENAME", | |
| ) | |
| abmil_hf_local_files_only: bool = Field( | |
| default=False, | |
| description="If true, Hub resolution uses only local HF cache (no network)", | |
| ) | |
| dinov3_model_id: str = Field( | |
| default="facebook/dinov3-vits16plus-pretrain-lvd1689m", | |
| description="Hugging Face model id for DINOv3 backbone", | |
| ) | |
| embedding_batch_size: int = Field( | |
| default=256, | |
| description="Batch size for tile embedding" | |
| ) | |
| embedding_device: Optional[str] = Field( | |
| default="cpu", | |
| description="Optional device override (cpu/cuda)", | |
| ) | |
| embedding_dtype: Optional[str] = Field( | |
| default="float32", | |
| description="Optional dtype for DINO model loading (auto/float16/float32/bfloat16)", | |
| ) | |
| dinov3_local_files_only: bool = Field( | |
| default=False, | |
| description="If true, do not fetch model files from Hugging Face", | |
| ) | |
| # --- Tiling / preprocessing (multi-scale; must match training extraction config) --- | |
| tile_sizes_raw: str = Field( | |
| default="", | |
| alias="TILE_SIZES", | |
| description="Comma-separated or JSON tile sizes, e.g. '128,64'. Empty falls back to TILE_SIZE, then [128, 64].", | |
| ) | |
| tile_size_legacy: str = Field( | |
| default="", | |
| alias="TILE_SIZE", | |
| description="Legacy single tile size; used only when TILE_SIZES is unset.", | |
| ) | |
| tile_overlap_ratio: float = Field(default=0.25, description="Preprocessing tile overlap ratio") | |
| tile_shrink_factor: float = Field(default=0.85, description="ROI shrink factor") | |
| tile_min_mask_coverage: float = Field( | |
| default=0.8, | |
| ge=0.0, | |
| le=1.0, | |
| description="Minimum fraction of tile pixels inside ROI mask to accept the tile", | |
| ) | |
| # ROI Hough-circle detection knobs (defaults match milk_adulteration_mil ROIConfig). | |
| roi_dp: float = Field(default=1.2, description="HoughCircles inverse accumulator resolution") | |
| roi_param1: float = Field(default=60.0, description="HoughCircles Canny high threshold") | |
| roi_param2: float = Field(default=35.0, description="HoughCircles accumulator threshold") | |
| roi_min_radius_frac: float = Field(default=0.25, description="Min circle radius as fraction of min(h, w)") | |
| roi_max_radius_frac: float = Field(default=0.75, description="Max circle radius as fraction of min(h, w)") | |
| roi_median_blur_ksize: int = Field(default=7, description="Median blur kernel size before Hough transform") | |
| roi_fallback_margin_frac: float = Field( | |
| default=0.10, | |
| description="Center-crop margin fraction used when no circle is detected", | |
| ) | |
| # Optional tile-quality gates (DISABLED by default to match current training extraction). | |
| tile_variance_gate_enabled: bool = Field( | |
| default=False, | |
| description="If true, reject tiles whose grayscale variance < tile_min_variance", | |
| ) | |
| tile_min_variance: float = Field(default=50.0, description="Min grayscale variance when variance gate enabled") | |
| tile_highlight_gate_enabled: bool = Field( | |
| default=False, | |
| description="If true, reject tiles whose specular-highlight fraction > tile_max_highlight_frac", | |
| ) | |
| tile_highlight_thresh: int = Field(default=235, description="Grayscale value above which a pixel is a highlight") | |
| tile_max_highlight_frac: float = Field( | |
| default=0.40, | |
| description="Max fraction of highlight pixels when highlight gate enabled", | |
| ) | |
| abmil_attn_dim: int = Field(default=256, description="Fallback ABMIL attention dimension") | |
| abmil_classifier_hidden: int = Field( | |
| default=256, | |
| description="Fallback ABMIL classifier hidden size", | |
| ) | |
| abmil_attn_hidden: int = Field(default=128, description="Fallback gated attention hidden size") | |
| abmil_dropout: float = Field(default=0.40, description="Fallback ABMIL dropout") | |
| abmil_threshold: float = Field(default=0.35, description="Fallback positive class threshold") | |
| abmil_scale_embed_dim: int = Field( | |
| default=16, | |
| description="Scale-embedding dim for MultiScaleEmbeddingProjector (0 disables); inferred from checkpoint when possible", | |
| ) | |
| abmil_num_scales: int = Field( | |
| default=3, | |
| description="Number of tile-scale buckets in the scale-embedding table; inferred from checkpoint when possible", | |
| ) | |
| abmil_lse_r: float = Field( | |
| default=5.0, | |
| description="LSE pooling sharpness r; not stored in the checkpoint, so must match the training default", | |
| ) | |
| def tile_sizes(self) -> list[int]: | |
| """Resolved multi-scale tile sizes (TILE_SIZES wins, then legacy TILE_SIZE, then [128, 64]).""" | |
| raw = (self.tile_sizes_raw or "").strip() | |
| if raw: | |
| if raw.startswith("["): | |
| import json | |
| return [int(x) for x in json.loads(raw)] | |
| return [int(x.strip()) for x in raw.split(",") if x.strip()] | |
| legacy = (self.tile_size_legacy or "").strip() | |
| if legacy: | |
| return [int(legacy)] | |
| return [128, 64] | |
| settings = Settings() | |