From 5a3118f5907f6777863d2216094b1ea4751c763b Mon Sep 17 00:00:00 2001 From: Frank Schwenk Date: Sat, 18 Jul 2026 17:11:28 +0200 Subject: [PATCH] refactor: share env-bool parsing and logging setup env_utils.env_bool replaces duplicated truthy parsing in config and rembg_cli. logging_config.configure_logging unifies entry-point setup. Co-authored-by: Cursor --- app/config.py | 6 +++++- app/env_utils.py | 12 ++++++++++++ app/logging_config.py | 11 +++++++++++ app/main.py | 15 ++++++++------- app/rembg_cli.py | 9 ++------- 5 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 app/env_utils.py create mode 100644 app/logging_config.py diff --git a/app/config.py b/app/config.py index 60596f3..1a0a0ad 100644 --- a/app/config.py +++ b/app/config.py @@ -9,6 +9,8 @@ from __future__ import annotations import os from pathlib import Path +from .env_utils import env_bool + def _int_env(name: str, default: int) -> int: try: @@ -55,13 +57,15 @@ 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) +# ImageMagick preprocess step timeout (resize + orient). +PREPROCESS_TIMEOUT = _int_env("PREPROCESS_TIMEOUT", 120) # 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"} +REMBG_ALPHA = env_bool("REMBG_ALPHA", True) NICE_LEVEL = _int_env("NICE_LEVEL", 18) # gmic CLI binary, override for local dev if not on PATH. rembg has no diff --git a/app/env_utils.py b/app/env_utils.py new file mode 100644 index 0000000..73d5311 --- /dev/null +++ b/app/env_utils.py @@ -0,0 +1,12 @@ +"""Shared environment-variable parsing.""" + +from __future__ import annotations + +import os + + +def env_bool(name: str, default: bool) -> bool: + raw = os.environ.get(name) + if raw is None: + return default + return raw.strip().lower() in {"1", "true", "yes", "on"} diff --git a/app/logging_config.py b/app/logging_config.py new file mode 100644 index 0000000..91d7c37 --- /dev/null +++ b/app/logging_config.py @@ -0,0 +1,11 @@ +"""Shared logging setup for entry-point modules.""" + +from __future__ import annotations + +import logging + +_LOG_FORMAT = "%(asctime)s %(levelname)s [%(name)s] %(message)s" + + +def configure_logging(level: int = logging.INFO) -> None: + logging.basicConfig(level=level, format=_LOG_FORMAT) diff --git a/app/main.py b/app/main.py index bfdf0dd..c20d1c0 100644 --- a/app/main.py +++ b/app/main.py @@ -14,8 +14,9 @@ from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from . import config, pipeline, remix +from .logging_config import configure_logging -logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s [%(name)s] %(message)s") +configure_logging() logger = logging.getLogger("livef12.web") app = FastAPI(title=config.SITE_TITLE) @@ -63,15 +64,15 @@ def _safe_job_file(job_id: str, filename: str) -> Path: def list_jobs() -> list[dict[str, Any]]: jobs = [] for job_id in pipeline.list_job_ids(): - status = pipeline.read_status(job_id) or {} - manifest = pipeline.read_manifest(job_id) or {} + data = pipeline.read_meta(job_id) or {} + variants = data.get("variants") or [] jobs.append( { "job_id": job_id, - "status": status.get("status", "unknown"), - "created_at": status.get("created_at") or manifest.get("created_at") or "", - "variant_count": len(manifest.get("variants", [])), - "thumbnail": (manifest.get("variants") or [{}])[-1].get("file") if manifest.get("variants") else None, + "status": data.get("status", "unknown"), + "created_at": data.get("created_at") or "", + "variant_count": len(variants), + "thumbnail": variants[-1].get("file") if variants else None, } ) jobs.sort(key=lambda j: j["created_at"] or j["job_id"], reverse=True) diff --git a/app/rembg_cli.py b/app/rembg_cli.py index cf98989..dae1763 100644 --- a/app/rembg_cli.py +++ b/app/rembg_cli.py @@ -18,12 +18,7 @@ import sys import traceback from pathlib import Path - -def _env_bool(name: str, default: bool) -> bool: - raw = os.environ.get(name) - if raw is None: - return default - return raw.strip().lower() in {"1", "true", "yes", "on"} +from .env_utils import env_bool def main() -> int: @@ -42,7 +37,7 @@ def main() -> int: output_path.parent.mkdir(parents=True, exist_ok=True) model = os.environ.get("REMBG_MODEL", "u2net") - alpha = _env_bool("REMBG_ALPHA", True) + alpha = env_bool("REMBG_ALPHA", True) session = new_session(model) output_path.write_bytes( remove(