tts-voice-creator-clone-and.../static/loader.js
mARTin-B78 d99395480a Add Script Rehearser; clean Connect Apps; About changelog; rework Try It Out
## Script Rehearser (new feature)
- New section s-rehearser.html + rehearser.js + nav/loader wiring
- Phase 1: paste/upload script (.txt), auto-detect characters from
  'CHARACTER: dialog' or ALL-CAPS screenplay format
- Phase 2: assign a TTS voice per character, or mark 'I play this'
- Phase 3: step-through rehearsal — synthesizes other characters via TTS,
  shows level-meter + oscilloscope for your own lines, records them from mic
- Phase 4: session summary with per-line audio playback + download

## Connect Apps
- Removed duplicate standalone MCP/speak/hotkey full-width cards
- Kept the integration-grid cards (they use the real server URL from JS)
- Added Global Hotkey Daemon as a proper integration card with snippet-hotkey
  populated by integrations.js (uses proxyBase URL dynamically)

## About page
- GET /api/changelog endpoint reads CHANGELOG.md and returns it as text
- Collapsible 'Changelog' <details> card fetches and displays it lazily

## Try It Out
- Reorganised into three cards: Voice & backend / Text to synthesize / Generate
- Backend help panel moved below the voice row (not in the same flex row)
- Style instruction field gains a dynamic badge ('style-aware ✓' / 'weak style')
  and a yellow warning when a non-style-aware backend is selected while the
  field is filled — wired to both backend-select change and input events

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:09:59 +02:00

135 lines
5.3 KiB
JavaScript

(async function () {
'use strict';
const SECTIONS = [
's-voices', 's-clone', 's-design', 's-studio', 's-tryout', 's-rehearser',
's-performance', 's-routing', 's-connect', 's-settings',
's-llms', 's-conversation',
];
// Determine which section to show first (same logic as nav.js)
var _savedSection = localStorage.getItem('ttsvc_section');
var _activeSection = (_savedSection && SECTIONS.indexOf(_savedSection) !== -1)
? _savedSection : 's-voices';
// ── Fetch app version once for JS cache-busting ──────────────────────────
var _appVersion = 'dev';
try {
var _vr = await fetch('/api/version');
var _vd = await _vr.json();
_appVersion = _vd.version || _appVersion;
} catch (_) {}
var _ts = Date.now(); // sections always fresh during a session
// Append session timestamp so that a version bump + container restart
// always invalidates previously cached JS, even on the same version string.
_appVersion = _appVersion + '-' + _ts;
function _inject(id, html) {
var el = document.getElementById(id);
if (el) el.innerHTML = html;
}
// ── 1. Load ONLY the active section before anything else ─────────────────
// Feature modules set up DOM event listeners — the active section's elements
// must exist when JS runs. Other sections are loaded in step 2.
try {
var _ar = await fetch('/static/sections/' + _activeSection + '.html?v=' + _ts);
if (!_ar.ok) throw new Error(_ar.status + ' ' + _ar.statusText);
_inject(_activeSection, await _ar.text());
} catch (e) {
var _ael = document.getElementById(_activeSection);
if (_ael) _ael.innerHTML =
'<p style="color:var(--red);padding:24px">Failed to load section <b>' +
_activeSection + '</b>: ' + e.message + '</p>';
}
// ── 2. Fetch remaining sections in background (parallel with JS loading) ──
// These run concurrently with utils + settings below. Because section HTML
// files are much smaller than JS, they finish before the feature-module batch
// needs them.
var _bgSections = Promise.all(
SECTIONS.filter(function (id) { return id !== _activeSection; })
.map(async function (id) {
try {
var res = await fetch('/static/sections/' + id + '.html?v=' + _ts);
if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
_inject(id, await res.text());
} catch (e) {
var el = document.getElementById(id);
if (el) el.innerHTML =
'<p style="color:var(--red);padding:24px">Failed to load section <b>' +
id + '</b>: ' + e.message + '</p>';
}
})
);
// ── 3. Load JS in parallel batches ────────────────────────────────────────
// Scripts with async=false are FETCHED in parallel but EXECUTED in DOM
// insertion order — safe for modules that share a global scope.
function _load(src) {
return new Promise(function (resolve, reject) {
var s = document.createElement('script');
s.src = src + '?v=' + _appVersion;
s.async = false; // fetch in parallel, execute in DOM order
s.onload = resolve;
s.onerror = function () { reject(new Error('Failed to load ' + src)); };
document.body.appendChild(s);
});
}
function _loadBatch(srcs) {
return Promise.all(srcs.map(_load));
}
// A — foundation (sequential: each must finish before the next batch starts)
await _load('/static/js/utils.js');
await _load('/static/js/settings.js');
// Wait for background sections BEFORE feature modules run.
// Feature modules set up event listeners on DOM elements; all section HTML
// must already be injected. On a local server the sections finish well before
// settings.js completes, so this await is typically instant.
await _bgSections;
// C — feature modules (9 files fetched in parallel, executed in order)
await _loadBatch([
'/static/js/voice-inspector.js',
'/static/js/voice-sources.js',
'/static/js/integrations.js',
'/static/js/routing.js',
'/static/js/voice-clone.js',
'/static/js/voice-library.js',
'/static/js/tts-preview.js',
'/static/js/benchmark.js',
'/static/js/stt.js',
'/static/js/rehearser.js',
]);
// D — init (needs everything above to be defined)
await _load('/static/js/init.js');
// F — navigation (must run before revealing UI so the correct section shows)
await _load('/static/nav.js');
// ── Remove skeleton, reveal sections — as soon as nav is ready ──────────
var sk = document.getElementById('app-skeleton');
if (sk) {
sk.classList.add('sk-hidden');
setTimeout(function () { if (sk.parentNode) sk.parentNode.removeChild(sk); }, 300);
}
document.querySelectorAll('.page-section').forEach(function (s) {
s.style.display = '';
});
// E — post-init modules load in background AFTER the UI is already visible.
// Engines, AI backends, generation, and conversation sections load while
// the user browses Voices / Clone / Design, not before.
_loadBatch([
'/static/js/engines.js',
'/static/js/ai-backends.js',
'/static/js/generation.js',
'/static/js/conversation.js',
]);
})();