Commit Graph
380 Commits
Author SHA1 Message Date
DemonGatanjieuandClaude Opus 5.5 7da4e1d91e fix(audio): the audio guide's tour walks the audio page; suggested folder layout
The "!" guide on the audio page hid its tour banner with the hidden attribute,
but the banner's display:flex overrode it, so the banner showed and started the
image-side tour, whose buttons are not on the audio page. The audio guide now
has its own spotlight steps, and tour steps whose target is not on screen are
skipped. The batch import screen shows a folded example of a folder layout that
sorts cleanly: one folder per character, named after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:32:46 +08:00
DemonGatanjieuandClaude Opus 5.5 32a3719d97 fix: offline scans stay offline, workshop snap dock, 400 on malformed requests
From an outside audit:
- The scan wizard's offline mode still sent the greyed-out rename and
  overwrite options, and scraper.py fetched Civitai model pages and preview
  media for models whose .info held a Civitai id. Offline now implies no
  media and no model page; the folder scan and scan_all refuse a missing or
  non-object body instead of defaulting to an online scan.
- The Prompt Workshop's snap dock referenced leftSearch from the source deck
  module (ReferenceError on click); the deck now exposes focusSearch().
- translate, delete_model, delete_gallery_image and the image-material
  routes answer malformed bodies with 400 instead of 500.
