"""Zentrale Konfiguration aus Umgebungsvariablen.""" from __future__ import annotations import os from pathlib import Path def _get_bool(name: str, default: bool = False) -> bool: val = os.getenv(name) if val is None: return default return val.strip().lower() in {"1", "true", "yes", "on", "ja"} def _get_int(name: str, default: int) -> int: try: return int(os.getenv(name, str(default))) except (TypeError, ValueError): return default # --- Telegram --------------------------------------------------------------- BOT_TOKEN: str = os.getenv("BOT_TOKEN", "").strip() # Kommagetrennte Liste erlaubter Telegram-User-IDs. Leer = jeder darf (nur # fuer Tests empfohlen). /start zeigt jedem seine ID, damit man hier eintraegt. _allowed = os.getenv("ALLOWED_USER_IDS", "").replace(";", ",") ALLOWED_USER_IDS: set[int] = { int(x) for x in (p.strip() for p in _allowed.split(",")) if x.strip().isdigit() } # --- Bild-Pipeline ---------------------------------------------------------- MODELS_DIR: Path = Path(os.getenv("MODELS_DIR", "/app/models")) WORK_DIR: Path = Path(os.getenv("WORK_DIR", "/tmp/klarbild")) # rembg-Modell fuers Freistellen: isnet-general-use (gut), u2net, u2netp (leicht), # birefnet-general (beste Qualitaet, schwer). Wird beim Build vorgeladen. REMBG_MODEL: str = os.getenv("REMBG_MODEL", "isnet-general-use") # OpenCV dnn_superres: "fsrcnn" (schnell, Default) oder "edsr" (mehr Detail, # aber auf CPU sehr langsam ~40s/Kachel -> nur fuer starke Boxen empfohlen). UPSCALE_MODEL: str = os.getenv("UPSCALE_MODEL", "fsrcnn").lower() # Optionales Real-ESRGAN-ONNX-Backend (fuer GPU/starke Boxen). Wenn aktiv und # Modelldatei vorhanden, wird es statt OpenCV genutzt. ENABLE_REALESRGAN: bool = _get_bool("ENABLE_REALESRGAN", False) REALESRGAN_ONNX: Path = Path( os.getenv("REALESRGAN_ONNX", str(MODELS_DIR / "realesrgan_x4.onnx")) ) # Speicherschutz auf kleinen Boxen (CX33: 8GB, keine GPU): # Laengste Kante des Eingangsbildes vor dem Upscalen begrenzen. MAX_INPUT_EDGE: int = _get_int("MAX_INPUT_EDGE", 1600) # Kachelgroesse fuer das Upscalen (kleiner = weniger RAM, mehr Overhead). TILE_SIZE: int = _get_int("TILE_SIZE", 256) # Deckel fuer die Ausgabe-Megapixel (Sicherheitsnetz gegen OOM). MAX_OUTPUT_MP: float = float(os.getenv("MAX_OUTPUT_MP", "80")) # Nach dem Upscalen leichte Entrauschung + Schaerfung ("Klarbild"-Finish). POST_DENOISE: bool = _get_bool("POST_DENOISE", True) POST_SHARPEN: bool = _get_bool("POST_SHARPEN", True) # JPEG-Qualitaet fuer zurueckgesendete Fotos (Freistellen liefert immer PNG). JPEG_QUALITY: int = _get_int("JPEG_QUALITY", 95) # --- OpenRouter (generative AI-Edits: Hintergrund, Retusche, freier Prompt) -- # Achtung: US-gehostet (Google/OpenAI via OpenRouter). Bewusst gesetzt. OPENROUTER_API_KEY: str = os.getenv("OPENROUTER_API_KEY", "").strip() OPENROUTER_BASE: str = os.getenv("OPENROUTER_BASE", "https://openrouter.ai/api/v1") OPENROUTER_MODEL: str = os.getenv("OPENROUTER_MODEL", "google/gemini-3.1-flash-image") OPENROUTER_TIMEOUT: int = _get_int("OPENROUTER_TIMEOUT", 120) # Laengste Kante, auf die Eingangsbilder vor dem Senden verkleinert werden # (Kosten/Tempo). Das Modell gibt ohnehin ~1024px-Ausgaben zurueck. AI_EDIT_MAX_EDGE: int = _get_int("AI_EDIT_MAX_EDGE", 1536) AI_EDIT_ENABLED: bool = bool(OPENROUTER_API_KEY) # --- Health-Server ---------------------------------------------------------- HEALTH_PORT: int = _get_int("PORT", 8080) # --- Picdrop (SFTP) --------------------------------------------------------- PICDROP_HOST: str = os.getenv("PICDROP_HOST", "ftps.picdrop.com") PICDROP_PORT: int = _get_int("PICDROP_PORT", 22) PICDROP_USER: str = os.getenv("PICDROP_USER", "") PICDROP_PASSWORD: str = os.getenv("PICDROP_PASSWORD", "") PICDROP_ENABLED: bool = bool(PICDROP_USER and PICDROP_PASSWORD) def validate() -> None: if not BOT_TOKEN: raise SystemExit("FEHLER: Umgebungsvariable BOT_TOKEN ist nicht gesetzt.") WORK_DIR.mkdir(parents=True, exist_ok=True)