diff --git a/public/src/tts.js b/public/src/tts.js index ab68d5a..2145e28 100644 --- a/public/src/tts.js +++ b/public/src/tts.js @@ -260,7 +260,17 @@ export async function speakTextStreaming(text, voice = "alloy", rate = 0.9, mode audio.play().catch(e => console.warn("Initial play blocked:", e.message)); // Return immediately with audio element - caller uses done promise to know when stream finishes - return { audio, blob: null, blobUrl: audioUrl, streamed: true, done }; + // The result object is mutable: blob/blobUrl get updated when done resolves, + // so click handlers that read result.blobUrl later will get the downloadable URL + const result = { audio, blob: null, blobUrl: audioUrl, streamed: true, done }; + + done.then(({ blob, blobUrl }) => { + result.blob = blob; + // Create a downloadable blob URL (MediaSource URL can't be downloaded) + result.blobUrl = URL.createObjectURL(blob); + }).catch(() => {}); + + return result; } // Process page content using Hermes (deprecated - use extractSpokenTokens instead) diff --git a/public/src/uncloseai-embed-modal.js b/public/src/uncloseai-embed-modal.js index c3a05f3..aef58f8 100644 --- a/public/src/uncloseai-embed-modal.js +++ b/public/src/uncloseai-embed-modal.js @@ -48,9 +48,9 @@ function parseVoiceSelection(selectedValue) { // Import required functions dynamically to avoid circular dependencies async function speakChatText(text, voiceSelection, speed) { - const { speakTextDirect } = await import("./tts.js"); + const { handleTTS } = await import("./tts.js"); const { model, voice } = parseVoiceSelection(voiceSelection); - return await speakTextDirect(text, voice, speed, model); + return await handleTTS(text, voice, speed, model); } async function* sendMessage(message) {