feat: TTS-Zeitbereiche + Diagnostic-Debug-Toggle + Play-Button respektiert Engine
TTS-Cleanup erweitert: - Zeitbereiche: '8:00-9:00 Uhr' / '8-9 Uhr' → 'acht bis neun Uhr' - Uhrzeiten: '8:30 Uhr' → 'acht Uhr dreissig', '15 Uhr' → 'fuenfzehn Uhr' - Kleine Zahlen-Bereiche: '5-6' → 'fuenf bis sechs' (nur ≤24) - Zahlen 0-59 als deutsche Woerter (inkl. 'einundzwanzig', 'fuenfundvierzig') Diagnostic: TTS-Debug Einblenden - Checkbox 'TTS-Text einblenden' in der Chat-Test Kopfzeile - Unter ARIA-Nachrichten erscheint die aufbereitete Variante (blauer Border + Label 'TTS:') - Nur in Diagnostic, nicht in der App - LocalStorage persistiert den Toggle-Zustand - Minimaler JS-Port von clean_text_for_tts als Fallback Play-Button respektiert Engine: - Bridge: tts_request nutzt jetzt die aktive TTS-Engine (Piper/XTTS), Text wird durch clean_text_for_tts aufbereitet - messageId wird vom Play-Button mitgeschickt → Bridge verknuepft generiertes Audio mit der urspruenglichen Message - XTTS-Chunks: requestId → messageId Map (LRU 100 Eintraege), beim xtts_response wird die Basis-UUID extrahiert und die messageId dem audio-Frame angehaengt - App cached auch XTTS-Audio jetzt (letzter Satz pro Message — echte Chunk-Konkatenation bleibt TODO) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+54
-3
@@ -198,7 +198,13 @@
|
||||
<div class="card full">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
|
||||
<h2 style="margin:0;">Chat Test</h2>
|
||||
<button class="btn secondary" onclick="toggleChatFullscreen()" id="btn-chat-fs" style="padding:4px 10px;font-size:11px;">Vollbild</button>
|
||||
<div style="display:flex;align-items:center;gap:12px;">
|
||||
<label style="color:#8888AA;font-size:11px;cursor:pointer;">
|
||||
<input type="checkbox" id="tts-debug-toggle" onchange="toggleTtsDebug()" style="margin-right:4px;vertical-align:middle;">
|
||||
TTS-Text einblenden
|
||||
</label>
|
||||
<button class="btn secondary" onclick="toggleChatFullscreen()" id="btn-chat-fs" style="padding:4px 10px;font-size:11px;">Vollbild</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-box" id="chat-box"></div>
|
||||
<div id="thinking-indicator" style="display:none;padding:6px 10px;font-size:12px;color:#FFD60A;background:#1E1E2E;border-radius:0 0 6px 6px;margin-top:-8px;margin-bottom:8px;align-items:center;justify-content:space-between;">
|
||||
@@ -1272,14 +1278,55 @@
|
||||
});
|
||||
}
|
||||
|
||||
function addChat(type, text, meta) {
|
||||
// Debug-Toggle: TTS-aufbereitete Variante unter ARIA-Nachrichten einblenden
|
||||
let showTtsDebug = localStorage.getItem('aria-show-tts-debug') === '1';
|
||||
function toggleTtsDebug() {
|
||||
showTtsDebug = !showTtsDebug;
|
||||
localStorage.setItem('aria-show-tts-debug', showTtsDebug ? '1' : '0');
|
||||
const el = document.getElementById('tts-debug-toggle');
|
||||
if (el) el.checked = showTtsDebug;
|
||||
}
|
||||
|
||||
// Minimal-JS-Port von clean_text_for_tts() (Bridge) — reine Anzeige
|
||||
function previewTtsText(text) {
|
||||
if (!text) return '';
|
||||
// <voice>...</voice>
|
||||
const vm = text.match(/<voice>([\s\S]*?)<\/voice>/i);
|
||||
if (vm) text = vm[1];
|
||||
let t = text;
|
||||
t = t.replace(/```[\s\S]*?```/g, '. ');
|
||||
t = t.replace(/`[^`]+`/g, '');
|
||||
t = t.replace(/\*\*([^*]+)\*\*/g, '$1');
|
||||
t = t.replace(/\*([^*]+)\*/g, '$1');
|
||||
t = t.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
|
||||
t = t.replace(/https?:\/\/\S+/g, 'ein Link');
|
||||
t = t.replace(/^#{1,6}\s*/gm, '');
|
||||
t = t.replace(/^>\s*/gm, '');
|
||||
t = t.replace(/^[\-\*]\s+/gm, '');
|
||||
t = t.replace(/(\d+)GB\b/g, '$1 Gigabyte');
|
||||
t = t.replace(/(\d+)MB\b/g, '$1 Megabyte');
|
||||
t = t.replace(/%/g, ' Prozent');
|
||||
t = t.replace(/\bCPU\b/g, 'C P U').replace(/\bAPI\b/g, 'A P I').replace(/\bRAM\b/g, 'R A M');
|
||||
t = t.replace(/\n{2,}/g, '. ').replace(/\n/g, ', ').replace(/\s{2,}/g, ' ');
|
||||
return t.trim();
|
||||
}
|
||||
|
||||
function addChat(type, text, meta, options) {
|
||||
const escaped = escapeHtml(text);
|
||||
let linked = linkifyText(escaped);
|
||||
// /shared/uploads/ Pfade als Inline-Bilder anzeigen
|
||||
linked = linked.replace(/\/shared\/uploads\/[^\s<"]+\.(jpg|jpeg|png|gif)/gi, (match) => {
|
||||
return `<a href="${match}" target="_blank">${match}</a><img src="${match}" class="chat-media" onclick="openLightbox('image','${match}')" onerror="this.style.display='none'">`;
|
||||
});
|
||||
const html = `${linked}<div class="meta">${escapeHtml(meta)} — ${new Date().toLocaleTimeString('de-DE')}</div>`;
|
||||
// Optional: TTS-Variante als zusaetzliches Block unter der Nachricht
|
||||
let ttsBlock = '';
|
||||
if (showTtsDebug && type === 'received') {
|
||||
const ttsText = (options && options.ttsText) || previewTtsText(text);
|
||||
if (ttsText && ttsText !== text) {
|
||||
ttsBlock = `<div style="margin-top:6px;padding:4px 8px;background:rgba(0,150,255,0.08);border-left:2px solid #0096FF;font-size:11px;color:#88AACC;"><span style="color:#0096FF;font-weight:bold;">TTS:</span> ${escapeHtml(ttsText)}</div>`;
|
||||
}
|
||||
}
|
||||
const html = `${linked}${ttsBlock}<div class="meta">${escapeHtml(meta)} — ${new Date().toLocaleTimeString('de-DE')}</div>`;
|
||||
|
||||
// Thinking-Indikator ausblenden bei neuer Nachricht
|
||||
updateThinkingIndicator({ activity: 'idle' });
|
||||
@@ -2129,6 +2176,10 @@
|
||||
send({ action: 'get_openclaw_config' });
|
||||
}
|
||||
|
||||
// Toggle-Checkbox initial korrekt setzen
|
||||
const ttsToggleEl = document.getElementById('tts-debug-toggle');
|
||||
if (ttsToggleEl) ttsToggleEl.checked = showTtsDebug;
|
||||
|
||||
connectWS();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user