Files
Imago/app/config.py
T
bruno 2f2a5e9b4a
CI / Lint & Format (push) Failing after 28s
CI / Tests (push) Has been skipped
CI / Security Scan (push) Failing after 8s
CI / Docker Build (push) Has been skipped
Add admin panel, WebSocket support, and API versioning
Introduce an admin portal (React + Nginx), WebSocket routing, and
API versioning middleware with `/api/v1/` prefix deprecation.
Add master API key authentication, new Prometheus metrics for AI
token consumption and active WebSockets, and extend S3 config
with a public endpoint URL. Update test paths and fixtures to
align with the new routing structure.
2026-06-22 11:25:22 -04:00

124 lines
3.3 KiB
Python

"""
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"
API_V1_SUNSET_DATE: str = ""
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_ENDPOINT_PUBLIC: str = "" # URL utilisée pour les liens présignés (ex: http://localhost:9000)
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()