- Removed six unused imports in ui_doctor.js and 16 duplicate locale keys
  per language (the later, effective entry is kept, so nothing changes on
  screen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:36:07 +08:00
DemonGatanjieuandClaude Opus 5.5 a083cfdc54 feat(audio): wider Script Director with a generate column, full cover when docked
The drawer grows to 1000px. From 760px wide the line cards take the full
height and the generation settings, generate bar, result and canvas buttons
sit in a 320px column beside them. When narrow (docked browser) the drawer
covers the studio column and keeps generating below the cards; only the
cards scroll in either layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:17:42 +08:00
DemonGatanjieuandClaude Opus 5.5 21d8ae5800 feat(audio): Script Director keeps one scroll area and a short bottom bar
Long scripts squeezed the line cards between the list and a footer that
scrolled on its own. Generation settings (language, speed, sampling) are
now one folded line above the cards that scrolls with them, and the footer
is a short bar: generate / retake / cancel, the result and the canvas
buttons. The fold state is remembered per browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:09:53 +08:00
DemonGatanjieuandClaude Opus 5.5 721a006b16 refactor(audio): drop F5-TTS, the audio page manages GPT-SoVITS only
The F5-TTS voice library (input/F5-TTS scanning, voice upload with ffmpeg
conversion, romanization, Load Audio clip drags) and the engine switch are
removed. The audio page now works with one engine, Anomalous_TTS
(GPT-SoVITS): characters, drags onto its node, the Script Director with
direct generation, pronunciation and settings. The audio gallery and its
stream route stay (output and temp folders only). The root PATH hack that
existed for F5-TTS's ffmpeg lookup is gone. Recorded as AD-016.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:53:07 +08:00
DemonGatanjieuandClaude Opus 5.5 6cb9ea39be feat(audio): pronunciation table for GPT-SoVITS characters
"Pronunciation" on a character card edits the node's `replace` setting
(script text -> what the character reads). Each row can be heard as the
character reads it now (the saved table applies) and as replaced, through
a Preview Audio run that stays out of the audio gallery; one preview at a
time, cancelled when the dialog closes. The file is re-read before editing
and every other settings field is kept. buildTtsPrompt gains `preview`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 02:41:44 +08:00
DemonGatanjieuandClaude Opus 5.5 e341b8a26d feat(audio): sampling parameters in the Script Director, roomier drawer, no audio workflow tab
- Generate section: top_k / top_p / temperature / repetition_penalty folded
  under "Advanced", ranges and defaults read from the node's /object_info;
  "save as this character's default" keeps language, speed and these (only
  values that differ from the node's defaults). The seed is not saved.
- Drawer 560px wide, line cards keep 180px, footer scrolls; for GPT-SoVITS
  the bundle preview is hidden and the canvas buttons are compact.
- The audio domain no longer shows the "Audio Workflows" header tab (the
  recipe library filtered to "audio"); a `hidden` header button now really
  hides despite the header's display !important rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 02:16:07 +08:00
DemonGatanjieuandClaude Opus 5.5 ff726db2f6 feat(audio): generate GPT-SoVITS scripts in the Script Director, drop the Arona template
The Script Director gets a Generate section for GPT-SoVITS characters
(ui_script_run.js): it queues the script as an API prompt with this
page's client id (audio_tts_run.js), shows queued/running/progress,
plays the result and saves it to output/audio/<character>/. The canvas
is never touched. A line card's retake button adds [take:N] to that
line so only it is regenerated; "New take of all" changes the seed.
Cancel deletes a queued job or interrupts it by prompt id when running
(checked against /queue, since the start event can arrive first).
Events that arrive before /prompt answers are buffered and replayed.
Language/speed start from the character's `defaults` and can be saved
back (read-modify-write, unknown fields kept). Needs Anomalous_TTS
interface 11; older versions get a hint and keep push-to-node.

The Arona multi-voice template read a file only one machine has; the
button, route, helper (alignedVoiceValue) and strings are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 01:25:05 +08:00
DemonGatanjieuandClaude Opus 5.5 7c97b73779 fix(notebooks): make UNet notes runnable and list unlabeled models
Sending a Prompt Note with a UNet main model chained its LoRAs through
LoraLoader, whose clip input nothing could feed. UNet LoRAs now use
LoraLoaderModelOnly and the editor says to connect a text encoder.

Models without a baseModel in their metadata matched no base model, so
they never appeared; base_models now reports them and
compatible_models serves them for "__unlabeled__". Both routes share
one walker and run it off the event loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:33:35 +08:00
DemonGatanjieuandClaude Opus 5.5 685de2fa15 fix(workspace): keep the header tabs usable, close with Esc, restore after the translator
- The recipe / notes / material workspace (nbPanel) starts below the 48px
  header instead of covering it, so Models / Gallery / Workflows stay
  clickable while it is open.
- Esc closes that workspace like a click beside it, unless one of this
  plugin's dialogs or a ComfyUI dialog is above it or a text field has focus.
- Closing the Prompt Translator shows the browser again when opening it had
  folded the browser away (not after sending text on to the studio).

Found in a browser audit; checked in an isolated ComfyUI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:24:52 +08:00
Claude a7749beed4 Merge remote-tracking branch 'origin/main' into claude/awesome-wright-48lzun
# Conflicts:
#	CHANGELOG.md
#	web/main.js
#	web/modules/browser_entry.js
#	web/styles.css
2026-09-26 19:21:26 +00:00
Claude af3bb60981 fix(perf): stop a :has() rule from slowing canvas dragging (v1.57.2)
`body:has(#…-modal[style*="display: flex"]) #…-tooltip-bubble` made the
browser re-check the whole page on every inline-style change anywhere.
ComfyUI moves every DOM widget (text boxes) on each pan/zoom frame, so every
frame paid for it, with the browser closed too, and much more with plugins
that add DOM per widget (ComfyUI Prompt Assistant).

Measured in ComfyUI (frontend 1.53.6, Chromium) panning a 300-node
workflow for 120 frames, style recalculation in total:
- no plugins 60 ms; AMB 690 ms -> 63 ms
- AMB + Prompt Assistant 2300 ms (~19 ms/frame) -> 86 ms (PA alone 80 ms)

The rule was redundant: both popups hide the tooltip when they open and
showSharedTooltip refuses while either is open (checked in the browser).
Cache-busting versions bumped so browsers load the new stylesheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012RMuwbsWZHnx2eCWpxYqAB
2026-09-26 19:20:03 +00:00
Claude d4603f8e8a feat(tts-import): folder-first grouping, visible skips, batches, preview
- A folder holding one character's GPT + SoVITS weights and its clips is that
  character, named after the folder: two characters whose weights are both
  "model" no longer merge, pinyin weights in a Chinese-named folder take the
  folder's name, version folders read "派蒙 v2". Package weight folders keep
  the name-by-stem rule.
- Skip rules match the node (interface v9): Python environments and base
  models always; GPT_SoVITS / logs / output / TEMP / tools only inside a
  package; the chosen or dropped folder never. The drop walker and the folder
  dialog apply them where the listing is known (the old re-check on each
  file's path skipped a chosen folder called "output"), local scans prefix
  the chosen folder so every source sorts alike, and the window names the
  skipped and too-deep folders instead of losing files quietly. Drops only
  open importable files and stop at 5000.
- Same-name files inside a character are renamed with their folder
  (难过_01.wav, sent as the file's "name") instead of dropped; an unclaimed
  .list goes to every character.
- Big adds open 20 characters (about 800 files) at a time; "next batch" opens
  the rest, and it opens by itself once a batch is imported, replacing the
  imported cards. Unassigned files upload only once put into a character.
- Every clip can be previewed while importing, local paths included (through
  the node's preview route): one at a time, ▶ turns into stop, another clip
  switches.
- Upload queue and preview player move to their own modules, the "add more"
  menu to the screens module (ui_tts_import.js 647 → 652 lines with batches and renames added).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012RMuwbsWZHnx2eCWpxYqAB
2026-09-26 15:20:24 +00:00
DemonGatanjieuandClaude Opus 5.5 4396ca375c feat(tts-import): big batches stay responsive; unusable clips left out
- A folder per character: clips and line files follow the weights in their
  nearest folder, so pinyin weights, Chinese folders and English clips still
  land together (a real 34-character folder: 3065 unassigned files -> 0).
- Clips outside 3-10 s and their same-name line files are left out of the
  import and folded under "left out" instead of one warning per clip.
- GPT-SoVITS program and training folders are skipped in drops (not even
  walked) and picked folders; a very large upload (>1500 files or 2 GB)
  first offers the local folder picker.
- Uploads run three at a time, status repaints are coalesced, a card shows
  its first 60 clips, move menus are filled when opened, and the unassigned
  card folds into one line per folder that can be assigned at once.
- New ui_tts_import_sources.js brings files in (dialogs, drops, local picker).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:17:47 +08:00
DemonGatanjieuandClaude Opus 5.5 bd7fb8beaa chore(shortcuts): remove the never-wired shortcut organizer
ui_shortcut_organizer.js and shortcut_layout.js only referenced each other;
the bottom bar is the fixed one built in ui_toolbox.js. Also drops their
eleven locale keys and marks the customizable-shortcuts plan as abandoned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:57:41 +08:00
DemonGatanjieuandClaude Opus 5.5 3274636720 feat(audio): guided GPT-SoVITS import (choose, checklist, tour)
The import window now asks what the user has first: one character, many
characters or a package, or files for an existing character (picked from
a list, or opened straight from a card's "Add files"). Dropped files skip
the question.

Each character card leads with a checklist (GPT model, SoVITS model,
clips, main voice, name) that lights up the next step and offers its
button in that line; the chosen weights sit in their lines, and the
card header says how many steps are left. A main voice (3-10 s) is now
required for a new character, as GPT-SoVITS needs one.

A spotlight tour explains the first question and the card the first time
each is shown; "?" in the header replays it. ui_spotlight_tour.js takes
its steps and an onClose from the caller now; the browser tour is
unchanged. The fixed screens and tour steps live in
ui_tts_import_screens.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:30:25 +08:00
DemonGatanjieuandClaude Opus 5.5 f220c63315 feat(audio): redesign the GPT-SoVITS import window
The two-column workbench was hard to read on first open. The window now
opens as one drop area that says what to bring (GPT model, SoVITS model,
3-10 s clips) with two buttons and a quiet "files on this PC" line, and
three steps at the top show where the user is.

With files, each character is a card: folded, one line with the name
(edited in place), a short status and what it holds; unfolded, two model
tiles, one line per clip (main-voice star, emotion, line) and the line
files and language at the bottom. One card is open at a time; files that
match no character get a card of their own at the top. "Add more" is a
single button with a menu, the owner picker on each clip only shows on
hover, and the footer says what still needs a look and where it saves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:55:24 +08:00
DemonGatanjieuandClaude Opus 5.5 56882fd1e4 feat(audio): batch import workbench for GPT-SoVITS characters
The import form becomes a two-column workbench for one or many
characters. Files and whole folders can be dropped, or a folder on this
PC scanned (Anomalous_TTS browse?recursive=1, interface 6). Weights pair
up by name with the latest epoch kept; clips and line files follow their
folder or file-name prefix; anything unclear waits in an unassigned
tray. The left column lists the characters with a status dot, the right
shows the selected one with one compact line per clip and a picker (or
drag handle) to move files between characters. Ready characters are
imported one after another, each on its own, so a failure leaves the
others alone.

Grouping rules live in tts_import_groups.js, the draft pane in
ui_tts_import_draft.js and OS drop reading in ui_tts_file_drop.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:26:16 +08:00
DemonGatanjieuandClaude Opus 5.5 a8d02f135b feat(audio): import form shows at a glance what is done
Each section title gets a mark (green check with counts, amber
"required" for what a new character still needs, red on problems) and
each row a coloured bar: green ready or merged, blue uploading, grey
skipped, red failed or refused. Clips scroll in their own box and the
Import button stays in view.

When adding to a character, inspect now sends the target (Anomalous_TTS
interface 5): files it already has show as skipped, annotation files as
merged, and a different file under the same name blocks the import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:55:34 +08:00
DemonGatanjieuandClaude Opus 5.5 248e137f23 feat(audio): richer audio sidebar, GPT-SoVITS settings as a dialog
The sidebar groups characters by language (GPT-SoVITS) or folder
(F5-TTS) in foldable groups; a character unfolds into its clips and a
click plays one through the studio row. Characters drag onto nodes from
the sidebar, a red dot marks characters that need a look, a search box
shows from six characters on, and files dropped on a GPT-SoVITS
character open "Add files" for it.

GPT-SoVITS settings move to a dialog opened from the sidebar footer,
which carries the reminder dot; "Import character" moves into the
studio toolbar. Canvas drag helpers move to audio_voice_drag.js so the
sidebar and the cards share them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 13:00:50 +08:00
DemonGatanjieuandClaude Opus 5.5 144c32929e feat(audio): quieter GPT-SoVITS setup, empty studio as a drop area
The setup card is one folded line; missing pretrained files (fetched on
first use anyway) only get a small dismissable dot once the studio's
characters need them, and the import form notes what the chosen
language will download. An empty GPT-SoVITS studio is a drop area with
the import button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:37:41 +08:00
DemonGatanjieuandClaude Opus 5.5 5dc570d880 feat(audio): one storage place for GPT-SoVITS characters
Uses Anomalous_TTS interface v4.

- Setup card: "where characters are kept" replaces the library list.
  "Change..." picks a folder on the ComfyUI machine and asks whether the
  current characters move along (move / don't move / cancel). A move shows
  its progress (characters, and bytes when copying across disks) and the
  studio redraws when it ends; an error says where it stopped.
- "Other places" lists earlier storage places that still hold characters
  and yaml folders; x on an earlier place stops listing it (files kept).
- Import form: no location picker; new characters go to the storage place
  and the form shows the exact path.
- The "add library" action is gone (no longer offered by the node).

Tested: node tests/tts_setup_api.mjs (storage calls, moving summary).
Isolated ComfyUI in the browser: change storage with move (both
characters moved, a non-character folder left, config updated), change
back without moving (old place listed under other places, stale move
message not shown), remove the earlier place (characters unlisted, files
kept), import form shows the storage path; a .list dropped on a clip's
text box fills it without being added as a file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:28:20 +08:00
DemonGatanjieuandClaude Opus 5.5 c0a6beff04 feat(audio): more ways to find a clip's reference line on import
- Each clip shows where its line came from (same-name .txt / .lab,
  annotation file, or the file name, marked as a guess to check).
- Dropping a .txt / .lab / .list on a clip's line box fills it: a plain
  file is the line, an annotation file is searched for that clip (same
  rule as the node, including the name without the emotion part).
- .lab is an importable line file.

Tested: node tests/tts_setup_api.mjs (textFromFile added).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:16:26 +08:00
DemonGatanjieuandClaude Opus 5.5 fd966a7ee3 feat(audio): simpler GPT-SoVITS import form
- Fixed sections for GPT weight, SoVITS weight, reference clips and line
  files; files dropped anywhere on the form go to their section. One GPT
  and one SoVITS: a new one replaces the old, and from a batch the latest
  epoch is kept (the others are named in a note).
- The save location is one line ("Saved to …/gpt_sovits/<name>") with
  "Change location"; the library list only shows when asked for.
- Name clashes are shown while typing; an exact match offers "add to that
  character instead", which switches the form to add mode in place.
- Unsupported SoVITS versions (v3/v4) are marked and block the import;
  clips outside 3-10 s cannot be the main voice.
- After an import the studio scrolls to the new card and highlights it.

Tested: node tests/tts_setup_api.mjs (epoch pick, name clash, version
block, clip range added). Isolated ComfyUI in the browser: name clash and
switch to add mode, three GPT epochs -> e15 kept, SoVITS replaced by a v4
file -> blocked, short clips not selectable as main, add-mode import of a
clip as {平静} with the card highlighted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:10:07 +08:00
DemonGatanjieuandClaude Opus 5.5 ed86a92aeb feat(audio): GPT-SoVITS setup card and character import
Uses Anomalous_TTS interface v3 so a new user can get going without
editing extra_model_paths.yaml or sorting model folders by hand.

- Setup card on the GPT-SoVITS studio: character libraries (add/remove),
  pretrained files (per-item or all download with progress, or use an
  existing GPT-SoVITS package) and missing Python packages with the
  install command. Collapses to one line when ready.
- Import form: drop files, pick them in the browser, or pick them on the
  ComfyUI machine (server-side path picker, no upload). Name, SoVITS
  version, clip length, lines, main voice and language are filled in from
  the node's inspect; emotions per clip. Uploads go in 8 MB chunks.
- "Add files" on a card, or a drop onto it, adds clips and emotions to
  that character without replacing its main voice.
- Hidden for nodes without v3; disabled when the page is not opened on
  the ComfyUI machine.
- New modules: tts_setup_api.js (calls + pure form rules),
  ui_tts_setup.js, ui_tts_import.js, ui_tts_path_picker.js and
  styles/12-tts-setup.css. ui_audio_studio.js only wires them in.

Tested: node tests/tts_setup_api.mjs (new, local) plus the audio engine,
node target and script rule tests. Isolated ComfyUI with both plugins in
the browser: setup card for a fresh user, package as pretrained source,
library add, import from local paths (lines found in all.txt), file drop
onto a card (chunked upload, add mode), cancel discards the upload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 19:37:42 +08:00
DemonGatanjieuandClaude Opus 5.5 ad8596ad48 perf(audio): stop the GPT-SoVITS page from refetching on every render
- Cache engine presence and voice groups (60 s) so domain switches, sidebar
  clicks and the studio + sidebar pair cost no requests; saves and added
  voices invalidate, Refresh also asks Anomalous_TTS to rescan (?refresh=1).
- Follow Anomalous_TTS interface v2: the list is a summary; the emotion
  editor opens at once and loads the character's audio list in the
  background (save waits for it, keeps unknown settings fields).
- Cards: show "角色/版本" as name + quiet suffix, one-line drag hint,
  header wraps instead of squeezing.
- Docs: ARCHITECTURE audio_engines paragraph, audio-studio guide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q6FStZ5hiKELvNH3WKgBnx
2026-09-24 18:15:49 +00:00
DemonGatanjieu ccb2beb490 Merge main (material card layout fix) into feature/audio-engines 2026-09-24 16:00:18 +00:00
DemonGatanjieuandClaude Opus 5.5 9e761d0705 fix(materials): stop apply-mode card text from overlapping
The grid used one fixed row height, so the extra apply button squeezed the
badges, date and node types on top of each other. Cards in apply mode now get
a taller row (the list is marked is-apply-mode when it renders), the apply
button sits at the bottom, and only the tag row may be clipped when space
runs out. The normal row is a little taller so a tag row fits as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-24 16:00:18 +00:00
DemonGatanjieu cb26b763b8 Merge main (material apply button fix) into feature/audio-engines 2026-09-24 15:55:24 +00:00
DemonGatanjieuandClaude Opus 5.5 01fc925bd6 fix(materials): one apply button per card, without a doubled icon
In apply mode each card rendered a second apply button (a clone meant for
the list layout's hover actions) that showed as an extra row in the grid,
and both labels prefixed another icon to a locale string that already has
one. Cards now render a single button whose text comes straight from the
locale (textContent), in grid and list layouts alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-24 15:55:24 +00:00
DemonGatanjieuandClaude Opus 5.5 634b2384cf feat(audio): engine switch with runtime detection; GPT-SoVITS via Anomalous_TTS
- audio_engines.js: F5-TTS and GPT-SoVITS (the separate Anomalous_TTS node
  pack), detected through /object_info/<node class>. Both engines' voices are
  normalised into one voice-group shape so cards, sidebar and Script Director
  share one implementation.
- The audio page shows an engine switch; a missing engine stays listed as
  "not installed" with install steps (no popups). The F5-TTS library still
  works without the F5-TTS node; GPT-SoVITS is never scanned when missing.
- GPT-SoVITS cards come only from the node's HTTP contract: preview reference
  clips, drag a character onto AnomalousTTS_CharacterSpeech, and edit the
  emotion references ("Edit emotions"), saved through /anomalous_tts/settings
  with unknown fields preserved and the node's validation messages shown.
- Drop targets and the Script Director are per engine: voices of one engine
  are refused on the other engine's node with the reason.
- Audio gallery reads the character of GPT-SoVITS generations.
- Usage guide (in-app and docs/guides/audio-studio.md) covers both engines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-24 13:13:49 +00:00
DemonGatanjieuandClaude Opus 5.5 9f45fef85b feat(audio): explicit drop targets, drag hints and an in-app usage guide
- audio_node_targets.js is the only list of nodes the audio studio writes
  into: F5-TTS (Audio / Advanced / FromModel) takes a whole character, so the
  card header sets its main voice; ComfyUI's Load Audio takes one exact clip,
  so a row sets that file. Unlisted nodes are refused instead of matched by
  widget name, and a single emotion clip is never written into F5-TTS's
  sample (it would break {emotion} tags).
- While dragging, the hint says what releasing will do, or why a hovered node
  is refused and what to do instead (shared bindMaterialDrag targetHint /
  rejectHint).
- Script Director uses the same table and refuses nodes whose sample_audio is
  linked.
- In the audio domain the header "!" opens a five-step usage guide;
  docs/guides/audio-studio.md is the full guide (docs/guides is now tracked).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-24 11:43:31 +00:00
DemonGatanjieu ca32fe09ed Merge main (version in update guide) into feature/audio-voice-studio 2026-09-23 14:53:50 +00:00
DemonGatanjieuandClaude Opus 5.5 eabff31c1c fix(ui): show the version in the update guide instead of the sidebar footer
The footer version sat right under the tool dock and invited misclicks.
The "!" update guide now opens with the current version and a
"Check for updates / switch version" button that closes the guide and
opens the version panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-23 14:53:49 +00:00
DemonGatanjieu 7b79e2b7d9 Merge main (version number in sidebar footer) into feature/audio-voice-studio 2026-09-23 14:28:16 +00:00
DemonGatanjieuandClaude Opus 5.5 61b828c716 fix(ui): move the version number to the sidebar footer
In the header it pushed the dock and close buttons out of view when the
browser is docked or the display is scaled. It now sits under the tool
dock and hides with the collapsed sidebar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-23 14:28:16 +00:00
DemonGatanjieuandClaude Opus 5.5 49514025c2 Merge main (v1.58 version panel, docs) into feature/audio-voice-studio
Conflicts:
- api/__init__.py, web/styles.css: keep audio routes/styles and add the
  version manager.
- README.md, CHANGELOG.md: take main's released text; this branch's
  0922b27 was an earlier alignment of the same v1.57 notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-23 13:50:55 +00:00
DemonGatanjieuandClaude Opus 5.5 e622850349 feat: version panel with manual update check, switching and rollback
- api/version_manager.py: installed version (local only), published
  releases on request (GitHub API, git tag fallback), switch to a
  published tag, return to the default branch (fast-forward only), undo
  the last switch; refuses to overwrite modified tracked files
- header version chip and "Version & updates" panel; nothing goes online
  until "Check for updates" is clicked; restart via ComfyUI Manager
- zh/en strings, styles, architecture notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeQEub5
2026-09-23 13:42:58 +00:00
DemonGatanjieuandClaude Opus 5.5 c5eaca1dc4 Merge main (gallery search, model hash index fix) into feature/audio-voice-studio
Conflicts resolved:
- entry trigger files, web/main.js, api/__init__.py: main carries the squashed
  entry fix (09b06d1), identical to this branch before its later cleanup, so
  this branch's versions are kept
- ARCHITECTURE.md, docs/architecture/backend.md, web/modules/ui_sidebar.js:
  both sides' additions kept

Verified on the merged tree: 107 Python tests, all JS tests except the orphaned
material_parameter_cross_node.mjs, jsdom walkthroughs of the audio studio,
domain switching and the gallery search blocks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 10:08:10 +00:00
DemonGatanjieuandClaude Opus 5.5 e0776891c8 feat(gallery): turn search terms into visible, removable search blocks
Splitting the query on spaces hid how it was read and made phrases like
"cyberpunk city" impossible to search.

- ui_search_chips.js: Enter or a comma (also "," / "、" inserted by an IME)
  turns the typed text into a block; blocks keep their spaces and match as a
  phrase; hash-like and numeric blocks are labelled; × removes a block,
  Backspace in an empty box removes the last one, one button clears all; text
  still being typed joins the search after a short pause; IME composition
  never commits a block
- gallery_images accepts repeated `term` params (q still works)

Verified: tests/test_image_search.py (phrase blocks vs split query, 107 Python
tests in total) and a jsdom walkthrough of blocks, IME commas, backspace,
remove, clear and the request parameters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 10:00:05 +00:00
DemonGatanjieuandClaude Opus 5.5 1476fafd8a feat(gallery): search output images by prompt, model, seed and model hash
- api/image_search.py reads only the PNG text chunks before IDAT (ComfyUI
  prompt/workflow, A1111 parameters), builds one small record per image and
  caches it by mtime; all space-separated terms must match
- hex terms of 8+ characters also match SHA256 values recorded in the
  workflow (extra.anomalous_hashes) and local model files with that hash, so
  renamed models are still found; A1111 "Model hash" text matches as text
- gallery_images accepts q; the search box above the gallery debounces input,
  shows the match count, keeps paging/infinite scroll and the detail viewer on
  the filtered list, and lets a newer query supersede one still loading

On the local output (774 PNG) the first search reads ~10 MB of text chunks;
later searches use the cache.

Verified: tests/test_image_search.py (prompt, seed, AND terms, A1111, file
names, recorded and local-index hashes, cache, chunk reader), full Python suite
(106), jsdom walkthrough of the gallery search box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 10:00:00 +00:00
DemonGatanjieuandClaude Opus 5.5 b319fa1027 feat(audio): show each file's speech in the audio gallery and rescue unsaved previews
The gallery listed file names only, and audio from Preview Audio nodes (the
template used one) lives in ComfyUI's temp folder, so the gallery stayed empty.

- api/audio_metadata.py reads ComfyUI's `prompt` comment from FLAC and
  Ogg/Opus files (read-only) and extracts the TTS node's speech, sample, seed
- gallery rows show the speech (emotion chips, expandable per-segment script),
  voice and seed, with copy-speech; results are cached by mtime/size
- search (?q=) matches speech text and file names
- "unsaved previews" section lists temp audio with "save to gallery", which
  copies into output/audio/ (O_EXCL, never overwrites; the preview is untouched)
- audio_stream serves input/output/temp only; .opus is recognized
- parseTaggedSpeech in audio_script.js reads speech back the way F5-TTS splits it

Also outside the repo: ComfyUI/arona_multivoice_workflow.json now ends in a
Save Audio node (prefix audio/F5-TTS/Arona) instead of Preview Audio.

Verified: 100 Python tests (5 new gallery tests with synthetic FLAC/Opus),
tests/audio_script_rules.mjs, jsdom walkthrough (speech rows, preview save,
search, delete, paging), and a read-only run on the two real temp previews.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 09:24:05 +00:00
DemonGatanjieuandClaude Opus 5.5 f04c5d8f8c fix(audio): stop the Script Director from splitting off punctuation-only cards
Sentence splitting cut after every '…', so "嗯……" produced a card holding only
"…"; stacked marks ("?!") and closing quotes ("!」") were split off the same way.

- split only at 。!?!? and a lone '.' before whitespace; ellipses never split
- stacked end marks and trailing quotes/brackets stay with their sentence
- punctuation-only pieces (either split mode) are attached to a neighbour
- new ✂ button splits a card at the text cursor, complementing merge

Verified: tests/audio_script_rules.mjs (ellipsis, quotes, stacked marks,
punctuation-only lines, caret split) and a jsdom walkthrough of split/merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 09:11:51 +00:00
DemonGatanjieuandClaude Opus 5.5 a8e81beeb0 feat(audio): let Script Director users control segments (split mode, merge, add)
One card is one segment spoken with one emotion, so users need to decide where
segments start and end instead of relying only on punctuation splitting.

- split mode: by sentence (default) or one card per line
- merge a card with the next one (keeps this card's emotion); Latin words get a
  space, CJK text is joined directly
- "+ add segment" appends an empty card with the previous card's emotion and
  focuses it
- counts now read "segments"

Verified: tests/audio_script_rules.mjs (line mode, joinSegments), jsdom
walkthrough of merge/add/delete/line-mode re-parse/drag; 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
2026-09-23 09:05:54 +00:00
DemonGatanjieuandClaude Opus 5.5 d69507724e feat(audio): rework Script Director around per-line emotion cards and a draggable bundle
Assigning a voice used to mean selecting a line card and then clicking a voice
row in the studio behind the drawer, which was not discoverable.

- pick one character at the top (F5-TTS needs one main voice per script); the
  hint lists the emotions that character can voice
- after parsing, each line is a card with editable text, a preview button,
  delete, and a row of emotion chips (main / happy / ...); a choice the current
  character cannot voice stays visible and blocks the bundle instead of being
  silently reset
- the footer shows the bundled speech and offers copy, push to the selected or
  only F5TTSAudio node, and a handle to drag the bundle onto a node
- voice rows and the bundle both use the shared bindMaterialDrag (the browser
  hides while dragging, the target node is highlighted); the studio's own
  window drop listener and the row-click assignment path are removed
- bundling is pure (buildScriptPackage/usableEmotions in audio_script.js)

Verified: tests/audio_script_rules.mjs, jsdom walkthrough of parse -> chips ->
push -> character switch -> drag onto a node, domain navigation walkthrough;
other JS tests unchanged. 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
2026-09-23 08:55:37 +00:00
DemonGatanjieuandClaude Opus 5.5 fa0482393f chore(entry,docs): tidy trigger module and bring architecture docs back to contracts
- entry: one explicit legacy-coordinate cleanup instead of three module-load
  side effects, no ?v= import, shared size estimate and DEFAULT_MIN_SAFE_X
  instead of literals, drop unused exports; drag behavior unchanged
- explain the !important topbar-entry rules as AGENTS.md requires
- docs: restore the model_identity.py entry, describe the F5-TTS voice layout,
  ingestion guarantees, the no-cache/no-?v= module rule, the shared all-in-one
  adapter table and the no-cross-role prompt rule; remove pixel values and
  promotional wording, fix the contradictory trigger position text

Verified: tests/floating_trigger_position.mjs (9 pass), jsdom setup of the real
browser entry plus an audio-domain navigation walkthrough (outside the repo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 08:11:34 +00:00
DemonGatanjieuandClaude Opus 5.5 40195aa842 fix(recipes,materials): keep all-in-one support without guessing or crossing roles
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
2026-09-23 08:07:14 +00:00
DemonGatanjieuandClaude Opus 5.5 66979f698a fix(audio): align voices with ComfyUI-F5-TTS multi-voice layout and repair studio UI
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
2026-09-23 08:02:33 +00:00
DemonGatanjieuandClaude Opus 5.5 3ec4b1de61 chore(checkpoint): save uncommitted Script Director work from previous session
未完成/验证待完成:剧本台(ui_script_director.js、13-script-director.css)、
音频面板返回状态与 locales 文案来自上一轮会话,尚未验证。仅作为恢复点,
后续修复另行提交。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W411Z69FC3em9CzpeqEub5
2026-09-23 07:42:41 +00:00
DemonGatanjieu e6758759f2 fix(audio): eliminate browser media caching with timestamp cache-buster and HTTP no-cache headers 2026-09-23 00:10:40 +08:00