1- // chat-part1.js
2- // Fix: remove concurrency check that led to partial TTS, allow full reading
3-
41document . addEventListener ( "DOMContentLoaded" , ( ) => {
5- // Grab essential DOM elements
62 const chatBox = document . getElementById ( "chat-box" ) ;
73 const chatInput = document . getElementById ( "chat-input" ) ;
84 const sendButton = document . getElementById ( "send-button" ) ;
95 const clearChatBtn = document . getElementById ( "clear-chat" ) ;
106 const voiceToggleBtn = document . getElementById ( "voice-toggle" ) ;
117 const modelSelect = document . getElementById ( "model-select" ) ;
128
13- // Current session from Storage
149 let currentSession = Storage . getCurrentSession ( ) ;
1510 if ( ! currentSession ) {
1611 currentSession = Storage . createSession ( "New Chat" ) ;
1712 localStorage . setItem ( "currentSessionId" , currentSession . id ) ;
1813 }
1914
20- // Browser speech synthesis / voices
2115 const synth = window . speechSynthesis ;
2216 let voices = [ ] ;
2317 let selectedVoice = null ;
2418 let isSpeaking = false ;
2519 let autoSpeakEnabled = localStorage . getItem ( "autoSpeakEnabled" ) === "true" ;
2620 let currentlySpeakingMessage = null ;
2721
28- // Speech recognition
2922 let recognition = null ;
3023 let isListening = false ;
31- let voiceInputBtn = null ; // We'll create it if needed
24+ let voiceInputBtn = null ;
3225 let slideshowInterval = null ;
3326
34- // ========== LOAD VOICES ==========
3527 function loadVoices ( ) {
3628 return new Promise ( ( resolve ) => {
3729 let voicesLoaded = false ;
@@ -54,7 +46,6 @@ document.addEventListener("DOMContentLoaded", () => {
5446 }
5547 }
5648 if ( ! selectedVoice ) {
57- // fallback to the first female voice or just the first available
5849 selectedVoice =
5950 voices . find ( ( v ) => v . name . toLowerCase ( ) . includes ( "female" ) ) ||
6051 voices [ 0 ] ;
@@ -64,10 +55,8 @@ document.addEventListener("DOMContentLoaded", () => {
6455 }
6556 }
6657
67- // Try immediate
6858 setVoices ( ) ;
6959
70- // If not loaded, wait for onvoiceschanged or a fallback
7160 if ( ! voicesLoaded && synth . onvoiceschanged !== undefined ) {
7261 synth . onvoiceschanged = ( ) => {
7362 setVoices ( ) ;
@@ -87,11 +76,6 @@ document.addEventListener("DOMContentLoaded", () => {
8776 updateVoiceToggleUI ( ) ;
8877 } ) ;
8978
90- // ========== TOGGLES / SPEECH SYNTHESIS ==========
91-
92- /**
93- * Toggle the 'autoSpeakEnabled' state. If enabling, speak a short message.
94- */
9579 function toggleAutoSpeak ( ) {
9680 autoSpeakEnabled = ! autoSpeakEnabled ;
9781 localStorage . setItem ( "autoSpeakEnabled" , autoSpeakEnabled . toString ( ) ) ;
@@ -111,24 +95,17 @@ document.addEventListener("DOMContentLoaded", () => {
11195 }
11296 }
11397
114- /**
115- * Speak the entire text.
116- * We removed the concurrency logic that cut off if the same text is triggered again,
117- * so it won't skip reading the rest anymore.
118- */
11998 function speakMessage ( text , onEnd = null ) {
12099 if ( ! synth || ! window . SpeechSynthesisUtterance ) {
121100 console . error ( "Speech synthesis not supported in this browser" ) ;
122101 showToast ( "Speech synthesis not supported in your browser" ) ;
123102 return ;
124103 }
125104
126- // If something is currently speaking, forcibly stop it before starting again.
127105 if ( isSpeaking ) {
128106 synth . cancel ( ) ;
129107 }
130108
131- // (Optional) sanitize or remove code blocks / links from spoken text
132109 let cleanText = text
133110 . replace ( / ` ` ` [ \s \S ] * ?` ` ` / g, "code block omitted." )
134111 . replace ( / ` [ \s \S ] * ?` / g, "inline code omitted." )
@@ -138,7 +115,6 @@ document.addEventListener("DOMContentLoaded", () => {
138115 if ( selectedVoice ) {
139116 utterance . voice = selectedVoice ;
140117 } else {
141- // If we don't have a voice yet, force load
142118 loadVoices ( ) . then ( ( voice ) => {
143119 if ( voice ) {
144120 utterance . voice = voice ;
@@ -184,7 +160,6 @@ document.addEventListener("DOMContentLoaded", () => {
184160 }
185161 }
186162
187- // ========== SPEECH RECOGNITION ==========
188163 function initSpeechRecognition ( ) {
189164 if ( "webkitSpeechRecognition" in window ) {
190165 recognition = new webkitSpeechRecognition ( ) ;
@@ -259,7 +234,6 @@ document.addEventListener("DOMContentLoaded", () => {
259234 }
260235 }
261236
262- // ========== UTILITY TOAST ==========
263237 function showToast ( message , duration = 3000 ) {
264238 let toast = document . getElementById ( "toast-notification" ) ;
265239 if ( ! toast ) {
@@ -285,30 +259,24 @@ document.addEventListener("DOMContentLoaded", () => {
285259 } , duration ) ;
286260 }
287261
288- // Put everything we need on a global object for chat-part2.js & chat-part3.js
289262 window . _chatInternals = {
290- // DOM
291263 chatBox,
292264 chatInput,
293265 sendButton,
294266 clearChatBtn,
295267 voiceToggleBtn,
296268 modelSelect,
297- // Session state
298269 currentSession,
299- // Synthesis
300270 synth,
301271 voices,
302272 selectedVoice,
303273 isSpeaking,
304274 autoSpeakEnabled,
305275 currentlySpeakingMessage,
306- // Recognition
307276 recognition,
308277 isListening,
309278 voiceInputBtn,
310279 slideshowInterval,
311- // Functions
312280 toggleAutoSpeak,
313281 updateVoiceToggleUI,
314282 speakMessage,
0 commit comments