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
62 lines
2.7 KiB
JavaScript
62 lines
2.7 KiB
JavaScript
import { t } from './interface_settings.js';
|
|
|
|
/**
|
|
* Domain Switcher component (Visual Studio <-> Audio & Voice Studio)
|
|
* Ultra-compact 26x26px icon button matching Anomalous Browser shell standards.
|
|
*/
|
|
|
|
const STORAGE_KEY = 'anomalous_active_domain';
|
|
|
|
const SVG_ICONS = {
|
|
// Elegant waveform / microphone for audio mode
|
|
AUDIO: `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/></svg>`,
|
|
// Elegant palette / grid for visual mode
|
|
VISUAL: `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>`
|
|
};
|
|
|
|
export function getActiveDomain() {
|
|
try {
|
|
return localStorage.getItem(STORAGE_KEY) === 'audio' ? 'audio' : 'visual';
|
|
} catch (_) {
|
|
return 'visual';
|
|
}
|
|
}
|
|
|
|
export function setActiveDomain(domain) {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, domain === 'audio' ? 'audio' : 'visual');
|
|
} catch (_) {
|
|
// Private windows may refuse storage; the switch still applies to this page.
|
|
}
|
|
}
|
|
|
|
export function createDomainSwitcher(browser) {
|
|
const container = document.createElement('div');
|
|
container.id = 'anomalous-domain-switcher';
|
|
|
|
const toggleBtn = document.createElement('button');
|
|
toggleBtn.className = 'anomalous-domain-toggle-btn';
|
|
toggleBtn.type = 'button';
|
|
|
|
function updateButtonState(domain) {
|
|
const isAudio = domain === 'audio';
|
|
toggleBtn.innerHTML = isAudio ? SVG_ICONS.AUDIO : SVG_ICONS.VISUAL;
|
|
toggleBtn.title = t(isAudio ? 'domainSwitchToVisual' : 'domainSwitchToAudio');
|
|
toggleBtn.setAttribute('aria-label', toggleBtn.title);
|
|
toggleBtn.classList.toggle('is-audio', isAudio);
|
|
}
|
|
|
|
updateButtonState(getActiveDomain());
|
|
|
|
toggleBtn.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
const nextDomain = getActiveDomain() === 'visual' ? 'audio' : 'visual';
|
|
setActiveDomain(nextDomain);
|
|
updateButtonState(nextDomain);
|
|
browser.handleDomainChange?.(nextDomain);
|
|
});
|
|
|
|
container.appendChild(toggleBtn);
|
|
return container;
|
|
}
|