tts-voice-creator-clone-and.../static/index.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

112 lines
6.0 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TTS Voice Creator</title>
<!-- WaveSurfer must load synchronously before app.js initialises audio -->
<script src="https://unpkg.com/wavesurfer.js@7/dist/wavesurfer.min.js"></script>
<script src="https://unpkg.com/wavesurfer.js@7/dist/plugins/regions.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flag-icons@7.3.2/css/flag-icons.min.css">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<!-- Hidden tabs nav — required for JS backend availability detection -->
<nav class="tabs" style="display:none" aria-hidden="true">
<div class="tab active" data-tab="library" data-backend-required="voice_clone" tabindex="-1"><span class="tab-title">Voice Clone</span></div>
<div class="tab" data-tab="design" data-backend-required="voice_design" tabindex="-1"><span class="tab-title">Voice Design</span></div>
<div class="tab" data-tab="custom" data-backend-required="customvoice" tabindex="-1"><span class="tab-title">Voice Custom</span></div>
<div class="tab" data-tab="generation" data-backend-required="any_tts" tabindex="-1"><span class="tab-title">TTS Generation</span></div>
<div class="tab" data-tab="stt-tts" data-backend-required="any_tts" tabindex="-1"><span class="tab-title">STT-TTS</span></div>
<div class="tab" data-tab="performance" data-backend-required="any_tts" tabindex="-1"><span class="tab-title">Performance</span></div>
<div class="tab" data-tab="routing" tabindex="-1"><span class="tab-title">Routing</span></div>
<div class="tab" data-tab="integrations" tabindex="-1"><span class="tab-title">How to</span></div>
<div class="tab" data-tab="getvoices" tabindex="-1"><span class="tab-title">Get Voices</span></div>
<div class="tab" data-tab="settings" tabindex="-1"><span class="tab-title">Settings</span></div>
</nav>
<!-- App shell -->
<div id="app-shell">
<!-- Sidebar -->
<aside id="sidebar">
<div class="sidebar-brand">
<h1>&#127908; Voice Creator</h1>
<p>Clone &middot; Design &middot; Deploy</p>
</div>
<nav class="sidebar-nav">
<div class="nav-group-label">Voices</div>
<div class="nav-item nav-tree-head active" data-nav-section="s-voices" id="nav-voices-head" onclick="navTo('s-voices')">
<span class="nav-icon">&#128266;</span>
<span class="nav-label">My Voices</span>
<span class="nav-badge" id="nav-voices-count"></span>
<span class="nav-chevron" id="nav-voices-chevron">&#8964;</span>
</div>
<div class="nav-tree open" id="nav-voices-tree">
<div class="nav-tree-item is-active" data-voice-cat="all" onclick="navVoicesCat('all')">All voices <span class="ntc" id="ntc-all"></span></div>
<div class="nav-tree-item" data-voice-cat="cloned" onclick="navVoicesCat('cloned')">Cloned <span class="ntc" id="ntc-cloned"></span></div>
<div class="nav-tree-item" data-voice-cat="designed" onclick="navVoicesCat('designed')">Designed <span class="ntc" id="ntc-designed"></span></div>
<div class="nav-tree-item" data-voice-cat="favorites" onclick="navVoicesCat('favorites')">Favorites <span class="ntc" id="ntc-favorites"></span></div>
<div class="nav-tree-item" data-voice-cat="hidden" onclick="navVoicesCat('hidden')">Hidden <span class="ntc" id="ntc-hidden"></span></div>
<div class="nav-tree-item" data-voice-cat="tools" onclick="navVoicesCat('tools')">Library tools</div>
</div>
<div class="nav-item" data-nav-section="s-clone" onclick="navTo('s-clone')">
<span class="nav-icon">&#127908;</span> Clone a Voice
</div>
<div class="nav-item" data-nav-section="s-design" onclick="navTo('s-design')">
<span class="nav-icon">&#10024;</span> Design a Voice
</div>
<div class="nav-item" data-nav-section="s-studio" onclick="navTo('s-studio')">
<span class="nav-icon">&#127760;</span> Get Voices Online
</div>
<div class="nav-item" data-nav-section="s-tryout" onclick="navTo('s-tryout')">
<span class="nav-icon">&#9654;</span> Try It Out
</div>
<div class="nav-group-label" style="margin-top:6px">Setup</div>
<div class="nav-item" data-nav-section="s-llms" onclick="navTo('s-llms')">
<span class="nav-icon">&#129504;</span> LLMs
</div>
<div class="nav-item" data-nav-section="s-routing" onclick="navTo('s-routing')">
<span class="nav-icon">&#8652;</span> App Routing
</div>
<div class="nav-item" data-nav-section="s-connect" onclick="navTo('s-connect')">
<span class="nav-icon">&#128279;</span> Connect Apps
</div>
<div class="nav-item" data-nav-section="s-settings" onclick="navTo('s-settings')">
<span class="nav-icon">&#9881;</span> Settings
</div>
</nav>
<div class="sidebar-footer">
<button id="theme-btn" title="Switch theme" style="display:none">&#9728;</button>
<button id="settings-btn" onclick="navTo('s-settings')" title="Open settings">&#9881; Settings</button>
</div>
</aside>
<!-- Main scrollable content — sections filled by loader.js -->
<main id="main-content">
<section class="page-section" id="s-voices"></section>
<section class="page-section" id="s-clone"></section>
<section class="page-section" id="s-design"></section>
<section class="page-section" id="s-studio"></section>
<section class="page-section" id="s-tryout"></section>
<section class="page-section" id="s-routing"></section>
<section class="page-section" id="s-connect"></section>
<section class="page-section" id="s-settings"></section>
<section class="page-section" id="s-llms"></section>
</main>
</div><!-- /app-shell -->
<div id="toast"></div>
<div id="status-bar">Loading…</div>
<!-- loader.js: fetches sections → loads app.js → loads nav.js -->
<script src="/static/loader.js"></script>
</body>
</html>