""" Configuration centralisée — chargée depuis .env """ from pathlib import Path from typing import List from pydantic_settings import BaseSettings from pydantic import field_validator import json class Settings(BaseSettings): # Application APP_NAME: str = "Imago" APP_VERSION: str = "1.0.0" DEBUG: bool = False SECRET_KEY: str = "changez-moi" # Serveur HOST: str = "0.0.0.0" PORT: int = 8000 # Base de données DATABASE_URL: str = "sqlite+aiosqlite:///./data/imago.db" # Stockage UPLOAD_DIR: str = "./data/uploads" THUMBNAILS_DIR: str = "./data/thumbnails" MAX_UPLOAD_SIZE_MB: int = 50 # AI — Configuration AI_ENABLED: bool = True AI_PROVIDER: str = "openrouter" # AI — Google Gemini GEMINI_API_KEY: str = "" GEMINI_MODEL: str = "gemini-3.1-pro-preview" GEMINI_MAX_TOKENS: int = 1024 # AI — OpenRouter OPENROUTER_API_KEY: str = "" OPENROUTER_MODEL: str = "qwen/qwen2.5-vl-72b-instruct" # AI — Comportement AI_TAGS_MIN: int = 5 AI_TAGS_MAX: int = 10 AI_DESCRIPTION_LANGUAGE: str = "français" AI_CACHE_DAYS: int = 30 # OCR OCR_ENABLED: bool = True TESSERACT_CMD: str = "/usr/bin/tesseract" OCR_LANGUAGES: str = "fra+eng" # CORS CORS_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:5173"] # Authentification ADMIN_API_KEY: str = "" JWT_SECRET_KEY: str = "changez-moi-jwt-secret" JWT_ALGORITHM: str = "HS256" # Rate limiting — global (legacy) RATE_LIMIT_UPLOAD: int = 10 RATE_LIMIT_AI: int = 20 # Rate limiting — par plan (requêtes/heure) RATE_LIMIT_FREE_UPLOAD: int = 20 RATE_LIMIT_FREE_AI: int = 50 RATE_LIMIT_STANDARD_UPLOAD: int = 100 RATE_LIMIT_STANDARD_AI: int = 200 RATE_LIMIT_PREMIUM_UPLOAD: int = 500 RATE_LIMIT_PREMIUM_AI: int = 1000 # Redis + ARQ Worker REDIS_URL: str = "redis://localhost:6379" WORKER_MAX_JOBS: int = 10 WORKER_JOB_TIMEOUT: int = 180 WORKER_MAX_TRIES: int = 3 AI_STEP_TIMEOUT: int = 120 OCR_STEP_TIMEOUT: int = 30 # Storage Backend STORAGE_BACKEND: str = "local" # "local" | "s3" S3_BUCKET: str = "" S3_REGION: str = "us-east-1" S3_ENDPOINT_URL: str = "" # vide = AWS, sinon MinIO/R2 S3_ACCESS_KEY: str = "" S3_SECRET_KEY: str = "" S3_PREFIX: str = "imago" SIGNED_URL_SECRET: str = "changez-moi-signed-url" @field_validator("CORS_ORIGINS", mode="before") @classmethod def parse_cors(cls, v): if isinstance(v, str): try: return json.loads(v) except Exception: return [v] return v @property def upload_path(self) -> Path: p = Path(self.UPLOAD_DIR) p.mkdir(parents=True, exist_ok=True) return p @property def thumbnails_path(self) -> Path: p = Path(self.THUMBNAILS_DIR) p.mkdir(parents=True, exist_ok=True) return p @property def max_upload_bytes(self) -> int: return self.MAX_UPLOAD_SIZE_MB * 1024 * 1024 model_config = {"env_file": ".env", "case_sensitive": True, "extra": "ignore"} settings = Settings()