Keeps the planned All-in-One loader and cross-node prompt features but removes
the regressions they introduced:
- model references: one adapter table for verified layouts (easy a1111Loader,
easy fullLoader, Efficient Loader) shared by recipe_identity.js and
recipe_schema.py; native loaders keep their stored labels; no more guessing
categories from file names (a "...vae.safetensors" checkpoint was a VAE);
"None"/"Baked VAE" are never references
- recipe summary sync follows the extraction rules: only checkpoint/UNet
loaders or ckpt_name/unet_name set the base model (not an upscaler's
model_name), only sampler-like nodes set seed/steps/cfg, and LoRA edits
update the entry of the edited loader instead of falling back to loras[0]
- one LoRA entry per loader again (deduplication shifted entries)
- prompt injection never writes negative text into a positive slot or the
reverse; the block chooser follows the same rule
- material cards only accept cross-node drops that carry prompts; parameter
blocks stay same-type
- drop unused imports and the unused modelSpecs alias
Verified: regression cases added to tests/recipe_all_in_one_compatibility.mjs
and tests/material_prompt_cross_node.mjs (both fail on the previous commit),
new tests/test_recipe_model_references.py; all JS tests except the orphaned
material_parameter_cross_node.mjs and 95 Python tests pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
ComfyUI-F5-TTS resolves {happy} to <sample stem>.happy.wav beside the selected
sample, so `Arona_happy.wav` + `{Arona_happy}` could never run. Voices now use
Character.wav (main, {main}) and Character.<emotion>.wav ({emotion}); the
catalog groups a main voice with its variants and marks tags that F5-TTS
cannot resolve (missing main, missing .txt, different format).
- script director: one character per script, untagged lines pinned to {main},
pushes sample (main voice, node's own combo spelling) and speech together,
confirms before overwriting and re-checks the node after the dialog
- pure rules (splitting, composing, planning, combo spelling) in audio_script.js
- one module instance per file: drop ?v= imports that duplicated
ui_audio_gallery/ui_audio_studio state, so studio playback stops the gallery
- all user/file-derived text goes through textContent (no innerHTML)
- studio/sidebar/gallery renders ignore stale responses; errors are shown
- gallery: count badge no longer overwrites the title, paging via "load more",
deletion errors surfaced, timeupdate instead of a 100ms timer
- sidebar: filter selection updates in place instead of refetching; the header
tabs, sidebar and domain switch share browser.switchAudioTab
- uploader: createViewScope lifecycle (Esc/overlay/close release listeners and
object URLs, Esc no longer reaches the parent), 409 -> confirm -> overwrite,
sends the pre-romanization text as original_text, no hard-coded character
- workflow template: confirm before replacing the canvas, clear message when
the template file is missing, align sample paths to the node's combo values
- static styles moved from inline JS into 11-audio-studio.css; strings localized
Verified: tests/audio_script_rules.mjs, tests/test_audio_catalog.py (15), a
jsdom walkthrough of studio/gallery/director/uploader with a stubbed app
(outside the repo), JS syntax and import/export link check. Not yet checked in
a live ComfyUI session.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
- upload: validate target folder with resolve_within, refuse to overwrite an
existing voice unless overwrite=1, stage audio/transcripts and swap them in
together so conversion or disk failures keep the previous voice, drop stale
.txt/.orig.txt and other-format siblings, write .orig.txt for the native script
- ffmpeg is resolved explicitly (PATH, then portable python dir) with a timeout
- voice/gallery scans run in a worker thread; stems are unique across scan
folders; audio URLs are percent-encoded and versioned by mtime
- stream and delete only accept audio extensions; paging and template names
are validated; errors are JSON
- romanizer no longer reads Han-only (Chinese) text as Japanese and reports
missing pykakasi / hangul-romanize instead of silently succeeding
- extension static files use Cache-Control: no-cache (revalidate) instead of
no-store; document the deliberate PATH exception in __init__.py
Verified: new local tests/test_audio_catalog.py (14 tests) plus the existing
Python suite (78 tests) pass in a Linux venv; not yet exercised in ComfyUI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5