feat(model-manager): generated-photo Gallery + device-routing landing
- Gallery view: grid of generated photos from ComfyUI's output/, full-size
lightbox, and permanent delete (with confirm). Paginated ("Load more").
- Backend: GET /api/gallery, GET /gallery/file (path-guarded image serve),
DELETE /api/gallery (path-guarded; clear error on permission denial).
- Mount ./output read-write into model-manager so the gallery can delete.
- Device-routing landing at /start: phones -> ComfyUIMini, desktops ->
the Gallery; ?force=mobile|desktop overrides. Ports come from the new
/api/ui-config (COMFYUI_PORT / COMFYUIMINI_PORT env).
- Responsive tweaks so the gallery is usable if opened directly on a phone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,18 @@ MODELS_DIR = Path(os.environ.get("MODELS_DIR", "/models")).resolve()
|
||||
# Persistent data dir for the SQLite database.
|
||||
DATA_DIR = Path(os.environ.get("DATA_DIR", "/data")).resolve()
|
||||
|
||||
# Generated images directory (ComfyUI output), mounted read-write for the gallery.
|
||||
OUTPUT_DIR = Path(os.environ.get("OUTPUT_DIR", "/output")).resolve()
|
||||
|
||||
DB_PATH = DATA_DIR / "manager.db"
|
||||
|
||||
# Ports of the sibling services, used by the device-routing landing page.
|
||||
COMFYUI_PORT = os.environ.get("COMFYUI_PORT", "8188")
|
||||
COMFYUIMINI_PORT = os.environ.get("COMFYUIMINI_PORT", "3000")
|
||||
|
||||
# Image file types shown in the gallery.
|
||||
IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp"}
|
||||
|
||||
# StabilityMatrix-style model types mapped to ComfyUI's standard `models/` subfolders.
|
||||
# `key` is the stable id used by the API/UI; `folder` is the on-disk subdirectory.
|
||||
MODEL_TYPES: list[dict[str, str]] = [
|
||||
@@ -51,3 +61,16 @@ def ensure_dirs() -> None:
|
||||
MODELS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
for t in MODEL_TYPES:
|
||||
(MODELS_DIR / t["folder"]).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def safe_output_path(rel_path: str) -> Path:
|
||||
"""Resolve a gallery-relative path to an absolute one under OUTPUT_DIR.
|
||||
|
||||
Raises ValueError on any attempt to escape the output directory.
|
||||
"""
|
||||
# Normalize and strip leading separators so it's treated as relative.
|
||||
rel = rel_path.replace("\\", "/").lstrip("/")
|
||||
target = (OUTPUT_DIR / rel).resolve()
|
||||
if target != OUTPUT_DIR and not str(target).startswith(str(OUTPUT_DIR) + os.sep):
|
||||
raise ValueError("Path is outside the output directory")
|
||||
return target
|
||||
|
||||
Reference in New Issue
Block a user