tts-voice-creator-clone-and.../static/sections/s-tryout.html
mARTin-B78 5fecbf06d4 Fix Fish-Speech emotion tags, wire book context into portraits, add emotion controls app-wide (v1.20.5)
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>
2026-08-11 18:02:41 +02:00

309 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="section-head">
<span class="section-icon"><span class="mdi mdi-play"></span></span>
<div class="section-title">
<h2>Try It Out</h2>
<p>Generate speech from text using any backend and voice. Also transcribe audio and re-speak it.</p>
</div>
</div>
<!-- TTS Generation Playground -->
<div class="tab-content" id="tab-generation">
<!-- ① Voice selection ─────────────────────────────────────────── -->
<div class="card" style="padding:14px">
<h2><span class="mdi mdi-account-voice"></span> Voice &amp; playback</h2>
<div class="engine-setup-row" style="margin-bottom:8px">
<div class="engine-setup-col" style="flex:1">
<label class="engine-setup-label"><span class="mdi mdi-account-voice"></span> Text to Speech <a href="#" class="engine-setup-link" onclick="navTo('s-llms'); navEnginesCat('tts'); return false;" title="Configure Text to Speech settings"><span class="mdi mdi-cog-outline"></span></a></label>
<div class="engine-setup-controls">
<select id="tts-backend-select" aria-label="TTS backend"><option value="">Checking...</option></select>
<button class="btn-secondary" id="fetch-tts-voices-btn" title="Fetch available voices"><span class="mdi mdi-refresh"></span></button>
<select id="tts-voice-select" aria-label="Voice"><option value="">— fetch voices —</option></select>
</div>
</div>
<div class="engine-setup-col no-border" style="flex:0.5">
<label class="engine-setup-label"><span class="mdi mdi-tune"></span> Playback</label>
<div class="engine-setup-controls">
<select id="preview-playback-mode" aria-label="Playback mode">
<option value="settings">Settings default</option>
<option value="streaming">Streaming only</option>
<option value="auto">Stream with fallback</option>
<option value="buffered">Buffered WAV</option>
</select>
</div>
</div>
</div>
<div class="backend-help" id="tts-backend-help" aria-live="polite" style="padding-left:14px">
<strong>Checking available TTS backends…</strong>
</div>
<!-- Reference voice panel (shown when the selected voice matches the library) -->
<div class="preview-match-panel" id="preview-match-panel" hidden style="margin-top:12px">
<div class="preview-match-meta">
<div class="preview-match-title" id="preview-match-title">Reference voice</div>
<div class="preview-match-detail" id="preview-match-detail"></div>
<div class="preview-match-warning" id="preview-match-warning"></div>
<div class="preview-match-actions">
<button class="btn-secondary" id="preview-ref-play" type="button">Play reference WAV</button>
<button class="btn-secondary" id="preview-ref-use-text" type="button">Use reference text</button>
<button class="btn-primary" id="preview-ref-synth" type="button">Synthesize reference text</button>
</div>
</div>
<div class="preview-match-meta">
<div class="preview-match-transcript" id="preview-match-transcript">No reference text saved for this voice.</div>
<audio id="preview-ref-audio" controls></audio>
</div>
</div>
</div>
<!-- ② Text & style ────────────────────────────────────────────── -->
<div class="card">
<h2><span class="mdi mdi-text-long"></span> Text to synthesize</h2>
<div class="field">
<textarea id="preview-text-area" placeholder="Enter the text you want to synthesize…" style="min-height:120px">Hello! This is a voice preview from TTS Voice Creator - Clone and Design.</textarea>
</div>
<div class="field" style="margin-top:10px">
<label style="display:flex;align-items:center;gap:8px">
Emotion
<span style="font-weight:400;color:var(--subtext)">(optional — quick pick)</span>
</label>
<select id="preview-emotion-select">
<option value="">— none / type your own below —</option>
</select>
<span id="preview-emotion-help" class="note" style="display:none;margin-top:4px"></span>
</div>
<div class="field" style="margin-top:10px">
<label style="display:flex;align-items:center;gap:8px">
Style instruction
<span style="font-weight:400;color:var(--subtext)">(optional)</span>
<span id="preview-style-support" class="backend-tag" style="font-size:11px;display:none"></span>
</label>
<input type="text" id="preview-style-instruction" placeholder="e.g. whisper softly, sound excited, speak very slowly">
<span id="preview-style-warn" class="note" style="color:var(--yellow);display:none">
<span class="mdi mdi-alert-outline"></span> The selected backend has <strong>weak style support</strong> — this instruction may be ignored. Switch to a <em>style-aware</em> backend (CustomVoice, VoiceDesign) for full effect.
</span>
</div>
<div class="field" style="margin-top:10px;display:flex;align-items:center;gap:12px">
<label style="white-space:nowrap;font-weight:500">Native Speed <span class="note">(0.52)</span></label>
<input type="number" id="preview-native-speed" min="0.5" max="2" step="0.05" value="1" placeholder="1.0" autocomplete="off" style="width:80px">
</div>
<div class="btn-row" style="gap:20px;margin-top:8px">
<label class="chunk-toggle-label" title="Rewrite text through this voice's character persona before generating">
<input type="checkbox" id="preview-persona-toggle">
<span>Apply character persona</span>
<span class="note" style="margin-left:2px">(LLM rewrite)</span>
</label>
<label class="chunk-toggle-label" title="Split long text at sentence boundaries and stitch chunks together">
<input type="checkbox" id="preview-chunked-toggle">
<span>Chunked generation</span>
<span class="note" style="margin-left:2px">(long text)</span>
</label>
</div>
</div>
<!-- ③ Generate ─────────────────────────────────────────────────── -->
<div class="card">
<div class="btn-row" style="gap:10px;flex-wrap:wrap">
<button class="btn-primary" id="preview-btn" style="padding:10px 24px;font-size:15px"><span class="mdi mdi-play"></span> Generate &amp; play</button>
<button class="btn-secondary" id="save-preview-mp3-btn" disabled><span class="mdi mdi-download"></span> Save MP3</button>
<button class="btn-secondary" id="save-preview-btn" disabled><span class="mdi mdi-download"></span> Save WAV</button>
<button class="btn-secondary" id="add-to-playlist-btn" disabled><span class="mdi mdi-plus"></span> Playlist</button>
</div>
<audio id="preview-audio" controls style="display:none;margin-top:12px;width:100%"></audio>
<div id="preview-chunk-progress" class="chunk-progress" hidden></div>
<p class="note" style="margin-top:8px">After changing active voices, restart the TTS container so the engine reads the updated voice folder.</p>
</div>
<!-- Audio Effects -->
<div class="card" id="effects-card">
<h2>Audio effects</h2>
<p class="card-subtitle">Apply post-processing to the last generated audio. Non-destructive — re-generate to reset.</p>
<div class="effects-preset-row">
<label class="field-label-sm">Preset</label>
<select id="effects-preset" aria-label="Effects preset">
<option value="">— Custom —</option>
<option value="studio">Studio Reverb</option>
<option value="broadcast">Broadcast (compressed)</option>
<option value="telephone">Telephone</option>
<option value="warm">Warm &amp; Intimate</option>
<option value="radio">Radio Voice</option>
</select>
<button class="btn-secondary btn-sm" id="effects-reset-btn">Reset</button>
</div>
<div class="effects-grid">
<div class="fx-row">
<label class="fx-toggle"><input type="checkbox" id="fx-reverb-on"> Reverb</label>
<div class="fx-sliders" id="fx-reverb-params">
<label>Room <input type="range" id="fx-reverb-room" min="0" max="1" step="0.01" value="0.35"><span id="fx-reverb-room-val">0.35</span></label>
<label>Wet <input type="range" id="fx-reverb-wet" min="0" max="1" step="0.01" value="0.25"><span id="fx-reverb-wet-val">0.25</span></label>
</div>
</div>
<div class="fx-row">
<label class="fx-toggle"><input type="checkbox" id="fx-compressor-on"> Compressor</label>
<div class="fx-sliders" id="fx-compressor-params">
<label>Threshold <input type="range" id="fx-comp-thresh" min="-60" max="0" step="1" value="-20"><span id="fx-comp-thresh-val">-20 dB</span></label>
<label>Ratio <input type="range" id="fx-comp-ratio" min="1" max="20" step="0.5" value="4"><span id="fx-comp-ratio-val">4:1</span></label>
</div>
</div>
<div class="fx-row">
<label class="fx-toggle"><input type="checkbox" id="fx-chorus-on"> Chorus</label>
<div class="fx-sliders" id="fx-chorus-params">
<label>Rate <input type="range" id="fx-chorus-rate" min="0.1" max="5" step="0.1" value="1"><span id="fx-chorus-rate-val">1.0 Hz</span></label>
<label>Mix <input type="range" id="fx-chorus-mix" min="0" max="1" step="0.01" value="0.5"><span id="fx-chorus-mix-val">0.50</span></label>
</div>
</div>
<div class="fx-row">
<label class="fx-toggle"><input type="checkbox" id="fx-pitch-on"> Pitch shift</label>
<div class="fx-sliders" id="fx-pitch-params">
<label>Semitones <input type="range" id="fx-pitch-semi" min="-12" max="12" step="0.5" value="0"><span id="fx-pitch-semi-val">0 st</span></label>
</div>
</div>
<div class="fx-row">
<label class="fx-toggle"><input type="checkbox" id="fx-bandpass-on"> Bandpass (telephone/radio)</label>
<div class="fx-sliders" id="fx-bandpass-params">
<label>Low cut <input type="range" id="fx-bandpass-low" min="20" max="1000" step="10" value="300"><span id="fx-bandpass-low-val">300 Hz</span></label>
<label>High cut <input type="range" id="fx-bandpass-high" min="1000" max="12000" step="100" value="3400"><span id="fx-bandpass-high-val">3400 Hz</span></label>
</div>
</div>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn-primary" id="effects-apply-btn" disabled>Apply effects</button>
<span class="note" id="effects-status"></span>
</div>
</div>
<!-- Generation History -->
<div class="card" id="history-card">
<h2>Generation history</h2>
<p class="card-subtitle">Last 20 generations this session. Audio is preserved in memory until you reload.</p>
<div id="history-list" class="history-list">
<div class="history-empty">No generations yet.</div>
</div>
<div class="btn-row" style="margin-top:8px">
<button class="btn-secondary btn-sm" id="history-clear-btn">Clear history</button>
</div>
</div>
<!-- Playlist -->
<div class="card" id="playlist-card">
<h2>Playlist</h2>
<p class="card-subtitle">Queue clips from history. Reorder by dragging, then export as one merged WAV.</p>
<div id="playlist-list" class="playlist-list">
<div class="history-empty">No clips in playlist. Use <strong>+ Playlist</strong> after generating.</div>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn-primary" id="playlist-export-btn" disabled><span class="mdi mdi-download"></span> Export merged WAV</button>
<button class="btn-secondary btn-sm" id="playlist-clear-btn">Clear</button>
</div>
</div>
</div><!-- /tab-generation -->
<!-- STT -> TTS -->
<div class="tab-content" id="tab-stt-tts">
<div class="card">
<h2>STT <span class="mdi mdi-arrow-right"></span> TTS workspace</h2>
<p class="card-subtitle">Upload speech audio, transcribe it with the configured STT endpoint, then synthesize the resulting text with any available TTS backend.</p>
</div>
<div class="card">
<h2>Source speech</h2>
<p class="card-subtitle">Record from your microphone or upload an audio file, then transcribe it.</p>
<div class="settings-grid">
<div class="s-field">
<label>Speech recognition</label>
<div style="display:flex;gap:8px">
<select id="stt-tts-stt-backend" aria-label="Speech-to-text engine"><option value="configured">Configured Whisper/STT</option></select>
<button class="btn-secondary" id="stt-tts-refresh-stt-btn" type="button">Refresh</button>
</div>
<div class="s-hint" id="stt-tts-stt-help">Uses Settings &rarr; Whisper/STT URL by default.</div>
</div>
<div class="s-field">
<label>Speech audio</label>
<div class="btn-row" style="gap:8px;align-items:center">
<input type="file" id="stt-tts-file" aria-label="Audio file to transcribe" accept="audio/*,video/*">
<button class="btn-secondary" id="stt-tts-rec-start" type="button" title="Record from microphone"><span class="mdi mdi-microphone-variant"></span> Record</button>
<button class="btn-secondary" id="stt-tts-rec-stop" type="button" disabled>Stop</button>
<span class="mic-timer" id="stt-tts-rec-time">0:00</span>
</div>
<span class="s-hint">Record or upload speech audio, then transcribe it with the selected recognition engine.</span>
</div>
<div class="s-field">
<label>Source preview</label>
<audio id="stt-tts-source-audio" controls style="display:none;width:100%"></audio>
<span class="s-hint" id="stt-tts-source-status">No source audio loaded.</span>
</div>
</div>
<div class="btn-row">
<button class="btn-secondary" id="stt-tts-transcribe-btn" disabled>Transcribe</button>
<button class="btn-secondary" id="stt-tts-copy-preview-btn" disabled>Copy to TTS playground</button>
</div>
<div class="field">
<label>Transcribed text</label>
<textarea id="stt-tts-text" placeholder="Transcribed text appears here. Edit before synthesis if needed."></textarea>
</div>
</div>
<!-- LLM Refinement card -->
<div class="card" id="refine-card">
<h2>Refine with LLM</h2>
<p class="card-subtitle">Clean up the transcription using a local language model — remove fillers, fix repetitions, and normalise punctuation.</p>
<div class="engine-setup-row" style="margin-bottom:12px; padding:10px 12px">
<div class="engine-setup-col" style="flex:1">
<label class="engine-setup-label"><span class="mdi mdi-brain"></span> Language Model <a href="#" class="engine-setup-link" onclick="navTo('s-llms'); navEnginesCat('llm'); return false;" title="Configure Language Model settings"><span class="mdi mdi-cog-outline"></span></a></label>
<div class="engine-setup-controls">
<input type="text" id="refine-llm-url" placeholder="http://localhost:11434/v1" spellcheck="false" title="OpenAI-compatible endpoint (Ollama, LM Studio, vLLM...)">
<input type="text" id="refine-model" placeholder="auto-detect model" style="max-width:140px">
</div>
</div>
</div>
<div class="refine-toggles">
<label class="refine-toggle"><input type="checkbox" id="refine-fillers" checked> Remove fillers</label>
<label class="refine-toggle"><input type="checkbox" id="refine-repetitions" checked> Fix repetitions</label>
<label class="refine-toggle"><input type="checkbox" id="refine-corrections" checked> Remove corrections</label>
<label class="refine-toggle"><input type="checkbox" id="refine-punctuation" checked> Fix punctuation</label>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn-primary" id="refine-btn" disabled><span class="mdi mdi-auto-fix"></span> Refine transcription</button>
<button class="btn-secondary" id="refine-restore-btn" disabled>Restore original</button>
<span class="note" id="refine-status"></span>
</div>
</div>
<div class="card">
<h2>Synthesize transcription</h2>
<p class="card-subtitle">Choose a TTS backend and voice, then generate audio from the transcribed text.</p>
<div class="engine-setup-row" style="margin-bottom:12px; padding:10px 12px">
<div class="engine-setup-col" style="flex:1">
<label class="engine-setup-label"><span class="mdi mdi-account-voice"></span> Text to Speech <a href="#" class="engine-setup-link" onclick="navTo('s-llms'); navEnginesCat('tts'); return false;" title="Configure Text to Speech settings"><span class="mdi mdi-cog-outline"></span></a></label>
<div class="engine-setup-controls">
<select id="stt-tts-backend-select" aria-label="TTS backend"><option value="">Checking backends...</option></select>
<button class="btn-secondary" id="stt-tts-fetch-voices-btn" title="Fetch voices"><span class="mdi mdi-refresh"></span></button>
<select id="stt-tts-voice-select" aria-label="Voice"><option value="">-- select voices --</option></select>
</div>
</div>
<div class="engine-setup-col no-border" style="flex:0.5">
<label class="engine-setup-label"><span class="mdi mdi-tune"></span> Playback</label>
<div class="engine-setup-controls">
<select id="stt-tts-playback-mode" aria-label="Playback mode">
<option value="settings">Settings default</option>
<option value="streaming">Streaming only</option>
<option value="auto">Stream with fallback</option>
<option value="buffered">Buffered WAV</option>
</select>
</div>
</div>
</div>
<div class="backend-help" id="stt-tts-backend-help" aria-live="polite" style="margin-bottom:10px">
<strong>Checking available TTS backends...</strong>
</div>
<div class="field">
<label>Style Instruction <span style="font-weight:400">(optional)</span></label>
<input type="text" id="stt-tts-style-instruction" placeholder="Optional style/emotion instruction">
</div>
<div class="btn-row">
<button class="btn-primary" id="stt-tts-generate-btn">Generate &amp; play</button>
<button class="btn-secondary" id="stt-tts-save-mp3-btn" disabled>Save MP3</button>
<button class="btn-secondary" id="stt-tts-save-wav-btn" disabled>Save WAV</button>
</div>
<audio id="stt-tts-output-audio" controls style="display:none"></audio>
</div>
</div><!-- /tab-stt-tts -->