Enhance on demand (#192): run a ComfyUI restore/edit template on a photo from the apps, preview it through ImageApi, approve it in-app, and it lands as a photo version (#191).
enhance.toml (annotated enhance.example.toml, gitignored, no secrets): templates, path map, timings. A template missing imageapi:source / imageapi:save, or with a prompt node lacking text|prompt|value, is logged and skipped; the rest load. Stray SaveImage nodes are a startup warning.
Template fill: nodes found by _meta.title; require_approval forced; prompt append (per-template prompt_join, default one space) or replace (required, empty is a 400); reference node and every link to it removed when no reference_path; fresh value for every seed, noise_seed and *.seed input per submit.
Path map /media/nas/ <-> Z:\ (longest prefix, both directions).
enhance_jobs table plus a background poller (/queue then /history/{id}): queued, running, ready, failed, and expired when ComfyUI forgot the prompt (restart). unavailable after unreachable_grace_secs.
Idle POST /free once per quiet spell (empty queue, no active job, newest /history unchanged for idle_free_secs; measured on ImageApi's clock).
Approve calls /imageapi/approve, maps the returned path, runs a targeted ingest (watcher::register_new_files, extracted from process_new_files, plus versions::link_new_files), and answers with the version. Idempotent.
ImageApi never writes under library roots; ComfyUI is never exposed to the apps.
API shapes are documented in CLAUDE.md ("Enhance on demand") and match FileViewer-React#57 as specified.
Differences from the ticket text (FileViewer please note)
GET /enhance/templates returns an object {available, reason?, default, warn_above_megapixels, templates: [...]}, not a bare array. Extra per-template fields: prompt_required, default, output_megapixels, warn_above_megapixels.
Job pending is [{n, preview, approved}] (preview is an API path); ComfyUI's internal staged id is not exposed. The ticket's {id, preview} became {n, preview}. Extra job fields: library_id, updated_at, saved: [{n, path, library_id}].
GET /enhance/jobs?path= returns {"jobs": [...]}, newest first.
POST /enhance/jobs/{id}/approve returns the bare /image/versionsversions[] entry. If the file was saved but could not be ingested, it returns 202 {"linked": false, "path", "library_id", "job"}.
Added POST /enhance/jobs/{id}/discard (requested by FileViewer): hides the job from the per-photo list; nothing is deleted on ComfyUI.
Errors are {"error", "code"}: 400 bad request, 404, 410 expired, 422 ComfyUI rejected, 502, 503 unavailable/disabled.
requires_reference is not exposed (no startup probe).
Tests
DATABASE_URL=":memory:" cargo test: 1026 passed. Enhance tests use a mock ComfyUI HTTP server (submit mapping and seeds, lifecycle, preview relay, expiry, approve with ingest and idempotency, discard, unavailable, idle free). Fixtures are copies of the real Restore, Edit and Dev templates in tests/fixtures/enhance/. cargo fmt and cargo clippy --all-targets are clean.
Real ComfyUI (0.43.1), submitted with require_approval, never approved: Restore and Edit each went submit, poll, ready, preview (1152x864 PNG for the 019_19.JPG test photo).
Not done
Not deployed. A real enhance.toml must be created on the host.
requires_reference probing; the optional upscale-to-original-size step.
## What
Enhance on demand (#192): run a ComfyUI restore/edit template on a photo from the apps, preview it through ImageApi, approve it in-app, and it lands as a photo version (#191).
- `enhance.toml` (annotated `enhance.example.toml`, gitignored, no secrets): templates, path map, timings. A template missing `imageapi:source` / `imageapi:save`, or with a prompt node lacking `text|prompt|value`, is logged and skipped; the rest load. Stray `SaveImage` nodes are a startup warning.
- Template fill: nodes found by `_meta.title`; `require_approval` forced; prompt `append` (per-template `prompt_join`, default one space) or `replace` (required, empty is a 400); reference node and every link to it removed when no `reference_path`; fresh value for every `seed`, `noise_seed` and `*.seed` input per submit.
- Path map `/media/nas/` <-> `Z:\` (longest prefix, both directions).
- `enhance_jobs` table plus a background poller (`/queue` then `/history/{id}`): queued, running, ready, failed, and `expired` when ComfyUI forgot the prompt (restart). `unavailable` after `unreachable_grace_secs`.
- Idle `POST /free` once per quiet spell (empty queue, no active job, newest `/history` unchanged for `idle_free_secs`; measured on ImageApi's clock).
- Approve calls `/imageapi/approve`, maps the returned path, runs a targeted ingest (`watcher::register_new_files`, extracted from `process_new_files`, plus `versions::link_new_files`), and answers with the version. Idempotent.
- ImageApi never writes under library roots; ComfyUI is never exposed to the apps.
API shapes are documented in CLAUDE.md ("Enhance on demand") and match FileViewer-React#57 as specified.
## Differences from the ticket text (FileViewer please note)
- `GET /enhance/templates` returns an object `{available, reason?, default, warn_above_megapixels, templates: [...]}`, not a bare array. Extra per-template fields: `prompt_required`, `default`, `output_megapixels`, `warn_above_megapixels`.
- Job `pending` is `[{n, preview, approved}]` (preview is an API path); ComfyUI's internal staged id is not exposed. The ticket's `{id, preview}` became `{n, preview}`. Extra job fields: `library_id`, `updated_at`, `saved: [{n, path, library_id}]`.
- `GET /enhance/jobs?path=` returns `{"jobs": [...]}`, newest first.
- `POST /enhance/jobs/{id}/approve` returns the bare `/image/versions` `versions[]` entry. If the file was saved but could not be ingested, it returns 202 `{"linked": false, "path", "library_id", "job"}`.
- Added `POST /enhance/jobs/{id}/discard` (requested by FileViewer): hides the job from the per-photo list; nothing is deleted on ComfyUI.
- Errors are `{"error", "code"}`: 400 bad request, 404, 410 expired, 422 ComfyUI rejected, 502, 503 unavailable/disabled.
- `requires_reference` is not exposed (no startup probe).
## Tests
`DATABASE_URL=":memory:" cargo test`: 1026 passed. Enhance tests use a mock ComfyUI HTTP server (submit mapping and seeds, lifecycle, preview relay, expiry, approve with ingest and idempotency, discard, unavailable, idle free). Fixtures are copies of the real Restore, Edit and Dev templates in `tests/fixtures/enhance/`. `cargo fmt` and `cargo clippy --all-targets` are clean.
Real ComfyUI (0.43.1), submitted with require_approval, never approved: Restore and Edit each went submit, poll, ready, preview (1152x864 PNG for the 019_19.JPG test photo).
## Not done
- Not deployed. A real `enhance.toml` must be created on the host.
- `requires_reference` probing; the optional upscale-to-original-size step.
Closes #192
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Enhance on demand (#192): run a ComfyUI restore/edit template on a photo from the apps, preview it through ImageApi, approve it in-app, and it lands as a photo version (#191).
enhance.toml(annotatedenhance.example.toml, gitignored, no secrets): templates, path map, timings. A template missingimageapi:source/imageapi:save, or with a prompt node lackingtext|prompt|value, is logged and skipped; the rest load. StraySaveImagenodes are a startup warning._meta.title;require_approvalforced; promptappend(per-templateprompt_join, default one space) orreplace(required, empty is a 400); reference node and every link to it removed when noreference_path; fresh value for everyseed,noise_seedand*.seedinput per submit./media/nas/<->Z:\(longest prefix, both directions).enhance_jobstable plus a background poller (/queuethen/history/{id}): queued, running, ready, failed, andexpiredwhen ComfyUI forgot the prompt (restart).unavailableafterunreachable_grace_secs.POST /freeonce per quiet spell (empty queue, no active job, newest/historyunchanged foridle_free_secs; measured on ImageApi's clock)./imageapi/approve, maps the returned path, runs a targeted ingest (watcher::register_new_files, extracted fromprocess_new_files, plusversions::link_new_files), and answers with the version. Idempotent.API shapes are documented in CLAUDE.md ("Enhance on demand") and match FileViewer-React#57 as specified.
Differences from the ticket text (FileViewer please note)
GET /enhance/templatesreturns an object{available, reason?, default, warn_above_megapixels, templates: [...]}, not a bare array. Extra per-template fields:prompt_required,default,output_megapixels,warn_above_megapixels.pendingis[{n, preview, approved}](preview is an API path); ComfyUI's internal staged id is not exposed. The ticket's{id, preview}became{n, preview}. Extra job fields:library_id,updated_at,saved: [{n, path, library_id}].GET /enhance/jobs?path=returns{"jobs": [...]}, newest first.POST /enhance/jobs/{id}/approvereturns the bare/image/versionsversions[]entry. If the file was saved but could not be ingested, it returns 202{"linked": false, "path", "library_id", "job"}.POST /enhance/jobs/{id}/discard(requested by FileViewer): hides the job from the per-photo list; nothing is deleted on ComfyUI.{"error", "code"}: 400 bad request, 404, 410 expired, 422 ComfyUI rejected, 502, 503 unavailable/disabled.requires_referenceis not exposed (no startup probe).Tests
DATABASE_URL=":memory:" cargo test: 1026 passed. Enhance tests use a mock ComfyUI HTTP server (submit mapping and seeds, lifecycle, preview relay, expiry, approve with ingest and idempotency, discard, unavailable, idle free). Fixtures are copies of the real Restore, Edit and Dev templates intests/fixtures/enhance/.cargo fmtandcargo clippy --all-targetsare clean.Real ComfyUI (0.43.1), submitted with require_approval, never approved: Restore and Edit each went submit, poll, ready, preview (1152x864 PNG for the 019_19.JPG test photo).
Not done
enhance.tomlmust be created on the host.requires_referenceprobing; the optional upscale-to-original-size step.Closes #192
🤖 Generated with Claude Code
2d6663c12cto97d9301a71