d5b44b221e
Remove SFTPGo; mount event data from the Syncthing folder, watch incoming/, and name variants after the source stem. Co-authored-by: Cursor <cursoragent@cursor.com>
100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
"""Central configuration, loaded from environment variables.
|
|
|
|
Every setting has a sane default so the app runs locally without a `.env`
|
|
file, but production deploys should set these via `compose.yml` / `.env`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
def _int_env(name: str, default: int) -> int:
|
|
try:
|
|
return int(os.environ.get(name, str(default)))
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
def _float_env(name: str, default: float) -> float:
|
|
try:
|
|
return float(os.environ.get(name, str(default)))
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
# --- Paths -------------------------------------------------------------
|
|
DATA_DIR = Path(os.environ.get("DATA_DIR", "/data"))
|
|
INBOX_DIR = DATA_DIR / "incoming"
|
|
JOBS_DIR = DATA_DIR / "jobs"
|
|
ASSETS_DIR = DATA_DIR / "assets"
|
|
PROCESSED_FILE = DATA_DIR / "processed.json"
|
|
|
|
BACKGROUND_FILE = ASSETS_DIR / "background"
|
|
FOREGROUND_FILE = ASSETS_DIR / "foreground"
|
|
BLEND_MODES_FILE = ASSETS_DIR / "blend_modes"
|
|
FILTERS_JSON = ASSETS_DIR / "filters.json"
|
|
|
|
# --- Processing ----------------------------------------------------------
|
|
OUTPUT_COUNT = _int_env("OUTPUT_COUNT", 3)
|
|
# Fallback / remix default. Auto variants pick randomly in
|
|
# [BLEND_OPACITY_MIN, BLEND_OPACITY_MAX] instead.
|
|
BLEND_OPACITY = os.environ.get("BLEND_OPACITY", "30%")
|
|
BLEND_OPACITY_MIN = _int_env("BLEND_OPACITY_MIN", 10)
|
|
BLEND_OPACITY_MAX = _int_env("BLEND_OPACITY_MAX", 50)
|
|
FILTER_TIMEOUT = _int_env("FILTER_TIMEOUT", 120)
|
|
# Second-chance timeout for variants that hit FILTER_TIMEOUT during the
|
|
# normal pass — retried once at the end of the job (not during filter probes).
|
|
FILTER_TIMEOUT_LONG = _int_env("FILTER_TIMEOUT_LONG", 300)
|
|
MAX_FILTER_ATTEMPTS = _int_env("MAX_FILTER_ATTEMPTS", 8)
|
|
# Longest edge after preprocess (ImageMagick). Keeps rembg/gmic sane on
|
|
# large camera JPEGs.
|
|
MAX_EDGE_PX = _int_env("MAX_EDGE_PX", 2000)
|
|
# Generous on purpose: the very first rembg call also downloads the model,
|
|
# which can take a while depending on the link.
|
|
REMBG_TIMEOUT = _int_env("REMBG_TIMEOUT", 600)
|
|
# birefnet-general OOMs on the ~8GB event box; u2net + alpha matting fits
|
|
# and is the practical equivalent of `rembg i -a`.
|
|
REMBG_MODEL = os.environ.get("REMBG_MODEL", "u2net")
|
|
REMBG_ALPHA = os.environ.get("REMBG_ALPHA", "1").strip().lower() in {"1", "true", "yes", "on"}
|
|
NICE_LEVEL = _int_env("NICE_LEVEL", 18)
|
|
|
|
# gmic CLI binary, override for local dev if not on PATH. rembg has no
|
|
# equivalent here — it runs via `python -m app.rembg_cli` (see pipeline.py
|
|
# run_rembg / app/rembg_cli.py), not a standalone binary.
|
|
GMIC_BIN = os.environ.get("GMIC_BIN", "gmic")
|
|
# ImageMagick binary (`magick` on IM7, `convert` on IM6). Empty = auto-detect.
|
|
MAGICK_BIN = os.environ.get("MAGICK_BIN", "")
|
|
|
|
# Fixed post-processing chain applied to every composed variant, ported
|
|
# verbatim from make_random.py.
|
|
POST_FILTERS: tuple[str, ...] = (
|
|
"fx_equalize_local_histograms 75,2,4,100,8,1,0",
|
|
"fx_map_tones 0.5,0.7,0.1,30,0",
|
|
"fx_LCE 80,0.5,1,1,0,0",
|
|
)
|
|
|
|
# Opacity choices offered in the remix form (blend "amount" percentages).
|
|
OPACITY_CHOICES: tuple[str, ...] = (
|
|
"10%",
|
|
"20%",
|
|
"30%",
|
|
"40%",
|
|
"50%",
|
|
"60%",
|
|
"70%",
|
|
"80%",
|
|
"90%",
|
|
"100%",
|
|
)
|
|
|
|
SUPPORTED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp"}
|
|
|
|
# --- Inbox watcher ---------------------------------------------------------
|
|
POLL_INTERVAL_SECONDS = _float_env("POLL_INTERVAL_SECONDS", 5)
|
|
STABLE_WAIT_SECONDS = _float_env("STABLE_WAIT_SECONDS", 2)
|
|
|
|
# --- Web ---------------------------------------------------------------
|
|
SITE_TITLE = os.environ.get("SITE_TITLE", "live.f12.rocks")
|