card-grader/docker-compose.yml
Barely Removable 034761e145 Add OpenAI (GPT-5.6 Sol) as a second vision provider; gate server settings to a named admin
vision.py now dispatches per-model to _call_anthropic or _call_openai --
same prompt, same schema, same cardimage.py measurements either way, only
the request/response shape differs. Confirmed the existing GRADING_SCHEMA
already satisfies OpenAI's strict-mode requirement (every property listed
in required, additionalProperties:false at every level) with no changes.

Settings gained a second axis: which server key applies now depends on the
selected model's provider, and friends' personal keys are stored per
provider (with a one-time migration from the old single-key localStorage
slot) since a Claude key and an OpenAI key aren't interchangeable.

CARD_GRADER_ADMIN_USER names one username (read from the proxy's forwarded
basic-auth header) who alone may write server settings; everyone else keeps
the same read-only view CARD_GRADER_LOCK used to give everyone, while still
being able to set their own personal key. Deployed here as ninja_hippo.
CARD_GRADER_LOCK remains the fallback when no admin is named.
2026-08-23 07:39:03 -07:00

52 lines
2.5 KiB
YAML

services:
card-grader:
build: .
container_name: card-grader
restart: unless-stopped
# Proper PID-1 signal handling — a clean, immediate stop on
# `docker compose down` instead of the 10s SIGKILL timeout.
init: true
# Without a cap, an always-on container's json log grows unbounded on
# the array — this is a server that never reboots, so it would.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# Bound to all interfaces (not 127.0.0.1) because Nginx Proxy Manager
# runs in its own container on a separate macvlan IP (192.168.86.2),
# not in this host's network namespace — it has to reach this over the
# LAN at 192.168.86.33:8778, same as every other *arr-style service
# already proxied through this box. That also means anything else on
# the LAN can hit :8778 directly, bypassing the basic-auth NPM adds in
# front of hippofam.com/cards — consistent with how the rest of this
# box's services already work (LAN is the trust boundary here), but
# worth knowing.
ports:
- "8778:8778"
volumes:
- ./data:/data
environment:
# Only this ONE username (from NPM's basic auth, forwarded upstream)
# may write server settings — model choice, both provider API keys.
# Everyone else gets the same read-only view CARD_GRADER_LOCK used to
# give everyone; they can still set their OWN personal key, which
# never touches server settings at all. Set with the app's Settings
# screen unlocked for ninja_hippo only, so paste keys in there, not
# here.
- CARD_GRADER_ADMIN_USER=ninja_hippo
# CARD_GRADER_LOCK is now redundant with CARD_GRADER_ADMIN_USER set
# (the admin check takes priority) — kept only as the fallback for
# anyone who unsets the admin var and wants the old all-or-nothing
# behaviour back.
- CARD_GRADER_LOCK=1
# This app is reverse-proxied at hippofam.com/cards, not the domain
# root — see app.py's BASE_PATH handling.
- CARD_GRADER_BASE_PATH=/cards
# How long a grade keeps the original photo(s) that produced it, so
# Regrade can re-run without asking for them again. Grades, their
# thumbnails and every measurement are kept FOREVER regardless — only
# the photos expire, since they're what makes the database grow (up
# to ~16MB per grade at the upload cap). Past the window, Regrade
# falls back to asking for the photo. 0 disables pruning.
- CARD_GRADER_IMAGE_RETENTION_DAYS=7