tts-voice-creator-clone-and.../static/sections/s-settings.html
mARTin-B78 90cc7b7eb1 AI Backends: local service connect/disconnect, Docker container management, 0.0.0.0 probe fix
- Add initLlmsSection() IIFE to app.js: copy buttons, API key persistence with eye toggle
  and saved badge, local service URL persistence, Connect/Disconnect toggle with server-side
  probe via /api/probe-url (avoids CORS), card turns green on success / red on failure
- Substitute 0.0.0.0 → host.docker.internal before probing (0.0.0.0 not routable from Docker)
- Add /api/local-containers, /api/probe-url, start/stop/restart endpoints to server.py
- Rewrite AI Backends section into Local / Online API categories with Docker stack grid,
  local service cards (LLM/STT/TTS) with icons and editable URL inputs, online cloud API cards
- Add bind mounts for static/ and server.py so changes take effect without image rebuild
- Add dc-grid, llm-local-grid CSS with uniform minmax(310px,1fr) card layout
- Fix VOICE_HOST_DIR default via .env so voice folders survive container recreation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:35:42 +02:00

246 lines
13 KiB
HTML

<div class="section-head">
<span class="section-icon">&#9881;</span>
<div class="section-title">
<h2>Settings</h2>
<p>Configure backend URLs, API keys, voice folders, and playback preferences.</p>
</div>
</div>
<div class="tab-content" id="tab-settings">
<div class="card" id="settings-box">
<div class="settings-title-row">
<div>
<h2>Settings</h2>
<p class="card-subtitle">Configure the service URLs you actually use first. Advanced payloads, folders, and keys are tucked away below.</p>
</div>
<div class="settings-status-pill">Local stack</div>
</div>
<div class="setup-intro settings-checklist" id="settings-first-run-note">
<strong>Quick setup</strong>
<span>1. Check core TTS URLs.</span>
<span>2. Point STT at Whisper, Parakeet, or the NVIDIA router.</span>
<span>3. Save settings.</span>
</div>
<section class="settings-section settings-section-primary">
<div class="settings-section-head">
<div>
<h3>Core connections</h3>
<p>These are the endpoints you change most often. Qwen3 TTS, NVIDIA TTS, and STT are grouped separately.</p>
</div>
</div>
<div class="settings-cluster-grid">
<div class="settings-cluster">
<div class="settings-cluster-head">
<strong>TTS Text to Speech</strong>
<span>Qwen3 engines: clone, design, custom, streaming</span>
</div>
<div class="settings-grid compact">
<div class="s-field">
<label>Voice Clone/Base URL <span style="font-weight:400">(WAV voices)</span></label>
<input type="text" id="s-tts-url" placeholder="http://host.docker.internal:8020">
<span class="s-hint">Uploaded/cloned WAV voices. Expected: <code>POST /v1/audio/speech</code>.</span>
</div>
<div class="s-field">
<label>Voice Design URL <span style="font-weight:400">(instruction voices)</span></label>
<input type="text" id="s-voice-design-url" placeholder="http://host.docker.internal:8021">
<span class="s-hint">Prompt-designed voices and <code>vd_...</code> virtual voices.</span>
</div>
<div class="s-field">
<label>CustomVoice URL</label>
<input type="text" id="s-customvoice-url" placeholder="http://host.docker.internal:8022">
<span class="s-hint">Style over configured speakers such as Ryan, Vivian, Serena.</span>
</div>
<div class="s-field">
<label>Streaming URL</label>
<input type="text" id="s-tts-stream-url" placeholder="http://host.docker.internal:8023">
<span class="s-hint">Progressive low-latency WAV playback.</span>
</div>
</div>
</div>
<div class="settings-cluster">
<div class="settings-cluster-head">
<strong>NVIDIA speech stack</strong>
<span>router, Magpie TTS, Parakeet ASR, clone NIM</span>
</div>
<div class="settings-grid compact">
<div class="s-field">
<label>NVIDIA router URL <span style="font-weight:400">(TTS + STT)</span></label>
<input type="text" id="s-nvidia-router-url" placeholder="http://host.docker.internal:8090">
<span class="s-hint">OpenAI-compatible base URL for the NVIDIA speech router.</span>
</div>
<div class="s-field">
<label>NVIDIA Magpie TTS URL</label>
<input type="text" id="s-nvidia-tts-url" placeholder="http://host.docker.internal:8091">
<span class="s-hint">Direct Magpie endpoint. Fixed speakers, not WAV cloning.</span>
</div>
<div class="s-field">
<label>NVIDIA Parakeet ASR URL</label>
<input type="text" id="s-nvidia-asr-url" placeholder="http://host.docker.internal:8092">
<span class="s-hint">Direct Parakeet endpoint for transcription.</span>
</div>
<div class="s-field">
<label>NVIDIA Zeroshot NIM URL</label>
<input type="text" id="s-nvidia-zeroshot-url" placeholder="http://host.docker.internal:8093">
<span class="s-hint">Magpie Zeroshot clone endpoint with <code>audio_prompt</code>.</span>
</div>
<div class="s-field">
<label>NVIDIA Flow NIM URL</label>
<input type="text" id="s-nvidia-flow-url" placeholder="http://host.docker.internal:8094">
<span class="s-hint">Magpie Flow clone endpoint with <code>audio_prompt</code> and transcript.</span>
</div>
</div>
</div>
<div class="settings-cluster settings-cluster-stt">
<div class="settings-cluster-head">
<strong>STT Speech to Text</strong>
<span>Whisper, Parakeet, or NVIDIA router</span>
</div>
<div class="settings-grid compact stt-settings-grid">
<div class="s-field stt-url-field">
<label>Whisper/STT URL</label>
<input type="text" id="s-whisper-url" placeholder="http://host.docker.internal:8010">
<span class="s-hint">Reference text recognition. Expected: <code>POST /v1/audio/transcriptions</code>.</span>
<div class="btn-row settings-mini-actions">
<button class="btn-secondary" id="s-use-parakeet-asr" type="button">Use Parakeet</button>
<button class="btn-secondary" id="s-use-nvidia-router" type="button">Use router</button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="settings-section">
<div class="settings-section-head">
<div>
<h3>Playback behavior</h3>
<p>Small behavior switches for previews and OpenAI-compatible TTS calls.</p>
</div>
</div>
<div class="settings-grid settings-behavior-grid">
<div class="s-field">
<label>TTS preview playback</label>
<select id="s-tts-stream-mode">
<option value="auto">Stream when available, then fall back</option>
<option value="streaming">Streaming only</option>
<option value="buffered">Buffered WAV only</option>
</select>
<span class="s-hint">Buffered keeps Save WAV available. Streaming starts sooner.</span>
</div>
<div class="s-field">
<label>OpenAI-compatible request style</label>
<select id="s-tts-backend">
<option value="openai">Qwen3-TTS / OpenAI</option>
<option value="localai">LocalAI (/tts)</option>
<option value="pocket">Pocket-TTS</option>
<option value="nvidia_magpie">NVIDIA Magpie / OpenAI</option>
</select>
<span class="s-hint">Controls payload shape for the normal TTS API URL.</span>
</div>
</div>
</section>
<details class="settings-details">
<summary>
<span>Advanced request payloads</span>
<small>JSON extras sent to each backend</small>
</summary>
<div class="settings-grid three settings-param-grid">
<div class="s-field">
<label>Voice Clone/Base params</label>
<textarea id="s-tts-extra-voice-clone" spellcheck="false" placeholder='{"temperature":0.1,"top_p":0.8,"seed":0}'></textarea>
<span class="s-hint">Extra fields for the 8020 WAV voice clone/base model.</span>
</div>
<div class="s-field">
<label>Streaming params</label>
<textarea id="s-tts-extra-streaming" spellcheck="false" placeholder='{"temperature":0.1,"top_p":0.8,"seed":0}'></textarea>
<span class="s-hint">Extra fields for the 8023 streaming model.</span>
</div>
<div class="s-field">
<label>CustomVoice params</label>
<textarea id="s-tts-extra-customvoice" spellcheck="false" placeholder='{"temperature":0.1,"top_p":0.8,"seed":0}'></textarea>
<span class="s-hint">Extra fields for the CustomVoice backend.</span>
</div>
<div class="s-field">
<label>Voice Design params</label>
<textarea id="s-tts-extra-voice-design" spellcheck="false" placeholder='{"temperature":0.1,"top_p":0.8,"seed":0}'></textarea>
<span class="s-hint">Extra fields for Voice Design and virtual <code>vd_...</code> voices.</span>
</div>
<div class="s-field">
<label>NVIDIA Magpie params</label>
<textarea id="s-tts-extra-nvidia-magpie" spellcheck="false" placeholder="{}"></textarea>
<span class="s-hint">Usually empty. Magpie accepts fixed speaker voices such as sofia, aria, jason, leo, and john.</span>
</div>
<div class="s-field">
<label>NVIDIA Zeroshot params</label>
<textarea id="s-tts-extra-nvidia-zeroshot" spellcheck="false" placeholder='{"zero_shot_quality":20}'></textarea>
<span class="s-hint">Optional multipart fields. The app supplies <code>text</code>, <code>language</code>, and <code>audio_prompt</code>.</span>
</div>
<div class="s-field">
<label>NVIDIA Flow params</label>
<textarea id="s-tts-extra-nvidia-flow" spellcheck="false" placeholder="{}"></textarea>
<span class="s-hint">Optional multipart fields. The app also sends the saved reference transcript.</span>
</div>
</div>
</details>
<details class="settings-details">
<summary>
<span>Voice folders</span>
<small>container paths and Portainer volume mounts</small>
</summary>
<div class="settings-grid">
<div class="s-field">
<label>Voice scan directory</label>
<input type="text" id="s-voices-scan-dir" placeholder="/voices">
<span class="s-hint">Contains <code>active_voices</code>, <code>hidden_voices</code>, sounds, and metadata.</span>
</div>
<div class="s-field">
<label>Active voices directory</label>
<input type="text" id="s-output-dir" placeholder="/voices/active_voices">
<span class="s-hint">New cloned/exported voices are saved here.</span>
</div>
</div>
</details>
<details class="settings-details">
<summary>
<span>API keys</span>
<small>usually empty for local containers</small>
</summary>
<div class="settings-grid three">
<div class="s-field">
<label>TTS API key <span style="font-weight:400">(optional)</span></label>
<div class="s-key-row">
<input type="password" id="s-tts-key" placeholder="dummy, sk-local, or leave empty" autocomplete="off">
<button type="button" class="s-eye-btn" data-target="s-tts-key">&#128065;</button>
</div>
</div>
<div class="s-field">
<label>Voice Design API key <span style="font-weight:400">(optional)</span></label>
<div class="s-key-row">
<input type="password" id="s-vd-key" placeholder="dummy, sk-local, or leave empty" autocomplete="off">
<button type="button" class="s-eye-btn" data-target="s-vd-key">&#128065;</button>
</div>
</div>
<div class="s-field">
<label>Whisper API key <span style="font-weight:400">(optional)</span></label>
<div class="s-key-row">
<input type="password" id="s-whisper-key" placeholder="dummy, sk-local, or leave empty" autocomplete="off">
<button type="button" class="s-eye-btn" data-target="s-whisper-key">&#128065;</button>
</div>
</div>
</div>
</details>
<div class="btn-row settings-actions">
<button class="btn-primary" id="s-save-btn">Save settings</button>
<button class="btn-secondary" id="s-close-btn">Reload settings</button>
</div>
</div>
</div><!-- /tab-settings -->