cfe5d36c70
- app/ai_edit.py: OpenRouter chat/completions (image in/out), Presets + Prompt, Retry - bot: AI-Preset-Buttons + Bildunterschrift = freier AI-Prompt; _process refaktoriert - Freistellen/Upscaling bleiben lokal (originaltreu); AI-Edit fuer generative Edits - httpx pin, config OPENROUTER_* Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNQ8ghPfzAfsyVYd6HgFb6
92 lines
3.9 KiB
Python
92 lines
3.9 KiB
Python
"""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)
|