Fish-Speech emotion tags were silently ignored on non-English books: per-line emotions are LLM-generated in the book's own language, but Fish-Speech only recognizes English [tag] markers, and a double-tagging bug was stacking a broken server-derived tag on top of the client's own. Added a DE->EN translation table and removed the double-tagging. Also wires the existing book-profile context and race_species field into character portrait prompts (previously only used for voice design), adds a recast-until-threshold loop for casting, and adds backend-aware emotion quick-picks to Read Aloud, Try a Voice, and Conversation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
89 lines
6.2 KiB
HTML
89 lines
6.2 KiB
HTML
<div class="section-head">
|
|
<span class="section-icon"><span class="mdi mdi-swap-horizontal"></span></span>
|
|
<div class="section-title">
|
|
<h2>App Routing</h2>
|
|
<p>Map incoming requests from apps like Open WebUI or SillyTavern to specific voices and backends.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content" id="tab-routing">
|
|
<div class="card">
|
|
<h2>TTS voice routing</h2>
|
|
<p class="card-subtitle">Map incoming app voice names to real cloned voices and backends. Rules are matched top-to-bottom by app name, voice, and detected language.</p>
|
|
<div class="routing-help">
|
|
Recommended OpenAI-compatible TTS base URL: <code id="routing-proxy-url"></code>. If an app asks for the full speech endpoint instead of a base URL, use <code>/v1/audio/speech</code>.
|
|
Rules can turn an incoming app voice such as <code>default</code> into a real cloned voice before the request is sent to Qwen3-TTS.
|
|
The app name is read from request JSON fields <code>app</code>/<code>client</code>, headers such as <code>X-TTS-App</code>, or guessed from <code>User-Agent</code>/<code>Origin</code>. If a client cannot send that, use app <code>*</code> or give each app a unique incoming voice name.
|
|
For Open WebUI, set Audio → Text-to-Speech → Additional Parameters to <code>{"app":"Open WebUI"}</code> so these routes match explicitly. For Home Assistant, set the TTS agent base URL to this Creator proxy, not the direct Qwen backend, and use extra payload <code>{"app":"Home Assistant"}</code>. Use Response splitting <code>Punctuation</code> for lower perceived latency.
|
|
Backend chooses whether this route uses normal Voice Clone, low-latency Streaming, or Voice Design presets such as <code>vd_...</code>. Streaming routes cannot apply before/after sounds without buffering.
|
|
Language rules use lightweight text detection for EN, DE, FR, ES, IT, PT, NL, and PL.
|
|
Optional before/after sounds are audio files inside the configured voices folder, for example <code>sounds/start.wav</code>.
|
|
<div class="routing-url-warning" id="routing-url-warning">
|
|
<strong>Do not use <code>0.0.0.0</code> in Open WebUI.</strong>
|
|
Use this machine's LAN IP, hostname, or Docker service name instead.
|
|
</div>
|
|
</div>
|
|
<div class="routing-toolbar">
|
|
<button class="btn-secondary" id="routing-refresh-btn">Refresh</button>
|
|
<button class="btn-primary" id="routing-add-btn">Add route</button>
|
|
<button class="btn-green" id="routing-save-btn">Save routes</button>
|
|
<button class="btn-secondary" id="routing-add-openwebui-btn">Add Open WebUI default examples</button>
|
|
<span class="note" id="routing-status">No routes loaded.</span>
|
|
</div>
|
|
<div class="routing-test-row">
|
|
<input id="routing-test-app" value="Open WebUI" spellcheck="false" placeholder="App or *" title="Examples: Open WebUI, SillyTavern, Home Assistant">
|
|
<input id="routing-test-voice" value="default" spellcheck="false" placeholder="Incoming voice">
|
|
<textarea id="routing-test-text" placeholder="Type sample text to test language routing">Das ist ein kurzer deutscher Routing Test.</textarea>
|
|
<button class="btn-secondary" id="routing-test-btn">Test route</button>
|
|
</div>
|
|
<div class="routing-test-result" id="routing-test-result"></div>
|
|
</div>
|
|
<div class="card">
|
|
<div class="routing-grid routing-header">
|
|
<div>On</div><div>App</div><div>Input voice</div><div>Language</div>
|
|
<div>Backend</div><div>Output voice</div><div>Speed</div><div>Before sound</div><div>After sound</div><div></div>
|
|
</div>
|
|
<datalist id="routing-voice-options"></datalist>
|
|
<datalist id="routing-sound-options"></datalist>
|
|
<div id="routing-list" style="display:flex;flex-direction:column;gap:6px"></div>
|
|
</div>
|
|
<div class="card" id="routing-sound-browser" hidden>
|
|
<div class="routing-sound-browser-head">
|
|
<div>
|
|
<h2>Sound browser</h2>
|
|
<p class="card-subtitle" id="routing-sound-browser-note">Preview uploaded route sounds, then apply one as a before or after sound.</p>
|
|
</div>
|
|
<div class="routing-sound-browser-actions">
|
|
<button class="btn-secondary" id="routing-sound-refresh-btn" type="button">Refresh sounds</button>
|
|
<button class="btn-secondary" id="routing-sound-close-btn" type="button">Close</button>
|
|
</div>
|
|
</div>
|
|
<input id="routing-sound-search" class="routing-sound-search" type="search" placeholder="Search sounds, e.g. beep, alert, computer..." autocomplete="off">
|
|
<div class="routing-sound-list" id="routing-sound-list"></div>
|
|
<audio class="routing-sound-preview" id="routing-sound-preview" controls hidden></audio>
|
|
</div>
|
|
<div class="card">
|
|
<div class="routing-log-head">
|
|
<div>
|
|
<h2>Routing log</h2>
|
|
<p class="card-subtitle">Recent route tests and proxy requests. This log is kept in memory and resets when the server restarts.</p>
|
|
</div>
|
|
<div class="routing-log-actions">
|
|
<select id="routing-log-filter" class="routing-log-filter" title="Filter routing log entries">
|
|
<option value="all">All entries</option>
|
|
<option value="attention">Errors + no match</option>
|
|
<option value="error">Errors only</option>
|
|
<option value="no_match">No match only</option>
|
|
</select>
|
|
<button class="btn-secondary" id="routing-log-refresh-btn" type="button">Refresh log</button>
|
|
<button class="btn-secondary" id="routing-log-clear-btn" type="button">Clear log</button>
|
|
</div>
|
|
</div>
|
|
<div class="routing-log-scroll">
|
|
<div class="routing-log-list" id="routing-log-list">
|
|
<div class="routing-log-empty">No routing log entries yet.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div><!-- /tab-routing -->
|