Simplify generation controls with task navigation and settings drawer
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# AIGen queue fix and codebase review
|
||||
|
||||
Reviewed September 6, 2026. Scope: queue dispatch and recovery, Comfy lifecycle and host connector, generation pipelines, storage/authentication, and the Vue pages/components. This includes a source review, isolated regression tests, a production build, and desktop/390px phone checks of the local iteration editor. The deployed site requires an Authentik session that was unavailable in the connected browser. Its authenticated pages and an actual RTX 5080 render have not been verified. No production queue records or saved media were changed.
|
||||
|
||||
## Queue failure: confirmed and fixed locally
|
||||
|
||||
The dispatcher serialized work using `dispatchChain`. During its own busy check, it could recover an image/music job whose output was already saved and await `onLiveVideoSettled`. That function queued another dispatch and awaited it. The new dispatch was behind the unfinished current dispatch: neither could finish. Clearing disk records does not release this in-memory promise, which explains why repeated clear actions can fail to restore handoffs. This is a reproduced code defect consistent with the reported symptoms, not a diagnosis from production logs.
|
||||
|
||||
Changes:
|
||||
|
||||
- Settlement still waits for its durable queue update, but schedules the next dispatch without awaiting it. This removes the circular dependency while preserving serialized dispatch.
|
||||
- Completion callbacks must match the live job, or an unassigned row with the same shot-queue ID. An old callback can no longer finish an unrelated newer job or a newer run of the same batch.
|
||||
- The 40-item retention limit now applies only to recent finished jobs. Waiting, held, and running jobs are preserved.
|
||||
- Comfy history requests have a 12-second timeout. Failed requests leave the job unresolved rather than declaring its prompt lost; a successfully fetched empty history still permits stale-job recovery.
|
||||
|
||||
Files: `server/utils/studioQueue.ts`, `server/utils/comfy.ts`, `tests/studio-queue.test.mjs`, `package.json`.
|
||||
|
||||
Validation: `npm test` passes all 25 tests in the combined checkout: 10 queue recovery tests, 5 iteration tests, and 10 shared-GPU tests added in separate concurrent work. The initial seven-test suite run against the original committed queue code produced four expected failures: image deadlock, music deadlock, late callback completing a newer job, and active queue truncation. Additional tests cover a late callback within the same shot batch and failed history requests. Tests execute the real queue module against temporary disk stores with simulated Comfy responses. They do not generate media.
|
||||
|
||||
Applying this to the running service requires rebuilding/redeploying AIGen and restarting its server process. Restarting Comfy alone cannot replace the application's deadlocked dispatcher. Preserve the existing library volume. After deployment, validate image -> image, video -> image, music -> video, and a multi-shot continuation; refresh the browser while rendering and verify each output is saved once and the next job starts once.
|
||||
|
||||
## Highest-priority functional improvements
|
||||
|
||||
| Priority | Finding and evidence | Recommended change |
|
||||
| --- | --- | --- |
|
||||
| High | Queue state exists independently in `studioQueue.ts`, `jobs.ts`, `pending.ts`, `shotQueue.ts`, and Comfy. `repairStaleJobs` can label a missing live job complete without proving that its output was saved. | Use one durable job record with explicit phases: waiting, waking GPU, submitting, rendering, saving, complete, failed, cancelled. Persist prompt ID, attempt ID, output IDs, and last successful contact. On restart, reconcile exact prompt IDs before claiming completion or retrying. |
|
||||
| High | `pending.ts` describes video recovery; `restoreJob` in `jobs.ts` restores jobs as video. Image/music pipelines do not share the same durable recovery record. | Give every generation type the same restart recovery contract. Persist submission intent before sending to Comfy, then attach the returned prompt ID. Resolve ambiguous submissions before resubmitting to avoid duplicates. |
|
||||
| Verify rollout | Separate concurrent work added `withSharedGpuReset` around force reset and a host reservation gate. | Verify the host-agent rollout together with the app, and test reset while a submission is already in progress. See `docs/shared-gpu-rollout.md`; do not deploy just the app against an older coordinator. |
|
||||
| High | `videoJobsBusy` returns a boolean from several partly independent checks, so the UI cannot explain which record is blocking work. Exceptions from dispatch are swallowed. | Return a structured blocker: owner-safe job ID, phase, pending count, last activity, connection state, retry time. Log state transitions and unexpected dispatcher errors. Expose a diagnostics panel with a copyable report. |
|
||||
| High | `readStore` in `studioQueue.ts` and the shot-queue reader return empty queues after parse/read errors; a later mutation can overwrite the damaged store. | Fail visibly and preserve the original file. Keep a previous known-good snapshot and add schema versions. Longer-term, replace independent JSON files with transactional storage and a single worker claim for the GPU. |
|
||||
| Medium | `jobs.ts` evicts the oldest in-memory job whenever the map exceeds 40 entries, regardless of active status. | Evict terminal jobs only. Persist older history separately. Add a regression test covering many prompt/recommendation jobs while a long render remains active. |
|
||||
| Medium | `runGeneration` in `videoChain.ts` settles in `finally`, while its caller in `studioQueue.ts` sets an escaped failure status afterward. | Establish error/cancel status before settlement inside the generation runner. Test wake failure, upload failure, and validation failure, including the queue status shown to the user. |
|
||||
| Medium | `generate/active.get.ts` ties a running job's visibility to Comfy being busy; a job saving media can disappear while the dispatcher correctly remains occupied. | Report saving/stitching as active and show its phase. Share one definition of active work between queue, header, and generator. |
|
||||
| Medium | Health, queue, and recovery polling run independently in `AppHeader.vue`, `index.vue`, `music.vue`, and `queue.vue`. | Share one client status store, deduplicate in-flight requests, slow polling for hidden tabs, and use push updates for transitions with polling as fallback. |
|
||||
| Medium | Queue fairness is owner-order based in `dispatchStudioQueue`; transient errors are repeatedly converted back to waiting. | Select work globally by explicit priority and creation time; add bounded retries with increasing delays and a visible retry action after repeated failure. |
|
||||
|
||||
## Visual and interaction recommendations
|
||||
|
||||
The existing dark palette, amber primary actions, reusable controls, and two-column editor/preview layout provide a good foundation. The biggest improvement would be making the active task and its status clearer, while reducing the amount of model configuration visible at once.
|
||||
|
||||
| Priority | Area and source | Recommendation |
|
||||
| --- | --- | --- |
|
||||
| Done · September 7, 2026 | ~~Generation controls: `pages/index.vue`, `components/StudioKindCards.vue`~~ | Implemented **Image / Video / Music** navigation, **From text / From image / Edit / Extend** task shortcuts, a shared generation-settings drawer, visible size/duration and Queue controls, and a persistent Advanced mode. Music uses the same drawer. Empty prompt wrappers are hidden in Simple mode; populated wrappers remain visible. |
|
||||
| High | Status: `components/AppHeader.vue`, `pages/queue.vue` | Add a persistent status strip: **GPU asleep / Starting / Rendering / Saving / Connection lost**, current job, and waiting count. A queued item should say what it is waiting for. Rename “Poke” to “Wake GPU” consistently. |
|
||||
| High | Queue: `pages/queue.vue` | Separate one prominent current-job card from a compact upcoming list. Show queue position, media type, duration, progress, and primary action. Collapse shot details until expanded. Distinguish **Pause after this shot**, **Cancel job**, **Clear waiting jobs**, and **Reset GPU** by their actual effects. |
|
||||
| Medium | Mobile mode selection: `components/StudioKindCards.vue` | The fixed three-column cards contain nested two-column model controls. Use a compact mode switch on narrow screens and show settings only for the selected mode. Increase small secondary text and touch spacing. Verify at 360px and 390px widths. |
|
||||
| Medium | Typography: `pages/queue.vue`, `pages/library.vue`, `pages/music.vue` | Reduce repeated 10–11px uppercase metadata and low-contrast labels. Establish a small set of shared text, spacing, panel, and button styles; reserve amber for the main action and selected state. |
|
||||
| Medium | Library: `pages/library.vue` | Keep search/filter controls visible and add an optional side-by-side comparison for image variants. Provide a consistent details drawer containing prompt, seed, model, parent, and **Use as input / Make variation / Extend** actions appropriate to the asset. |
|
||||
| Medium | Dialogs: `QueuedJobModal.vue`, `ImagePickerModal.vue` | Use a shared accessible dialog component with a named dialog role, focus trap, Escape handling, initial focus, and focus restoration. Escape handling already exists, but focus behavior and dialog semantics are inconsistent. |
|
||||
| Medium | Feedback across generator and queue | Keep an always-visible Queue action near the prompt, with clear success feedback such as “Added at position 3.” Preserve the editor draft on network failure and offer an explicit retry without duplicating submissions. |
|
||||
|
||||
Suggested desktop arrangement: a compact left navigation, central prompt/source editor, right output preview, and a collapsible queue strip below. On mobile, stack editor and preview and keep Queue plus GPU status reachable near the bottom. These are broader design proposals based on the source. The enhanced iteration editor itself was also checked visually in the isolated local preview.
|
||||
|
||||
## Maintenance and deployment concerns
|
||||
|
||||
- `pages/index.vue` is roughly 348 KB of source; `studioQueue.ts` roughly 71 KB. Extract generation drafts, status subscriptions, and submission into shared composables, and split mode-specific editors. Extract scheduling, reconciliation, and persistence from the queue module. Do this incrementally behind the regression tests.
|
||||
- The session and local credential modules accept a fixed development secret; backup configuration also has a fixed fallback token (`session.ts`, `localAuth.ts`, `backupStudio.ts`, `nuxt.config.ts`). In a network-exposed deployment, require explicitly configured secrets and fail startup when missing. Audit current configuration before changing any existing encryption key, because saved credentials depend on it. No secret values need to appear in logs or diagnostics.
|
||||
- `interrupt.post.ts` selects live jobs before enforcing owner matching and can target other owners' in-memory jobs. Apply owner filtering before mutations; make device-wide interruption an explicit administrative operation if multiple users share this instance.
|
||||
- `api/media.get.ts` downloads the full response before applying a byte range, while library-file routes already support streaming. Relay ranges/streams for large Comfy outputs to reduce memory use and improve playback seeking.
|
||||
- Add `npm test` and a production build to CI. Add a type-check step after establishing a baseline for Nuxt's generated types. Prefer lockfile-based installation in the Docker build so deployments use the reviewed dependency tree.
|
||||
|
||||
Recommended order: deploy and validate the queue fix; add explicit job phases and blocker diagnostics; make reset/restart recovery consistent across media types; simplify the editor and queue presentation; then split the larger modules. Keep the current generation workflows intact while making these improvements.
|
||||
|
||||
## Enhanced iteration mode: implemented locally
|
||||
|
||||
In Image -> Iterate, open **Compare settings · build a sweep**. Enter steps **24, 20, 18, 19** and CFG **1.5**, then choose **Build 4 variations**. The shared prompt and first-image settings form the base. Later rows can override steps, CFG, seed, and LoRAs, or leave the prompt blank to reuse the first prompt. Krea edits can also override denoise within the workflow's supported range.
|
||||
|
||||
The sweep uses the same seed for all images and the original input (if supplied). This makes it useful for comparing settings. Choose **Random** or a custom seed per variation when desired. An unchecked **Use shared LoRAs** option starts an independent, empty LoRA stack; add the LoRAs and strengths for that image. Custom steps/CFG take precedence over the shared Turbo preset for that variation.
|
||||
|
||||
Multiple CFG values produce every requested steps/CFG combination in order. At most 50 images are accepted per batch. Review the count before queueing. Model, graph, dimensions, and negative prompt remain shared in this version; per-image overrides cover the requested sampling and LoRA comparisons. Existing **From original** and **From last** behavior remains available for image-based iterations.
|
||||
|
||||
Overrides survive queue storage, queue editing, reload into the editor, and generation-log requeue. Each output records the actual settings used. The iteration worker keeps its queue slot through upload/save gaps, preventing a previous iteration's saved output from being mistaken for completion of the whole batch. The first-image seed now preserves an explicitly entered zero.
|
||||
|
||||
Tests cover sweep construction, validation, settings/seed/LoRA propagation through the actual iteration runner with a simulated Comfy connection, saved metadata, and queue-edit round trips. The local UI check created the four requested variations and verified independent editing; it did not submit a real GPU render.
|
||||
|
||||
## Generation controls update — September 7, 2026
|
||||
|
||||
Completed the generation-controls recommendation above. Validation: all 35 existing tests passed and the production build passed. Local browser checks covered the simple layout, the settings drawer with Escape and focus restoration, and 390px/360px layouts without horizontal overflow. No GPU generation was submitted during these UI checks.
|
||||
Reference in New Issue
Block a user