Files
livef12rocks/README.md
T
Frank Schwenk d5b44b221e feat: replace SFTP drop with Syncthing share path
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>
2026-07-18 14:06:57 +02:00

82 lines
3.7 KiB
Markdown

# live.f12.rocks
Event photo pep pipeline: guests drop a photo into a Syncthing folder, a
worker runs it through `rembg` (background removal) + `gmic` (random
filter/blend compositing, ported from `make_random.py`), and a small web
UI shows the results with a "remix" option to try different filters on
the same photo. Finished jobs sync back via the same share.
No web auth. This is an event tool, not a DAM.
## Services (`compose.yml`)
| Service | What | Port |
|----------|--------------------------------------------------|--------------------------|
| `worker` | Watches `incoming/`, runs the compose pipeline | none published |
| `web` | FastAPI + Jinja UI, browse jobs, remix | via Traefik only |
Both share one host directory (`DATA_HOST_DIR`) mounted at `/data`.
Syncthing runs on the host — not in this compose.
## Data layout (Syncthing share)
Prod path: `/home/frank/sync.schwenk.online/data/livef12`
```
incoming/ # phone drop — worker only ever reads/copies from here
jobs/<job_id>/
original.<ext> # private copy of the uploaded photo
rembg.png # background removed (computed once, reused)
intermediates/ # every intermediate step, kept for inspection
variants/ # final composed images ({stem}_v1.png, …)
manifest.json # filter names/commands/blends per variant
status.json # pending | processing | done | error
processed.json # worker bookkeeping: which incoming files were handled
```
`assets/` (filter lists + trimmed `filters.json`) lives in the repo and is
bind-mounted read-only into `worker`/`web` at `/data/assets`.
## Running it
```bash
cp .env.example .env
# local: set DATA_HOST_DIR=./data
# prod: leave unset (defaults to the Syncthing share path)
docker compose up -d --build
```
Drop a photo into `incoming/` (via Syncthing or locally). After a few
seconds (poll interval + processing time) it shows up on the web UI as a
new job; the full `jobs/<id>/` tree syncs back to the phone.
## Configuration (`.env`, see `.env.example`)
| Var | Default | Notes |
|-----|---------|-------|
| `DATA_HOST_DIR` | `/home/frank/sync.schwenk.online/data/livef12` | Syncthing share root; use `./data` locally |
| `OUTPUT_COUNT` | `3` | Variants generated per uploaded photo |
| `BLEND_OPACITY` | `30%` | Default blend opacity for auto-generated variants |
| `FILTER_TIMEOUT` | `120` | Seconds before a single gmic call is killed |
| `MAX_FILTER_ATTEMPTS` | `8` | Random-filter retry budget per bg/fg pick |
| `NICE_LEVEL` | `18` | `nice -n` level for gmic/rembg subprocesses |
## Deploy notes / caveats
- **Firewall:** Traefik must already route `live.f12.rocks` — this repo
only adds the router labels; it assumes the external `traefik` docker
network exists. No SFTP port needed.
- **rembg model download:** first background-removal call downloads the
`u2net` ONNX model (~176 MB) from GitHub. This needs outbound internet
on first run and can take a minute or two depending on the link; the
model is cached in the `rembg_cache` named volume afterwards, so
restarts don't re-download it.
- **Incoming is append-only:** the worker only ever copies out of
`incoming/` and never deletes or moves anything there — plan disk space
accordingly, or clean up `incoming/` manually between events.
- **Sequential processing:** the worker handles one photo at a time
(`cpus: "1.0"`, no concurrency) — fine for an event pace, but a burst of
uploads will just queue up and get processed in order.
- Deploy itself (`docker compose up -d` on the server) is on you — this
repo doesn't run it automatically.