A SQLite-backed API for creating six styled book-cover previews and one selected final cover.
SERVICE_URL=https://pin-log.com/image
The unauthenticated readiness endpoint is GET /health and returns
{"status":"ok"} with HTTP 200.
python -m venv .venv
. .venv/bin/activate
pip install -r requirements-dev.txt
uvicorn app.main:app --reloadConfiguration:
DATABASE_PATHdefaults todata/app.db.FILES_DIRdefaults todata/files.STALE_JOB_SECONDSdefaults to1800. A running job older than this is requeued when attempts remain, or marked failed afterMAX_ATTEMPTSclaims.PUBLIC_BASE_PATHdefaults to empty. Set it to the externally mounted service prefix (for example,/image) so returned file URLs use/image/files/NAME; the application's internal static route remains/files/NAME.WORKER_TOKEN, when set, protects every/jobsendpoint withAuthorization: Bearer TOKEN.
Create all six previews:
curl -X POST "$SERVICE_URL/api/covers" \
-H 'content-type: application/json' \
-d '{"title":"달빛 고양이","keywords":["숲","달빛"]}'The response is {"request_id":"...","candidates":[{"style_id":"watercolour","label":"수채화"}, ...]}.
Poll request state:
curl "$SERVICE_URL/api/covers/REQUEST_ID"A worker claims work (the default long poll is 25 seconds):
curl "$SERVICE_URL/jobs/claim?worker_id=gpu-1" \
-H "Authorization: Bearer $WORKER_TOKEN"The claim response contains exactly id, workflow, and inputs. Upload one or more generated images with a JSON-string meta field; image_0 is required:
curl -X POST "$SERVICE_URL/jobs/JOB_ID/result" \
-H "Authorization: Bearer $WORKER_TOKEN" \
-F 'meta={"renderer":"comfyui"}' \
-F image_0=@preview.webp \
-F image_1=@alternate.webpReport a permanent or retryable failure:
curl -X POST "$SERVICE_URL/jobs/JOB_ID/fail" \
-H "Authorization: Bearer $WORKER_TOKEN" \
-H 'content-type: application/json' \
-d '{"error":"GPU unavailable","retryable":true}'Select a style to enqueue the full-size final job:
curl -X POST "$SERVICE_URL/api/covers/REQUEST_ID/select" \
-H 'content-type: application/json' \
-d '{"style_id":"watercolour"}'Previews request 512×768 WebP at quality 82. Final jobs request 1795×2657 WebP at quality 92. Both use generation dimensions 1024×1536 and four steps.
pytest -q
python -m compileall -q app testsThe container runs as the fixed non-root identity 1000:1000. Its persistent
/data directory is owned by that identity, so any mounted volume must also be
writable by UID/GID 1000.
GitHub Actions runs the test suite and Python bytecode compilation for pull
requests and pushes to main. A push to main also publishes the image as
ghcr.io/team-pinlog/image:sha-COMMIT_SHA and reports its registry digest. No
mutable latest tag is produced.