11document . addEventListener ( "DOMContentLoaded" , ( ) => {
2- const { chatBox, chatInput, clearChatBtn, voiceToggleBtn, modelSelect, synth, autoSpeakEnabled, speakMessage, stopSpeaking, showToast, toggleSpeechRecognition, initSpeechRecognition } = window . _chatInternals ;
3-
2+ const {
3+ chatBox,
4+ chatInput,
5+ clearChatBtn,
6+ voiceToggleBtn,
7+ modelSelect,
8+ synth,
9+ autoSpeakEnabled,
10+ speakMessage,
11+ stopSpeaking,
12+ showToast,
13+ toggleSpeechRecognition,
14+ initSpeechRecognition
15+ } = window . _chatInternals ;
16+
417 // No static currentSession; we'll fetch it fresh each time
18+
519 function randomSeed ( ) {
620 return Math . floor ( Math . random ( ) * 1000000 ) . toString ( ) ;
721 }
8-
22+
923 function generateSessionTitle ( messages ) {
1024 let title = "" ;
1125 for ( let i = 0 ; i < messages . length ; i ++ ) {
@@ -18,7 +32,7 @@ document.addEventListener("DOMContentLoaded", () => {
1832 if ( title . length > 50 ) title = title . substring ( 0 , 50 ) + "..." ;
1933 return title ;
2034 }
21-
35+
2236 function checkAndUpdateSessionTitle ( ) {
2337 const currentSession = Storage . getCurrentSession ( ) ;
2438 if ( ! currentSession . name || currentSession . name === "New Chat" ) {
@@ -28,12 +42,23 @@ document.addEventListener("DOMContentLoaded", () => {
2842 }
2943 }
3044 }
31-
45+
46+ // Wait for Prism.js to load before applying highlighting
3247 function waitForPrism ( callback ) {
3348 if ( window . Prism ) callback ( ) ;
3449 else setTimeout ( ( ) => waitForPrism ( callback ) , 100 ) ;
3550 }
36-
51+
52+ // Highlight all code blocks inside chatBox
53+ function highlightAllCodeBlocks ( ) {
54+ waitForPrism ( ( ) => {
55+ const codeBlocks = chatBox . querySelectorAll ( "pre code" ) ;
56+ codeBlocks . forEach ( ( block ) => {
57+ Prism . highlightElement ( block ) ;
58+ } ) ;
59+ } ) ;
60+ }
61+
3762 function appendMessage ( { role, content, index } ) {
3863 const container = document . createElement ( "div" ) ;
3964 container . classList . add ( "message" ) ;
@@ -97,9 +122,11 @@ document.addEventListener("DOMContentLoaded", () => {
97122 copyBtn . className = "message-action-btn" ;
98123 copyBtn . textContent = "Copy" ;
99124 copyBtn . addEventListener ( "click" , ( ) => {
100- navigator . clipboard . writeText ( content ) . then ( ( ) => showToast ( "AI response copied to clipboard" ) ) . catch ( ( ) => {
101- showToast ( "Failed to copy to clipboard" ) ;
102- } ) ;
125+ navigator . clipboard . writeText ( content )
126+ . then ( ( ) => showToast ( "AI response copied to clipboard" ) )
127+ . catch ( ( ) => {
128+ showToast ( "Failed to copy to clipboard" ) ;
129+ } ) ;
103130 } ) ;
104131 actionsDiv . appendChild ( copyBtn ) ;
105132 const speakBtn = document . createElement ( "button" ) ;
@@ -147,11 +174,13 @@ document.addEventListener("DOMContentLoaded", () => {
147174 copyCodeBtn . textContent = "Copy Code" ;
148175 copyCodeBtn . style . fontSize = "12px" ;
149176 copyCodeBtn . addEventListener ( "click" , ( ) => {
150- navigator . clipboard . writeText ( codeContent ) . then ( ( ) => {
151- showToast ( "Code copied to clipboard" ) ;
152- } ) . catch ( ( ) => {
153- showToast ( "Failed to copy code" ) ;
154- } ) ;
177+ navigator . clipboard . writeText ( codeContent )
178+ . then ( ( ) => {
179+ showToast ( "Code copied to clipboard" ) ;
180+ } )
181+ . catch ( ( ) => {
182+ showToast ( "Failed to copy code" ) ;
183+ } ) ;
155184 } ) ;
156185 buttonContainer . appendChild ( copyCodeBtn ) ;
157186 const downloadCodeBtn = document . createElement ( "button" ) ;
@@ -171,7 +200,7 @@ document.addEventListener("DOMContentLoaded", () => {
171200 speakMessage ( content ) ;
172201 }
173202 }
174-
203+
175204 function downloadCodeAsTxt ( codeContent , language ) {
176205 const blob = new Blob ( [ codeContent ] , { type : "text/plain" } ) ;
177206 const url = URL . createObjectURL ( blob ) ;
@@ -184,7 +213,7 @@ document.addEventListener("DOMContentLoaded", () => {
184213 URL . revokeObjectURL ( url ) ;
185214 showToast ( "Code downloaded as .txt" ) ;
186215 }
187-
216+
188217 function createImageElement ( url ) {
189218 const imageContainer = document . createElement ( "div" ) ;
190219 imageContainer . className = "ai-image-container" ;
@@ -227,7 +256,7 @@ document.addEventListener("DOMContentLoaded", () => {
227256 imageContainer . appendChild ( buttonContainer ) ;
228257 return imageContainer ;
229258 }
230-
259+
231260 function renderMarkdown ( mdText ) {
232261 if ( window . marked ) {
233262 marked . setOptions ( {
@@ -242,28 +271,34 @@ document.addEventListener("DOMContentLoaded", () => {
242271 return mdText . replace ( / \n / g, "<br>" ) ;
243272 }
244273 }
245-
274+
246275 function escapeHTML ( html ) {
247- return html . replace ( / & / g, "&" ) . replace ( / < / g, "<" ) . replace ( / > / g, ">" ) . replace ( / " / g, """ ) . replace ( / ' / g, "'" ) ;
276+ return html . replace ( / & / g, "&" )
277+ . replace ( / < / g, "<" )
278+ . replace ( / > / g, ">" )
279+ . replace ( / " / g, """ )
280+ . replace ( / ' / g, "'" ) ;
248281 }
249-
282+
250283 function renderStoredMessages ( messages ) {
251284 chatBox . innerHTML = "" ;
252285 messages . forEach ( ( msg , idx ) => appendMessage ( { role : msg . role , content : msg . content , index : idx } ) ) ;
286+ highlightAllCodeBlocks ( ) ;
253287 }
254-
288+
255289 window . addNewMessage = function ( { role, content } ) {
256290 const currentSession = Storage . getCurrentSession ( ) ;
257291 currentSession . messages . push ( { role, content } ) ;
258292 Storage . updateSessionMessages ( currentSession . id , currentSession . messages ) ;
259293 appendMessage ( { role, content, index : currentSession . messages . length - 1 } ) ;
260294 if ( role === "ai" ) checkAndUpdateSessionTitle ( ) ;
261295 } ;
262-
296+
263297 function editMessage ( msgIndex ) {
264298 const currentSession = Storage . getCurrentSession ( ) ;
265299 const oldMessage = currentSession . messages [ msgIndex ] ;
266300 if ( ! oldMessage ) return ;
301+ window . _chatInternals . stopSpeaking ( ) ;
267302 const newContent = prompt ( "Edit this message:" , oldMessage . content ) ;
268303 if ( newContent === null || newContent === oldMessage . content ) return ;
269304 if ( oldMessage . role === "user" ) {
@@ -285,17 +320,20 @@ document.addEventListener("DOMContentLoaded", () => {
285320 sendToPollinations ( ( ) => {
286321 const loadingMsg = document . getElementById ( loadingMsgId ) ;
287322 if ( loadingMsg ) loadingMsg . remove ( ) ;
323+ highlightAllCodeBlocks ( ) ;
288324 } , newContent ) ;
289325 showToast ( "User message updated and new response generated" ) ;
290326 } else {
291327 currentSession . messages [ msgIndex ] . content = newContent ;
292328 Storage . updateSessionMessages ( currentSession . id , currentSession . messages ) ;
293329 renderStoredMessages ( currentSession . messages ) ;
330+ highlightAllCodeBlocks ( ) ;
294331 showToast ( "AI message updated" ) ;
295332 }
296333 }
297-
334+
298335 function reGenerateAIResponse ( aiIndex ) {
336+ window . _chatInternals . stopSpeaking ( ) ;
299337 const currentSession = Storage . getCurrentSession ( ) ;
300338 if ( aiIndex < 0 || aiIndex >= currentSession . messages . length ) return ;
301339 let userIndex = - 1 ;
@@ -327,10 +365,11 @@ document.addEventListener("DOMContentLoaded", () => {
327365 sendToPollinations ( ( ) => {
328366 const loadingMsg = document . getElementById ( loadingMsgId ) ;
329367 if ( loadingMsg ) loadingMsg . remove ( ) ;
368+ highlightAllCodeBlocks ( ) ;
330369 showToast ( "Response regenerated successfully" ) ;
331370 } , userMessage ) ;
332371 }
333-
372+
334373 window . sendToPollinations = function ( callback = null , overrideContent = null ) {
335374 const currentSession = Storage . getCurrentSession ( ) ;
336375 const loadingMsgId = "loading-" + Date . now ( ) ;
@@ -344,7 +383,7 @@ document.addEventListener("DOMContentLoaded", () => {
344383 loadingDiv . textContent = "Thinking..." ;
345384 chatBox . appendChild ( loadingDiv ) ;
346385 chatBox . scrollTop = chatBox . scrollHeight ;
347- const memoryInstructions = "You are the user's AI. Be yourself, the 'you' and name and gender you know is you the AI. Do not mix up your name and gender with the user's. Write user 'memories' you make in [memory]your_text_memory[/memory] format, and include an additional plain text description in your response. When sharing code, always use [CODE]language\ncode[/CODE] for proper syntax highlighting (e.g., [CODE]python\nprint('Hello')\n[/CODE]). Always wrap code in these blocks for readability. Images can be generated via https://image.pollinations.ai/prompt/your_detailed_prompt_here." ;
386+ const memoryInstructions = "You are the user's AI. Be yourself, the 'you' and name and gender you know is you the AI. Do not mix up your name and gender with the user's. Write user 'memories' you make in [memory]your_text_memory[/memory] format, and include an additional plain text description in your response. When sharing code, always use [CODE]language\ncode[/CODE] for proper syntax highlighting (e.g., [CODE]python\nprint('Hello')\n[/CODE]). Always wrap code in these blocks for readability. Images can be generated via https://image.pollinations.ai/openai/ prompt/your_detailed_prompt_here." ;
348387 const messages = [ ] ;
349388 if ( memoryInstructions ) messages . push ( { role : "system" , content : memoryInstructions } ) ;
350389 const memories = Memory . getMemories ( ) ;
@@ -361,8 +400,9 @@ document.addEventListener("DOMContentLoaded", () => {
361400 if ( overrideContent && messages [ messages . length - 1 ] . content !== overrideContent ) {
362401 messages . push ( { role : "user" , content : overrideContent } ) ;
363402 }
403+ const safeParam = window . _pollinationsAPIConfig ? `safe=${ window . _pollinationsAPIConfig . safe } ` : "safe=false" ;
364404 const body = { messages, model : currentSession . model || modelSelect . value || "unity" , stream : false } ;
365- fetch ( " https://text.pollinations.ai/openai" , {
405+ fetch ( ` https://text.pollinations.ai/openai? ${ safeParam } ` , {
366406 method : "POST" ,
367407 headers : { "Content-Type" : "application/json" , Accept : "application/json" } ,
368408 body : JSON . stringify ( body )
@@ -375,28 +415,23 @@ document.addEventListener("DOMContentLoaded", () => {
375415 const loadingMsg = document . getElementById ( loadingMsgId ) ;
376416 if ( loadingMsg ) loadingMsg . remove ( ) ;
377417 let aiContent = extractAIContent ( data ) ;
378-
379- // Check if the user's prompt is requesting an image
380418 const lastUserMsg = messages [ messages . length - 1 ] . content . toLowerCase ( ) ;
381- const isImageRequest = lastUserMsg . includes ( "image" ) || lastUserMsg . includes ( "picture" ) || lastUserMsg . includes ( "show me" ) || lastUserMsg . includes ( "generate an image" ) ;
382-
383- // If the prompt suggests an image request but no image URL is in the response, generate one
419+ const isImageRequest = lastUserMsg . includes ( "image" ) ||
420+ lastUserMsg . includes ( "picture" ) ||
421+ lastUserMsg . includes ( "show me" ) ||
422+ lastUserMsg . includes ( "generate an image" ) ;
384423 if ( aiContent && isImageRequest && ! aiContent . includes ( "https://image.pollinations.ai" ) ) {
385- let imagePrompt = lastUserMsg
386- . replace ( / s h o w m e | g e n e r a t e | i m a g e o f | p i c t u r e o f | i m a g e | p i c t u r e / gi, "" )
387- . trim ( ) ;
388-
424+ let imagePrompt = lastUserMsg . replace ( / s h o w m e | g e n e r a t e | i m a g e o f | p i c t u r e o f | i m a g e | p i c t u r e / gi, "" ) . trim ( ) ;
389425 if ( imagePrompt . length < 5 && aiContent . toLowerCase ( ) . includes ( "image" ) ) {
390- imagePrompt = aiContent
391- . toLowerCase ( )
392- . replace ( / h e r e ' s a n i m a g e o f | i m a g e | t o e n j o y v i s u a l l y / gi , "" )
393- . trim ( ) ;
426+ imagePrompt = aiContent . toLowerCase ( ) . replace ( / h e r e ' s a n i m a g e o f | i m a g e | t o e n j o y v i s u a l l y / gi , "" ) . trim ( ) ;
427+ }
428+ if ( imagePrompt . length > 100 ) {
429+ imagePrompt = imagePrompt . substring ( 0 , 100 ) ;
394430 }
395-
396- const imageUrl = `https://image.pollinations.ai/prompt/${ encodeURIComponent ( imagePrompt ) } ?width=512&height=512&seed=${ randomSeed ( ) } ` ;
431+ imagePrompt += ", photographic" ;
432+ const imageUrl = `https://image.pollinations.ai/prompt/${ encodeURIComponent ( imagePrompt ) } ?width=512&height=512&seed=${ randomSeed ( ) } & ${ safeParam } &nolog=true ` ;
397433 aiContent += `\n\n**Generated Image:**\n${ imageUrl } ` ;
398434 }
399-
400435 if ( aiContent ) {
401436 const foundMemories = parseMemoryBlocks ( aiContent ) ;
402437 foundMemories . forEach ( ( m ) => Memory . addMemoryEntry ( m ) ) ;
@@ -415,28 +450,32 @@ document.addEventListener("DOMContentLoaded", () => {
415450 }
416451 } ) ;
417452 } ;
418-
453+
419454 function extractAIContent ( response ) {
420455 if ( response . choices && response . choices . length > 0 ) {
421- if ( response . choices [ 0 ] . message && response . choices [ 0 ] . message . content ) return response . choices [ 0 ] . message . content ;
422- else if ( response . choices [ 0 ] . text ) return response . choices [ 0 ] . text ;
423- } else if ( response . response ) return response . response ;
424- else if ( typeof response === "string" ) return response ;
456+ if ( response . choices [ 0 ] . message && response . choices [ 0 ] . message . content )
457+ return response . choices [ 0 ] . message . content ;
458+ else if ( response . choices [ 0 ] . text )
459+ return response . choices [ 0 ] . text ;
460+ } else if ( response . response )
461+ return response . response ;
462+ else if ( typeof response === "string" )
463+ return response ;
425464 return "Sorry, I couldn't process that response." ;
426465 }
427-
466+
428467 function parseMemoryBlocks ( text ) {
429468 const memRegex = / \[ m e m o r y \] ( [ \s \S ] * ?) \[ \/ m e m o r y \] / gi;
430469 const found = [ ] ;
431470 let match ;
432471 while ( ( match = memRegex . exec ( text ) ) !== null ) found . push ( match [ 1 ] . trim ( ) ) ;
433472 return found ;
434473 }
435-
474+
436475 function removeMemoryBlocks ( text ) {
437476 return text . replace ( / \[ m e m o r y \] [ \s \S ] * ?\[ \/ m e m o r y \] / gi, "" ) ;
438477 }
439-
478+
440479 if ( voiceToggleBtn ) {
441480 voiceToggleBtn . addEventListener ( "click" , window . _chatInternals . toggleAutoSpeak ) ;
442481 window . _chatInternals . updateVoiceToggleUI ( ) ;
@@ -455,7 +494,7 @@ document.addEventListener("DOMContentLoaded", () => {
455494 }
456495 } , 2000 ) ;
457496 }
458-
497+
459498 if ( clearChatBtn ) {
460499 clearChatBtn . addEventListener ( "click" , ( ) => {
461500 const currentSession = Storage . getCurrentSession ( ) ;
@@ -467,7 +506,7 @@ document.addEventListener("DOMContentLoaded", () => {
467506 }
468507 } ) ;
469508 }
470-
509+
471510 function checkFirstLaunch ( ) {
472511 const firstLaunch = localStorage . getItem ( "firstLaunch" ) === "0" ;
473512 if ( firstLaunch ) {
@@ -498,7 +537,7 @@ document.addEventListener("DOMContentLoaded", () => {
498537 }
499538 }
500539 checkFirstLaunch ( ) ;
501-
540+
502541 function setupVoiceInputButton ( ) {
503542 if ( "webkitSpeechRecognition" in window || "SpeechRecognition" in window ) {
504543 const inputButtonsContainer = document . querySelector ( ".input-buttons-container" ) ;
@@ -514,7 +553,7 @@ document.addEventListener("DOMContentLoaded", () => {
514553 }
515554 }
516555 setupVoiceInputButton ( ) ;
517-
556+
518557 const sendButton = document . getElementById ( "send-button" ) ;
519558 function handleSendMessage ( ) {
520559 const message = chatInput . value . trim ( ) ;
@@ -525,24 +564,24 @@ document.addEventListener("DOMContentLoaded", () => {
525564 window . sendToPollinations ( ) ;
526565 sendButton . disabled = true ;
527566 }
528-
567+
529568 chatInput . addEventListener ( "input" , ( ) => {
530569 sendButton . disabled = chatInput . value . trim ( ) === "" ;
531570 chatInput . style . height = "auto" ;
532571 chatInput . style . height = chatInput . scrollHeight + "px" ;
533572 } ) ;
534-
573+
535574 chatInput . addEventListener ( "keydown" , ( e ) => {
536575 if ( e . key === "Enter" && ! e . shiftKey ) {
537576 e . preventDefault ( ) ;
538577 handleSendMessage ( ) ;
539578 }
540579 } ) ;
541-
580+
542581 sendButton . addEventListener ( "click" , ( ) => {
543582 handleSendMessage ( ) ;
544583 } ) ;
545-
584+
546585 const initialSession = Storage . getCurrentSession ( ) ;
547586 if ( initialSession . messages && initialSession . messages . length > 0 ) {
548587 renderStoredMessages ( initialSession . messages ) ;
0 commit comments