diff --git a/src/lib/components/Message.svelte b/src/lib/components/Message.svelte index 79cbcfc..26d5f35 100644 --- a/src/lib/components/Message.svelte +++ b/src/lib/components/Message.svelte @@ -294,8 +294,7 @@ } .content { - font-size: 13.5px; - line-height: 1.55; + /* Schrift wird von .msg geerbt (User-konfigurierbar) */ word-wrap: break-word; } .content.faint { color: var(--vscode-descriptionForeground); } @@ -308,9 +307,9 @@ margin: 10px 0 4px 0; font-weight: 600; } - .content :global(h1) { font-size: 16px; } - .content :global(h2) { font-size: 14.5px; } - .content :global(h3) { font-size: 13.5px; } + .content :global(h1) { font-size: 1.25em; } + .content :global(h2) { font-size: 1.13em; } + .content :global(h3) { font-size: 1.05em; } .content :global(.code-block-wrapper) { background: var(--vscode-terminal-background); border: 1px solid var(--vscode-input-border); diff --git a/src/lib/voice/conversationEngine.ts b/src/lib/voice/conversationEngine.ts index 12b88d3..93aec54 100644 --- a/src/lib/voice/conversationEngine.ts +++ b/src/lib/voice/conversationEngine.ts @@ -43,6 +43,7 @@ let audioChunks: Blob[] = []; let analyser: AnalyserNode | null = null; let animationFrame: number | null = null; let ttsAudio: HTMLAudioElement | null = null; +let ttsResolve: (() => void) | null = null; // VAD const SILENCE_THRESHOLD = 0.03; @@ -299,13 +300,28 @@ async function speakAndWait(text: string): Promise { try { const voice = get(chatAppearance).ttsVoice || null; const audioBase64: string = await invoke('text_to_speech', { text, voice }); + // Falls in der Zwischenzeit gestoppt wurde — kein Audio mehr starten + if (!isActive()) return; return new Promise((resolve) => { + let resolved = false; + const finish = () => { + if (resolved) return; + resolved = true; + if (ttsAudio) { + ttsAudio.pause(); + ttsAudio.src = ''; + try { ttsAudio.load(); } catch { /* ignore */ } + ttsAudio = null; + } + resolve(); + }; + ttsResolve = finish; if (ttsAudio) { ttsAudio.pause(); ttsAudio = null; } ttsAudio = new Audio(`data:audio/wav;base64,${audioBase64}`); - ttsAudio.onended = () => { ttsAudio = null; resolve(); }; - ttsAudio.onerror = () => { ttsAudio = null; resolve(); }; - ttsAudio.play().catch(() => resolve()); - monitorInterrupt(resolve); + ttsAudio.onended = finish; + ttsAudio.onerror = finish; + ttsAudio.play().catch(finish); + monitorInterrupt(finish); }); } catch (err) { console.error('TTS fehlgeschlagen:', err); @@ -337,10 +353,20 @@ function monitorInterrupt(onInterrupt: () => void) { function stopSpeaking() { if (ttsAudio) { - ttsAudio.pause(); - ttsAudio.currentTime = 0; + try { + ttsAudio.pause(); + ttsAudio.currentTime = 0; + ttsAudio.src = ''; + ttsAudio.load(); + } catch { /* ignore */ } ttsAudio = null; } + // Wartendes speakAndWait()-Promise sofort aufloesen + if (ttsResolve) { + const r = ttsResolve; + ttsResolve = null; + try { r(); } catch { /* ignore */ } + } } // Helpers -------------------------------------------------------------------