{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./app/javascript/modules/audio_handler.js","webpack:///./app/javascript/modules/ui_controls.js","webpack:///./app/javascript/modules/message_handler.js","webpack:///./app/javascript/modules/nudge_handler.js","webpack:///./app/javascript/modules/explanation_handler.js","webpack:///./app/javascript/modules/ios_handler.js","webpack:///./app/javascript/modules/conversation_core.js","webpack:///./app/javascript/packs/conversation.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","debug","currentlyPlayingAudio","currentlyPlayingMessageId","autoplayEnabled","playAudio","audioUrl","audio","Audio","isIOSDevice","test","navigator","userAgent","window","MSStream","play","then","error","concat","message","playLatestAudio","console","log","audioElements","document","querySelectorAll","length","latestAudio","load","addEventListener","onCanPlay","removeEventListener","toggleAudioControls","messageId","isPlaying","querySelector","stopBtn","listenBtn","style","display","enableAutoplay","isAutoplayEnabled","setupAudioHandling","debugFunction","recordBtn","getElementById","statusElement","mediaRecorder","audioChunks","isSubmitting","textContent","mediaDevices","getUserMedia","stream","MediaRecorder","event","push","data","audioBlob","Blob","type","size","pathParts","location","pathname","split","conversationId","indexOf","formData","FormData","append","fetch","method","body","headers","content","response","status","ok","text","Error","reload","getTracks","forEach","track","stop","start","state","setupAudioRecording","target","classList","contains","messageElement","closest","dataset","audioElement","pause","currentTime","messageContent","trim","JSON","stringify","speechResponse","json","audio_url","audioEl","audioControlsDiv","createElement","className","appendChild","onended","oncanplaythrough","onplay","onpause","onloadedmetadata","newAudioEl","src","parentNode","replaceChild","aiMessages","lastAIMessage","messagesContainer","MutationObserver","mutations","mutation","addedNodes","node","nodeType","observe","childList","setupAudioPlayback","URLSearchParams","search","newUrl","history","replaceState","title","checkForAutoplayParameter","addMessageToDOM","senderType","messageDiv","sender_type","setAttribute","id","contentDiv","highlighted_translation","innerHTML","replace","buttonsDiv","alignItems","marginTop","explainContainer","explainButton","cursor","color","fontSize","background","border","padding","borderRadius","width","height","textAlign","tooltipText","listenButton","marginLeft","stopButton","lastElementChild","scrollToBottom","setTimeout","updateButtonVisibility","recordButton","continueButton","messages","updateMessageButtonsVisibility","offsetHeight","translateMessageIfNeeded","translated_content","Promise","resolve","sendMessage","preventDefault","messageInput","appendUserMessage","translatedContent","updateUserMessageWithTranslation","appendAiMessage","ai_response","highlightedTranslation","contentElement","displayContent","updateMessageWithTranslation","checkForTranslatedContent","applyHighlightedContent","ensureAllMessagesVisible","visibility","opacity","container","scrollTop","scrollHeight","restoreScrollPosition","savedPosition","sessionStorage","getItem","parseInt","removeItem","addRetryButtonToLastUserMessage","lastMessage","mainButton","buttonsContainer","retryContainer","retryButton","setupMessageHandling","matches","button","getAttribute","pop","disabled","message_id","userCredits","updateCreditCounter","checkCreditsAndUpdateButton","undefined","credits","retryButtonHandlersInitialized","isRetry","click","_regeneratorRuntime","e","a","iterator","asyncIterator","u","define","configurable","writable","wrap","Generator","Context","makeInvokeMethod","tryCatch","arg","h","f","y","GeneratorFunction","GeneratorFunctionPrototype","getPrototypeOf","v","values","g","defineIteratorMethods","_invoke","AsyncIterator","invoke","__await","callInvokeWithMethodAndArg","done","delegate","maybeInvokeDelegate","sent","_sent","dispatchException","abrupt","TypeError","resultName","next","nextLoc","pushTryEntry","tryLoc","catchLoc","finallyLoc","afterLoc","tryEntries","resetTryEntry","completion","reset","isNaN","displayName","isGeneratorFunction","constructor","mark","setPrototypeOf","__proto__","awrap","async","keys","reverse","prev","charAt","slice","rval","handle","complete","finish","delegateYield","asyncGeneratorStep","_asyncToGenerator","arguments","apply","_next","_throw","isIOSFlow","ensureExplainButtonsVisible","showImprovementPopup","originalMessage","improvedVersion","explanation","improvementContainer","originalMessageElement","improvedMessageElement","explanationElement","acceptButton","scrollIntoView","behavior","onclick","acceptImprovement","setupUIControls","messageHandler","belowMessagesButton","newButton","cloneNode","conversationContainer","iosDevice","isExistingConversation","existingConversation","creditCounter","creditWarning","stopPropagation","currentState","_ref","_callee","silentAudio","_messages","_messages2","_context","audioHandler","t0","_x","_ref2","_callee2","firstAIMessage","_silentAudio","_context2","_x2","languageNudgeCount","localStorage","languageNudgeDismissed","languageNudge","isIOS","mimeType","isTypeSupported","actualMimeType","timeslice","fileExtension","includes","remove","retriedMessageIds","user_message","messageToRemove","newAIMessage","capture","observer","setupBelowMessagesButton","initializeExplanationChunks","chunk","add","setupTextSelectionExplain","position","maxWidth","whiteSpace","zIndex","backgroundColor","boxShadow","currentSelectedText","currentSenderType","isButtonInteraction","showButtonNearSelection","selection","getSelection","rangeCount","toString","anchorNode","isInMessage","rect","getRangeAt","getBoundingClientRect","left","scrollX","top","scrollY","updateButtonContent","selected_text","translationText","questionMark","dispatchEvent","CustomEvent","detail","action","this","spinner","borderTopColor","animation","fontFamily","fontWeight","head","setItem","href","encodeURIComponent","statusText","setupExplanationButtonHandlers","setupExplanationHandling","SELECTION_NUDGE_DISMISSED_KEY","SELECTION_NUDGE_SHOWN_COUNT_KEY","LANGUAGE_NUDGE_DISMISSED_KEY","DIFFERENT_LANGUAGE_USAGE_COUNT_KEY","LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY","LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY","isMobileDevice","shouldShowSelectionNudge","shouldShowLanguageNudge","parse","dismissSelectionNudge","hideSelectionNudge","trackDifferentLanguageUsage","newCount","dismissLanguageNudge","hideLanguageNudge","showSelectionNudge","nudgeElement","currentCount","showLanguageNudge","shownConversations","conversationCount","checkMessageCountForNudge","aiMessageCount","setupNudgeHandling","actualRecordButton","toLowerCase","setupLanguageNudgeListeners","ua","playSilentAudio","_playSilentAudio","showAllAIMessages","setupIOSHandler","explainMessage","alert","showExplanationPopup","modal","improvedText","originalContent","fontStyle","marginBottom","originalLabel","originalParagraph","improvedDiv","improvedLabel","paragraph","debugInfo","explanationHandler","selectionNudge","firstAudio","err","subtree","currentAudio","currentButton","_this"],"mappings":"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","file":"js/conversation-487110c7af0690fae3c5.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/packs/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 14);\n","/**\n * Audio handling functionality for the conversation interface\n * Manages audio recording, playback, and related UI controls\n */\n\n// Debug helper (imported from main file)\nlet debug;\n\n// Global variables for audio playback tracking\nlet currentlyPlayingAudio = null;\nlet currentlyPlayingMessageId = null;\n\n// Flag to track if autoplay is enabled (unlocked on iOS)\nlet autoplayEnabled = false;\n\n/**\n * Play audio from a URL\n */\nfunction playAudio(audioUrl) {\n if (!audioUrl || audioUrl === '') {\n debug('Audio URL is missing or empty, skipping playback');\n return;\n }\n \n // Create a new audio element\n const audio = new Audio(audioUrl);\n \n // Check if we're on iOS and autoplay is not yet enabled\n const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n \n // Play the audio\n audio.play()\n .then(() => {\n // If we successfully played audio on iOS, mark autoplay as enabled\n if (isIOSDevice && !autoplayEnabled) {\n autoplayEnabled = true;\n debug('Autoplay successfully enabled on iOS');\n }\n })\n .catch(error => {\n debug(`Audio playback failed: ${error.message}`);\n \n // If on iOS and autoplay failed, we need user interaction\n if (isIOSDevice) {\n debug('Autoplay failed on iOS - requires user interaction');\n }\n });\n}\n\n/**\n * Play the latest audio element on the page\n */\nfunction playLatestAudio() {\n console.log(\"DEBUG: Attempting to play latest audio\");\n \n // Get all audio elements\n const audioElements = document.querySelectorAll('audio');\n console.log(`DEBUG: Found ${audioElements.length} audio elements`);\n \n if (audioElements.length > 0) {\n // Get the last audio element (most recent)\n const latestAudio = audioElements[audioElements.length - 1];\n \n console.log(\"DEBUG: Found latest audio element, attempting to play\");\n \n // Simple play without the complex promise handling\n try {\n // Make sure it's loaded\n latestAudio.load();\n \n // Add a simple event listener for when it's ready\n latestAudio.addEventListener('canplaythrough', function onCanPlay() {\n latestAudio.play();\n latestAudio.removeEventListener('canplaythrough', onCanPlay);\n console.log(\"DEBUG: Audio playback started\");\n });\n \n // Also try to play directly in case it's already loaded\n latestAudio.play();\n } catch (error) {\n console.error(\"DEBUG: Audio playback error:\", error);\n }\n } else {\n console.log(\"DEBUG: No audio elements found\");\n }\n}\n\n/**\n * Check for autoplay parameter in URL and handle accordingly\n */\nfunction checkForAutoplayParameter() {\n const urlParams = new URLSearchParams(window.location.search);\n if (urlParams.get('autoplay') === 'true') {\n console.log('DEBUG: Autoplay parameter detected, but not playing audio automatically');\n // Don't play audio automatically\n // playLatestAudio(); <- Remove or comment this line\n \n // Remove the parameter from the URL to prevent repeated autoplay on refresh\n const newUrl = window.location.pathname;\n window.history.replaceState({}, document.title, newUrl);\n }\n}\n\n/**\n * Toggle audio controls visibility for a message\n */\nfunction toggleAudioControls(messageId, isPlaying) {\n const message = document.querySelector(`.message[data-message-id=\"${messageId}\"]`);\n if (!message) return;\n \n const stopBtn = message.querySelector('.stop-audio-btn');\n const listenBtn = message.querySelector('.listen-audio-btn');\n \n if (!stopBtn || !listenBtn) return;\n \n if (isPlaying) {\n stopBtn.style.display = 'inline-block';\n listenBtn.style.display = 'none';\n } else {\n stopBtn.style.display = 'none';\n listenBtn.style.display = 'inline-block';\n }\n}\n\n/**\n * Enable autoplay for iOS devices\n * This should be called after user interaction has unlocked autoplay\n */\nfunction enableAutoplay() {\n autoplayEnabled = true;\n debug('Autoplay enabled for iOS');\n return autoplayEnabled;\n}\n\n/**\n * Check if autoplay is enabled\n */\nfunction isAutoplayEnabled() {\n return autoplayEnabled;\n}\n\n/**\n * Set up audio recording functionality\n */\nfunction setupAudioRecording() {\n const recordBtn = document.getElementById('record-button');\n const stopBtn = document.getElementById('stop-button');\n const statusElement = document.getElementById('recording-status');\n \n console.log('DEBUG: Record button found:', !!recordBtn);\n console.log('DEBUG: Stop button found:', !!stopBtn);\n \n if (!recordBtn || !stopBtn) {\n console.log('DEBUG: Recording buttons not found');\n return;\n }\n \n // Force initial button states\n recordBtn.style.display = 'inline-block';\n stopBtn.style.display = 'none';\n \n let mediaRecorder;\n let audioChunks = [];\n let isSubmitting = false;\n \n recordBtn.addEventListener('click', function() {\n console.log('DEBUG: Start button clicked');\n \n // Immediately update UI\n recordBtn.style.display = 'none';\n stopBtn.style.display = 'inline-block';\n statusElement.textContent = 'Recording...';\n \n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n console.log('DEBUG: Microphone access granted');\n \n mediaRecorder = new MediaRecorder(stream);\n audioChunks = [];\n \n mediaRecorder.addEventListener('dataavailable', event => {\n audioChunks.push(event.data);\n });\n \n mediaRecorder.addEventListener('stop', () => {\n console.log('DEBUG: Audio data available');\n statusElement.textContent = 'Processing...';\n \n // Prevent duplicate submissions\n if (isSubmitting) {\n console.log('DEBUG: Already submitting, ignoring duplicate request');\n return;\n }\n \n isSubmitting = true;\n \n const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });\n console.log('DEBUG: Audio blob created, size:', audioBlob.size, 'bytes');\n \n // Check if the audio blob is valid\n if (audioBlob.size === 0) {\n console.log('DEBUG: Empty audio blob, not sending');\n statusElement.textContent = 'Error: No audio recorded';\n recordBtn.style.display = 'inline-block';\n stopBtn.style.display = 'none';\n isSubmitting = false;\n return;\n }\n \n // Get the conversation ID from the URL\n const pathParts = window.location.pathname.split('/');\n const conversationId = pathParts[pathParts.indexOf('conversations') + 1];\n \n console.log('DEBUG: Sending audio to conversation', conversationId);\n \n // Create FormData and append the audio blob\n const formData = new FormData();\n formData.append('audio', audioBlob, 'recording.wav');\n formData.append('hide_response', 'true'); // Add this flag to hide the AI response initially\n \n // Send the audio to the server\n fetch(`/conversations/${conversationId}/messages`, {\n method: 'POST',\n body: formData,\n headers: {\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n }\n })\n .then(response => {\n console.log('DEBUG: Server response status:', response.status);\n \n // Check if the response is ok\n if (!response.ok) {\n return response.text().then(text => {\n console.log('DEBUG: Error response body:', text);\n throw new Error(`Server responded with ${response.status}: ${text}`);\n });\n }\n \n // Reset submission flag and reload the page\n isSubmitting = false;\n window.location.reload();\n })\n .catch(error => {\n console.log('DEBUG: Error sending audio:', error);\n statusElement.textContent = 'Error: Failed to send audio';\n // Revert UI\n recordBtn.style.display = 'inline-block';\n stopBtn.style.display = 'none';\n isSubmitting = false; // Reset submission flag\n });\n \n // Stop all tracks in the stream to release the microphone\n stream.getTracks().forEach(track => track.stop());\n });\n \n mediaRecorder.start();\n console.log('DEBUG: Recording started');\n })\n .catch(error => {\n console.error('DEBUG: Error accessing microphone:', error);\n statusElement.textContent = 'Error: Could not access microphone';\n // Revert UI if there's an error\n recordBtn.style.display = 'inline-block';\n stopBtn.style.display = 'none';\n });\n });\n \n stopBtn.addEventListener('click', function() {\n console.log('DEBUG: Stop button clicked');\n // Immediately update UI\n stopBtn.style.display = 'none';\n recordBtn.style.display = 'inline-block';\n \n if (mediaRecorder && mediaRecorder.state !== 'inactive') {\n mediaRecorder.stop();\n console.log('DEBUG: MediaRecorder stopped');\n statusElement.textContent = 'Processing...';\n }\n });\n}\n\n/**\n * Set up audio playback event listeners\n */\nfunction setupAudioPlayback() {\n // Find all audio elements\n document.addEventListener('click', function(event) {\n // Handle listen button clicks\n if (event.target.classList.contains('listen-audio-btn')) {\n const messageElement = event.target.closest('.message');\n if (!messageElement) return;\n \n const messageId = messageElement.dataset.messageId;\n const audioElement = messageElement.querySelector('audio');\n \n // Check if this is a user message\n const isUserMessage = messageElement.classList.contains('user-message');\n \n if (isUserMessage) {\n // For user messages, we need to fetch the audio URL from the server\n // Stop any currently playing audio first\n if (currentlyPlayingAudio) {\n currentlyPlayingAudio.pause();\n currentlyPlayingAudio.currentTime = 0;\n \n // Reset UI for the previously playing audio\n if (currentlyPlayingMessageId) {\n toggleAudioControls(currentlyPlayingMessageId, false);\n }\n }\n \n // Show loading state\n toggleAudioControls(messageId, true);\n \n // Fetch the audio URL for this message\n fetch(`/messages/${messageId}/audio`)\n .then(response => {\n if (!response.ok) {\n // If we get a 404, it means the message doesn't exist in the database\n // Let's try to use the content from the DOM instead\n if (response.status === 404) {\n const messageContent = messageElement.querySelector('.message-content');\n if (messageContent && messageContent.textContent.trim()) {\n const content = messageContent.textContent.trim();\n debug(`Using content from DOM for speech generation: ${content}`);\n \n // Make a direct request to generate speech from the content\n return fetch('/messages/generate_speech', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ content: content })\n }).then(speechResponse => {\n if (!speechResponse.ok) {\n throw new Error(`Speech generation failed with status ${speechResponse.status}`);\n }\n return speechResponse.json();\n });\n }\n }\n throw new Error(`Server responded with ${response.status}`);\n }\n return response.json();\n })\n .then(data => {\n if (!data.audio_url) {\n throw new Error('No audio URL returned from server');\n }\n \n // If the audio element doesn't exist, create one\n let audioEl = audioElement;\n if (!audioEl) {\n // Find or create the audio controls div\n let audioControlsDiv = messageElement.querySelector('.audio-controls');\n if (!audioControlsDiv) {\n audioControlsDiv = document.createElement('div');\n audioControlsDiv.className = 'audio-controls';\n audioControlsDiv.style.display = 'none';\n messageElement.appendChild(audioControlsDiv);\n }\n \n // Create a new audio element\n audioEl = document.createElement('audio');\n audioEl.style.display = 'none';\n audioControlsDiv.appendChild(audioEl);\n }\n \n // Remove ALL event listeners to prevent duplicates\n audioEl.onended = null;\n audioEl.oncanplaythrough = null;\n audioEl.onplay = null;\n audioEl.onpause = null;\n audioEl.onloadedmetadata = null;\n \n // Create a clean audio element to avoid any lingering event handlers\n const newAudioEl = document.createElement('audio');\n newAudioEl.src = data.audio_url;\n newAudioEl.style.display = 'none';\n \n // Replace the old audio element with the new one\n if (audioEl.parentNode) {\n audioEl.parentNode.replaceChild(newAudioEl, audioEl);\n audioEl = newAudioEl;\n }\n \n // Play the audio\n audioEl.play()\n .then(() => {\n // Update tracking variables\n currentlyPlayingAudio = audioEl;\n currentlyPlayingMessageId = messageId;\n \n // If we're on iOS, this successful play means autoplay is now enabled\n const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n if (isIOSDevice && !autoplayEnabled) {\n autoplayEnabled = true;\n debug('Autoplay enabled on iOS after user interaction');\n }\n })\n .catch(error => {\n debug(`Failed to play audio for message ${messageId}: ${error.message}`);\n toggleAudioControls(messageId, false);\n });\n \n // Set up ended event handler\n audioEl.onended = function() {\n // Reset UI when audio finishes\n toggleAudioControls(messageId, false);\n \n // Clear tracking variables\n if (currentlyPlayingAudio === audioEl) {\n currentlyPlayingAudio = null;\n currentlyPlayingMessageId = null;\n }\n };\n })\n .catch(error => {\n debug(`Error fetching audio for message ${messageId}: ${error.message}`);\n toggleAudioControls(messageId, false);\n });\n } else {\n // For AI messages, use the existing logic\n if (!audioElement || !audioElement.src) {\n debug('No audio element or source found for message ' + messageId);\n return;\n }\n \n // If there's already an audio playing, stop it\n if (currentlyPlayingAudio && currentlyPlayingAudio !== audioElement) {\n currentlyPlayingAudio.pause();\n currentlyPlayingAudio.currentTime = 0;\n \n // Reset UI for the previously playing audio\n if (currentlyPlayingMessageId) {\n toggleAudioControls(currentlyPlayingMessageId, false);\n }\n }\n \n // Play this audio\n audioElement.play()\n .then(() => {\n // Update UI\n toggleAudioControls(messageId, true);\n \n // Track currently playing audio\n currentlyPlayingAudio = audioElement;\n currentlyPlayingMessageId = messageId;\n \n // If we're on iOS, this successful play means autoplay is now enabled\n const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n if (isIOSDevice && !autoplayEnabled) {\n autoplayEnabled = true;\n debug('Autoplay enabled on iOS after user interaction');\n }\n })\n .catch(error => {\n debug(`Failed to play audio for message ${messageId}: ${error.message}`);\n });\n \n // Set up ended event handler\n audioElement.onended = function() {\n // Reset UI when audio finishes\n toggleAudioControls(messageId, false);\n \n // Clear tracking variables\n if (currentlyPlayingAudio === audioElement) {\n currentlyPlayingAudio = null;\n currentlyPlayingMessageId = null;\n }\n };\n }\n }\n \n // Handle stop button clicks\n if (event.target.classList.contains('stop-audio-btn')) {\n const messageElement = event.target.closest('.message');\n if (!messageElement) return;\n \n const messageId = messageElement.dataset.messageId;\n const audioElement = messageElement.querySelector('audio');\n \n if (audioElement) {\n // Stop the audio\n audioElement.pause();\n audioElement.currentTime = 0;\n \n // Update UI\n toggleAudioControls(messageId, false);\n \n // Clear tracking variables if this was the playing audio\n if (currentlyPlayingAudio === audioElement) {\n currentlyPlayingAudio = null;\n currentlyPlayingMessageId = null;\n }\n }\n }\n });\n \n // Set up autoplay for the latest AI message\n document.addEventListener('DOMContentLoaded', function() {\n // Check if we're on iOS and need special handling\n const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n \n // For non-iOS devices, or iOS with autoplay already enabled, play the latest audio\n if (!isIOSDevice || autoplayEnabled) {\n // Find the last AI message with audio\n const aiMessages = document.querySelectorAll('.ai-message');\n if (aiMessages.length > 0) {\n const lastAIMessage = aiMessages[aiMessages.length - 1];\n const audioElement = lastAIMessage.querySelector('audio');\n \n if (audioElement && audioElement.src) {\n // Try to play the audio\n audioElement.play()\n .then(() => {\n // Update UI\n toggleAudioControls(lastAIMessage.dataset.messageId, true);\n \n // Track currently playing audio\n currentlyPlayingAudio = audioElement;\n currentlyPlayingMessageId = lastAIMessage.dataset.messageId;\n })\n .catch(error => {\n debug(`Failed to autoplay latest AI message audio: ${error.message}`);\n });\n \n // Set up ended event handler\n audioElement.onended = function() {\n // Reset UI when audio finishes\n toggleAudioControls(lastAIMessage.dataset.messageId, false);\n \n // Clear tracking variables\n currentlyPlayingAudio = null;\n currentlyPlayingMessageId = null;\n };\n }\n }\n }\n });\n \n // Also set up a MutationObserver to play audio for newly added AI messages\n const messagesContainer = document.querySelector('.messages-container');\n if (messagesContainer) {\n const observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(mutation) {\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n // Check each added node\n mutation.addedNodes.forEach(function(node) {\n // Check if this is an AI message with audio\n if (node.nodeType === 1 && node.classList.contains('ai-message')) {\n const audioElement = node.querySelector('audio');\n \n if (audioElement && audioElement.src) {\n // Check if we're on iOS and need special handling\n const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n \n // For non-iOS devices, or iOS with autoplay already enabled, play the audio\n if (!isIOSDevice || autoplayEnabled) {\n // Try to play the audio\n audioElement.play()\n .then(() => {\n // Update UI\n toggleAudioControls(node.dataset.messageId, true);\n \n // Track currently playing audio\n currentlyPlayingAudio = audioElement;\n currentlyPlayingMessageId = node.dataset.messageId;\n })\n .catch(error => {\n debug(`Failed to autoplay new AI message audio: ${error.message}`);\n });\n \n // Set up ended event handler\n audioElement.onended = function() {\n // Reset UI when audio finishes\n toggleAudioControls(node.dataset.messageId, false);\n \n // Clear tracking variables\n currentlyPlayingAudio = null;\n currentlyPlayingMessageId = null;\n };\n }\n }\n }\n });\n }\n });\n });\n \n observer.observe(messagesContainer, { childList: true });\n }\n}\n\n/**\n * Initialize the audio handling functionality\n */\nexport function setupAudioHandling(debugFunction) {\n // Set up the debug function\n debug = debugFunction;\n \n // Set up audio recording\n setupAudioRecording();\n \n // Set up audio playback\n setupAudioPlayback();\n \n // Check for autoplay parameter\n checkForAutoplayParameter();\n \n // Return public methods\n return {\n playAudio,\n playLatestAudio,\n toggleAudioControls,\n enableAutoplay,\n isAutoplayEnabled\n };\n}\n","/**\n * UI Controls functionality for the conversation interface\n * Manages buttons, UI state, and user interactions\n */\n\n// Debug helper (imported from main file)\nlet debug;\n\n// Flag to track if we're using iOS-specific flow\nlet isIOSFlow = false;\n\n/**\n * Ensure explain buttons are visible\n */\nfunction ensureExplainButtonsVisible() {\n document.querySelectorAll('.explain-button').forEach(button => {\n button.style.display = 'inline-block';\n button.style.visibility = 'visible';\n button.style.opacity = '1';\n console.log('Made button visible:', button.dataset.messageId);\n });\n}\n\n/**\n * Show improvement popup\n */\nfunction showImprovementPopup(originalMessage, improvedVersion, explanation, messageId) {\n // Get the improvement container\n const improvementContainer = document.getElementById('improvement-container');\n const originalMessageElement = document.getElementById('original-message');\n const improvedMessageElement = document.getElementById('improved-message');\n const explanationElement = document.getElementById('improvement-explanation');\n const acceptButton = document.getElementById('accept-improvement-btn');\n \n // Set the content\n originalMessageElement.textContent = originalMessage;\n improvedMessageElement.textContent = improvedVersion;\n explanationElement.textContent = explanation || 'This is a more accurate way to express your message.';\n \n // Store the message ID for later use\n acceptButton.setAttribute('data-message-id', messageId);\n \n // Show the container\n improvementContainer.style.display = 'block';\n \n // Scroll to the improvement container\n improvementContainer.scrollIntoView({ behavior: 'smooth' });\n \n // Add event listener to the accept button\n acceptButton.onclick = function() {\n if (typeof acceptImprovement === 'function') {\n acceptImprovement(messageId, improvedVersion);\n } else {\n console.error('acceptImprovement function not found');\n }\n };\n}\n\n/**\n * Setup the below messages button - SUPER SIMPLE VERSION\n */\nfunction setupBelowMessagesButton(messageHandler) {\n // Get the button element\n const belowMessagesButton = document.getElementById('below-messages-button');\n if (!belowMessagesButton) {\n console.error('DEBUG: below-messages-button not found');\n return;\n }\n \n console.log('DEBUG: Setting up below messages button - FOUND:', belowMessagesButton);\n \n // Our own recording variables\n let mediaRecorder = null;\n let audioChunks = [];\n \n // Remove any existing click listeners to prevent duplicates\n const newButton = belowMessagesButton.cloneNode(true);\n belowMessagesButton.parentNode.replaceChild(newButton, belowMessagesButton);\n \n // Get user credits from the conversation container\n const conversationContainer = document.querySelector('.conversation-container');\n let userCredits = parseInt(conversationContainer?.dataset.userCredits || 0);\n const isIOSDevice = conversationContainer && conversationContainer.dataset.iosDevice === 'true';\n const isExistingConversation = conversationContainer && conversationContainer.dataset.existingConversation === 'true';\n \n // Update credit counter display\n const updateCreditCounter = (credits) => {\n const creditCounter = document.getElementById('credit-counter');\n if (creditCounter) {\n creditCounter.textContent = `Credits: ${credits}`;\n }\n };\n \n // Check credits and update button state\n const checkCreditsAndUpdateButton = () => {\n // Update button state based on credits\n if (userCredits <= 0) {\n // Disable the button when no credits\n newButton.disabled = true;\n // Show the credit warning message\n const creditWarning = document.getElementById('credit-warning');\n if (creditWarning) {\n creditWarning.style.display = 'block';\n }\n } else {\n // Enable the button when credits available\n newButton.disabled = false;\n // Hide the credit warning message\n const creditWarning = document.getElementById('credit-warning');\n if (creditWarning) {\n creditWarning.style.display = 'none';\n }\n }\n };\n \n // Initial check of credits\n checkCreditsAndUpdateButton();\n \n // Set initial state based on the last message and device type\n if (isIOSDevice) {\n if (isExistingConversation) {\n // For existing conversations on iOS, set button to \"Resume conversation!\"\n newButton.textContent = 'Resume conversation!';\n newButton.dataset.state = 'resume';\n console.log('DEBUG: iOS device detected with existing conversation, setting initial button state to Resume conversation!');\n } else {\n // For new conversations on iOS, set button to \"Start conversation!\"\n newButton.textContent = 'Start conversation!';\n newButton.dataset.state = 'start';\n console.log('DEBUG: iOS device detected, setting initial button state to Start conversation!');\n }\n } else {\n // Standard flow: set button based on last message\n const messages = document.querySelectorAll('.message');\n if (messages.length === 0 || messages[messages.length - 1].classList.contains('ai-message')) {\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n } else {\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n }\n }\n \n console.log('DEBUG: Button initial state:', newButton.dataset.state);\n \n // Add click event listener\n newButton.addEventListener('click', function(event) {\n // Prevent event bubbling\n event.preventDefault();\n event.stopPropagation();\n \n console.log('DEBUG: Button clicked, current state:', newButton.dataset.state);\n \n // If button is disabled, do nothing\n if (newButton.disabled) return;\n \n const currentState = newButton.dataset.state;\n \n if (currentState === 'resume' && isIOSDevice) {\n // iOS-specific resume flow for existing conversations\n console.log('DEBUG: iOS resume button clicked');\n \n // Change to LOADING state temporarily\n newButton.textContent = 'Loading...';\n\n // Request microphone permission\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(async function(stream) {\n console.log('DEBUG: Got microphone access on iOS');\n \n try {\n // Play silent audio to unlock autoplay\n const silentAudio = new Audio('/silent.mp3');\n await silentAudio.play();\n console.log('DEBUG: Successfully played silent audio on iOS');\n \n // If we get here, autoplay is successfully unlocked\n if (window.audioHandler && typeof window.audioHandler.enableAutoplay === 'function') {\n window.audioHandler.enableAutoplay();\n }\n \n // Get all messages and check the last one\n const messages = document.querySelectorAll('.message');\n if (messages.length > 0) {\n const lastMessage = messages[messages.length - 1];\n \n if (lastMessage.classList.contains('ai-message')) {\n // Last message is AI, set to Record state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n \n // Play the audio for the last AI message\n const audioElement = lastMessage.querySelector('audio');\n if (audioElement && audioElement.src) {\n console.log('DEBUG: Playing last AI message audio');\n audioElement.play()\n .then(() => {\n console.log('DEBUG: Successfully played last AI message audio');\n // Update UI to show the audio is playing\n if (typeof toggleAudioControls === 'function') {\n toggleAudioControls(lastMessage.dataset.messageId, true);\n }\n })\n .catch(error => {\n console.error('DEBUG: Failed to play last AI message audio:', error);\n });\n \n // Set up ended event handler\n audioElement.onended = function() {\n // Reset UI when audio finishes\n if (typeof toggleAudioControls === 'function') {\n toggleAudioControls(lastMessage.dataset.messageId, false);\n }\n };\n }\n } else {\n // Last message is user, set to Continue state\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n }\n } else {\n // No messages, set to Record state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n }\n } catch (audioError) {\n console.error('DEBUG: Failed to play audio on iOS:', audioError);\n // Even if audio unlock fails, we can still proceed with the conversation\n // Just without autoplay until the user interacts again\n \n // Set button state based on last message\n const messages = document.querySelectorAll('.message');\n if (messages.length > 0) {\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.classList.contains('ai-message')) {\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n } else {\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n }\n } else {\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n }\n }\n \n // Stop all tracks in the stream to release microphone\n stream.getTracks().forEach(track => track.stop());\n })\n .catch(function(error) {\n console.error('DEBUG: Error accessing microphone on iOS:', error);\n // Keep the button as \"Resume conversation!\" to try again\n newButton.textContent = 'Resume conversation!';\n newButton.dataset.state = 'resume';\n // The user will need to click again to trigger the permission prompt\n });\n }\n else if (currentState === 'start' && isIOSDevice) {\n // iOS-specific start flow\n console.log('DEBUG: iOS start button clicked');\n \n // Change to LOADING state temporarily\n newButton.textContent = 'Loading...';\n\n // Request microphone permission\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(async function(stream) {\n console.log('DEBUG: Got microphone access on iOS');\n \n try {\n // Try to play the first AI message's audio to unlock autoplay\n const aiMessages = document.querySelectorAll('.ai-message');\n \n // First, show all AI messages that were hidden\n aiMessages.forEach(message => {\n message.style.display = 'block';\n });\n \n if (aiMessages.length > 0) {\n // Try to play the first AI message audio\n const firstAIMessage = aiMessages[0];\n const audioElement = firstAIMessage.querySelector('audio');\n \n if (audioElement && audioElement.src) {\n console.log('DEBUG: Playing first AI message audio to unlock autoplay');\n await audioElement.play();\n console.log('DEBUG: Successfully played audio on iOS');\n \n // If we get here, autoplay is successfully unlocked\n if (window.audioHandler && typeof window.audioHandler.enableAutoplay === 'function') {\n window.audioHandler.enableAutoplay();\n }\n } else {\n // If no audio element found in the first message, try to play a silent audio\n console.log('DEBUG: No audio found in first message, playing silent audio');\n const silentAudio = new Audio('/silent.mp3');\n await silentAudio.play();\n console.log('DEBUG: Successfully played silent audio on iOS');\n \n // If we get here, autoplay is successfully unlocked\n if (window.audioHandler && typeof window.audioHandler.enableAutoplay === 'function') {\n window.audioHandler.enableAutoplay();\n }\n }\n } else {\n // If no AI messages found, play silent audio\n console.log('DEBUG: No AI messages found, playing silent audio');\n const silentAudio = new Audio('/silent.mp3');\n await silentAudio.play();\n console.log('DEBUG: Successfully played silent audio on iOS');\n \n // If we get here, autoplay is successfully unlocked\n if (window.audioHandler && typeof window.audioHandler.enableAutoplay === 'function') {\n window.audioHandler.enableAutoplay();\n }\n }\n } catch (audioError) {\n console.error('DEBUG: Failed to play audio on iOS:', audioError);\n // Even if audio unlock fails, we can still proceed with the conversation\n // Just without autoplay until the user interacts again\n }\n \n // Update button to Record state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n \n // Stop all tracks in the stream to release microphone\n stream.getTracks().forEach(track => track.stop());\n })\n .catch(function(error) {\n console.error('DEBUG: Error accessing microphone on iOS:', error);\n // Keep the button as \"Start conversation!\" to try again\n newButton.textContent = 'Start conversation!';\n newButton.dataset.state = 'start';\n // The user will need to click again to trigger the permission prompt\n });\n }\n else if (currentState === 'record') {\n // Change to STOP state\n newButton.textContent = 'Stop';\n newButton.dataset.state = 'stop';\n console.log('DEBUG: Changed button to STOP');\n \n // Show language nudge if this is the first user message\n const userMessages = document.querySelectorAll('.message.user-message');\n if (userMessages.length === 0) {\n // Check if this is a mobile device\n const isMobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\n \n // Only show nudge on non-mobile devices\n if (!isMobileDevice) {\n // Check if we've already shown the nudge in 3 conversations\n const languageNudgeCount = parseInt(localStorage.getItem('language_nudge_count') || '0');\n console.log('DEBUG: Language nudge count:', languageNudgeCount);\n \n // Check if the nudge has been dismissed due to different language usage\n const languageNudgeDismissed = localStorage.getItem('language_nudge_dismissed') === 'true';\n \n if (languageNudgeCount < 3 && !languageNudgeDismissed) {\n const languageNudge = document.getElementById('language-nudge');\n if (languageNudge) {\n console.log('DEBUG: Showing language nudge for first message');\n languageNudge.style.display = 'block';\n }\n }\n } else {\n console.log('DEBUG: Not showing language nudge on mobile device');\n }\n }\n \n // Start recording\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(function(stream) {\n console.log('DEBUG: Got microphone access');\n \n // Check if this is iOS Safari\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n \n // Set appropriate MIME type and options based on browser\n let mimeType = 'audio/webm';\n let recorderOptions = {};\n \n if (isIOS) {\n // For iOS, we need to use a supported format\n if (MediaRecorder.isTypeSupported('audio/mp4')) {\n mimeType = 'audio/mp4';\n } else if (MediaRecorder.isTypeSupported('audio/aac')) {\n mimeType = 'audio/aac';\n } else if (MediaRecorder.isTypeSupported('audio/wav')) {\n mimeType = 'audio/wav';\n }\n console.log('DEBUG: Using iOS-compatible audio format:', mimeType);\n } else {\n // For non-iOS browsers, prefer WebM\n if (MediaRecorder.isTypeSupported('audio/webm')) {\n mimeType = 'audio/webm';\n }\n console.log('DEBUG: Using standard audio format:', mimeType);\n }\n \n // Create MediaRecorder with appropriate options\n try {\n mediaRecorder = new MediaRecorder(stream, { mimeType: mimeType });\n } catch (e) {\n // Fallback to default if specified MIME type isn't supported\n console.log('DEBUG: Specified MIME type not supported, using default');\n mediaRecorder = new MediaRecorder(stream);\n }\n \n // Store the actual MIME type being used for later reference\n const actualMimeType = mediaRecorder.mimeType || (isIOS ? 'audio/mp4' : 'audio/webm');\n console.log('DEBUG: MediaRecorder created with actual MIME type:', actualMimeType);\n \n audioChunks = [];\n \n // Set up dataavailable event handler with proper interval for iOS\n mediaRecorder.addEventListener('dataavailable', function(e) {\n if (e.data.size > 0) {\n audioChunks.push(e.data);\n console.log('DEBUG: Audio chunk received, size:', e.data.size);\n }\n });\n \n // Start recording with appropriate timeslice (smaller for iOS)\n const timeslice = isIOS ? 100 : 1000; // Use smaller chunks on iOS\n mediaRecorder.start(timeslice);\n console.log('DEBUG: Recording started with timeslice:', timeslice, 'ms');\n \n mediaRecorder.addEventListener('stop', function() {\n console.log('DEBUG: Recording stopped, processing audio');\n \n // Get the actual MIME type being used\n const actualMimeType = mediaRecorder.mimeType || (isIOS ? 'audio/mp4' : 'audio/webm');\n \n // Create a blob from the chunks with the correct MIME type\n const audioBlob = new Blob(audioChunks, { type: actualMimeType });\n console.log('DEBUG: Audio blob created with type:', actualMimeType, 'size:', audioBlob.size);\n \n // Check if the audio blob is valid\n if (audioBlob.size === 0) {\n console.error('DEBUG: Empty audio recording');\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n return;\n }\n \n // Determine the correct file extension based on the MIME type\n let fileExtension = 'webm';\n if (actualMimeType.includes('mp4')) fileExtension = 'mp4';\n else if (actualMimeType.includes('aac')) fileExtension = 'aac';\n else if (actualMimeType.includes('wav')) fileExtension = 'wav';\n else if (actualMimeType.includes('ogg')) fileExtension = 'ogg';\n \n // Create a FormData object\n const formData = new FormData();\n formData.append('audio', audioBlob, `recording.${fileExtension}`);\n console.log('DEBUG: Sending audio as', `recording.${fileExtension}`);\n \n // Check if this is a retry - if so, delete the last message\n const messages = document.querySelectorAll('.message');\n if (messages.length > 0) {\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.classList.contains('user-message') && window.isRetry) {\n // This is a retry, so we'll delete the last message\n const messageId = lastMessage.dataset.messageId;\n console.log('DEBUG: This is a retry, deleting last message:', messageId);\n lastMessage.remove();\n window.isRetry = false;\n \n // Store the message ID that's being retried\n if (!window.retriedMessageIds) {\n window.retriedMessageIds = [];\n }\n window.retriedMessageIds.push(messageId);\n }\n }\n \n // Get the conversation ID from the URL\n const pathParts = window.location.pathname.split('/');\n const conversationId = pathParts[pathParts.indexOf('conversations') + 1];\n \n console.log('DEBUG: Sending audio to conversation', conversationId);\n \n // Send the audio to the server with hide_response=true to prevent automatic AI response\n formData.append('hide_response', 'true');\n \n fetch(`/conversations/${conversationId}/messages`, {\n method: 'POST',\n body: formData,\n headers: {\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n }\n })\n .then(response => {\n console.log('DEBUG: Server response status:', response.status);\n \n // Check if the response is ok\n if (!response.ok) {\n if (response.status === 402) { // Payment Required status code\n return response.json().then(data => {\n console.log('DEBUG: Out of credits response:', data);\n // Update credits to 0\n userCredits = 0;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n // Reset button state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n // Throw error to stop the chain\n throw new Error('Out of credits');\n });\n }\n \n return response.text().then(text => {\n console.log('DEBUG: Error response body:', text);\n throw new Error(`Server responded with ${response.status}: ${text}`);\n });\n }\n \n return response.json();\n })\n .then(data => {\n console.log('DEBUG: Message created successfully', data);\n \n // Update user credits from the response\n if (data.credits !== undefined) {\n userCredits = data.credits;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n }\n \n // Instead of immediately reloading, wait for the user to click Continue\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n \n // Use the user_message data to add it to the DOM immediately\n if (data.user_message && messageHandler) {\n messageHandler.addMessageToDOM(data.user_message, 'user');\n }\n })\n .catch(error => {\n console.log('DEBUG: Error sending audio:', error);\n // Reset button state on error\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n });\n \n // Stop all tracks in the stream\n stream.getTracks().forEach(track => track.stop());\n });\n })\n .catch(function(error) {\n console.error('DEBUG: Error accessing microphone:', error);\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n });\n } \n else if (currentState === 'stop') {\n // Change to LOADING state\n newButton.textContent = 'Loading...';\n newButton.dataset.state = 'loading';\n console.log('DEBUG: Changed button to LOADING');\n \n // Hide language nudge when stopping recording\n const languageNudge = document.getElementById('language-nudge');\n if (languageNudge) {\n console.log('DEBUG: Hiding language nudge after recording');\n languageNudge.style.display = 'none';\n }\n \n // Stop recording\n if (mediaRecorder && mediaRecorder.state !== 'inactive') {\n mediaRecorder.stop();\n console.log('DEBUG: MediaRecorder stopped');\n }\n } \n else if (currentState === 'next') {\n // Change to LOADING state\n newButton.textContent = 'Loading...';\n newButton.dataset.state = 'loading';\n console.log('DEBUG: Changed button to Loading... (continue)');\n \n // Get the conversation ID and last message ID\n const conversationId = document.querySelector('.conversation-container').dataset.conversationId;\n const messages = document.querySelectorAll('.message');\n if (messages.length === 0) return;\n \n const lastMessage = messages[messages.length - 1];\n const messageId = lastMessage.dataset.messageId;\n \n // If we have retried messages, remove all but the latest one\n if (window.retriedMessageIds && window.retriedMessageIds.length > 0) {\n console.log('DEBUG: Removing retried messages before continuing:', window.retriedMessageIds);\n \n // Remove all retried messages from the DOM\n window.retriedMessageIds.forEach(id => {\n const messageToRemove = document.querySelector(`.message[data-message-id=\"${id}\"]`);\n if (messageToRemove) {\n console.log('DEBUG: Removing retried message from DOM:', id);\n messageToRemove.remove();\n }\n });\n \n // Clear the retried message IDs\n window.retriedMessageIds = [];\n }\n \n // Send request to continue the conversation\n fetch(`/conversations/${conversationId}/continue`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ message_id: messageId })\n })\n .then(response => {\n // Check if the response is ok\n if (!response.ok) {\n if (response.status === 402) { // Payment Required status code\n return response.json().then(data => {\n console.log('DEBUG: Out of credits response:', data);\n // Update credits to 0\n userCredits = 0;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n // Reset button state\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n // Throw error to stop the chain\n throw new Error('Out of credits');\n });\n }\n \n return response.text().then(text => {\n console.log('DEBUG: Error response body:', text);\n throw new Error(`Server responded with ${response.status}: ${text}`);\n });\n }\n \n return response.json();\n })\n .then(data => {\n console.log('DEBUG: Response from continue:', data);\n \n // Update user credits from the response\n if (data.credits !== undefined) {\n userCredits = data.credits;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n }\n \n if (data.ai_response) {\n // For iOS devices, we need to handle the response differently\n if (isIOSDevice) {\n // Add the AI response to the DOM\n if (messageHandler) {\n messageHandler.addMessageToDOM(data.ai_response, 'ai');\n \n // Set button back to Record state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n \n // Try to play the audio for the new message\n setTimeout(() => {\n const aiMessages = document.querySelectorAll('.ai-message');\n const newAIMessage = aiMessages[aiMessages.length - 1];\n if (newAIMessage) {\n const audioElement = newAIMessage.querySelector('audio');\n if (audioElement && audioElement.src) {\n console.log('DEBUG: Attempting to play audio for new AI message');\n audioElement.play()\n .then(() => {\n console.log('DEBUG: Successfully autoplayed AI response audio');\n // Update UI to show the audio is playing\n toggleAudioControls(newAIMessage.dataset.messageId, true);\n })\n .catch(error => {\n console.error('DEBUG: Failed to autoplay AI response audio:', error);\n });\n \n // Set up ended event handler\n audioElement.onended = function() {\n // Reset UI when audio finishes\n toggleAudioControls(newAIMessage.dataset.messageId, false);\n };\n }\n }\n }, 500); // Small delay to ensure the DOM is updated\n }\n } else {\n // For non-iOS devices, add the AI response to the DOM instead of reloading the page\n if (messageHandler) {\n messageHandler.addMessageToDOM(data.ai_response, 'ai');\n \n // Set button back to Record state\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n }\n }\n } else {\n // No AI response in the data\n console.log('DEBUG: No AI response in continue data');\n // Reset button state\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n }\n })\n .catch(error => {\n console.log('DEBUG: Error continuing conversation:', error);\n // Reset button state on error\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n });\n }\n }, { capture: true }); // Use capture to ensure our handler runs first\n \n // Add a mutation observer to detect when new messages are added\n const messagesContainer = document.querySelector('.messages-container');\n if (messagesContainer) {\n const observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(mutation) {\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n // Update button state based on the last message\n setTimeout(function() {\n // Don't update if we're in the middle of recording or loading\n if (newButton.dataset.state === 'stop' || newButton.dataset.state === 'loading') {\n return;\n }\n \n const messages = document.querySelectorAll('.message');\n if (messages.length > 0) {\n const lastMessage = messages[messages.length - 1];\n \n if (lastMessage.classList.contains('ai-message')) {\n newButton.textContent = 'Record';\n newButton.dataset.state = 'record';\n } else {\n newButton.textContent = 'Continue';\n newButton.dataset.state = 'next';\n \n // Make sure the retry button is visible for the last user message\n const retryContainer = lastMessage.querySelector('.retry-container');\n if (retryContainer) {\n retryContainer.style.display = 'block';\n } else {\n // If the retry container doesn't exist, try to add it\n if (messageHandler && typeof messageHandler.addRetryButtonToLastUserMessage === 'function') {\n messageHandler.addRetryButtonToLastUserMessage();\n }\n }\n }\n }\n }, 100);\n }\n });\n });\n \n observer.observe(messagesContainer, { childList: true });\n }\n \n return {\n updateCreditCounter,\n checkCreditsAndUpdateButton\n };\n}\n\n/**\n * Initialize the UI controls functionality\n */\nexport function setupUIControls(debugFunction, messageHandler) {\n debug = debugFunction;\n \n // Set up the below messages button\n setupBelowMessagesButton(messageHandler);\n \n // Check if we're on iOS\n isIOSFlow = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n debug(`Device detection: iOS = ${isIOSFlow}`);\n \n // Return the public API\n return {\n ensureExplainButtonsVisible,\n showImprovementPopup,\n isIOSFlow\n };\n}\n","/**\n * Message handling functionality for the conversation interface\n * Manages message creation, display, translation, and related UI\n */\n\n// Debug helper (imported from main file)\nlet debug;\n\n/**\n * Add a message to the DOM\n */\nfunction addMessageToDOM(message, senderType) {\n const messagesContainer = document.querySelector('.messages-container');\n if (!messagesContainer) return;\n \n // Create the message element\n const messageDiv = document.createElement('div');\n messageDiv.className = `message ${message.sender_type === 'user' ? 'user-message' : 'ai-message'}`;\n messageDiv.setAttribute('data-message-id', message.id);\n \n // Create the message content\n const contentDiv = document.createElement('div');\n contentDiv.className = 'message-content';\n \n // For user messages with highlighted translation, use it immediately\n if (message.sender_type === 'user' && message.highlighted_translation) {\n contentDiv.innerHTML = message.highlighted_translation;\n } else {\n contentDiv.innerHTML = message.content.replace(/\\n/g, '
');\n }\n \n // Add the content div to the message\n messageDiv.appendChild(contentDiv);\n \n // Create message-buttons container for both buttons\n const buttonsDiv = document.createElement('div');\n buttonsDiv.className = 'message-buttons';\n buttonsDiv.style.display = 'flex';\n buttonsDiv.style.alignItems = 'center';\n buttonsDiv.style.marginTop = '5px';\n \n // Add explain button\n if (message.id && message.id !== 0) {\n const explainContainer = document.createElement('div');\n explainContainer.className = 'tooltip-container';\n \n const explainButton = document.createElement('span');\n explainButton.className = 'explain-button';\n explainButton.style.cursor = 'pointer';\n explainButton.style.color = '#C8AC93';\n explainButton.style.fontSize = '18px';\n explainButton.style.background = 'none';\n explainButton.style.border = 'none';\n explainButton.style.padding = '0';\n explainButton.style.borderRadius = '0';\n explainButton.style.display = 'inline-block';\n explainButton.style.width = '20px';\n explainButton.style.height = '20px';\n explainButton.style.textAlign = 'center';\n explainButton.setAttribute('data-message-id', message.id);\n // No text content - the question mark will be added via CSS\n \n const tooltipText = document.createElement('span');\n tooltipText.className = 'tooltip-text';\n tooltipText.textContent = 'Explain';\n \n explainContainer.appendChild(explainButton);\n explainContainer.appendChild(tooltipText);\n buttonsDiv.appendChild(explainContainer);\n }\n \n // Add listen button for all messages\n const listenButton = document.createElement('button');\n listenButton.className = 'listen-audio-btn';\n listenButton.style.marginLeft = '10px';\n listenButton.style.fontSize = '20px';\n listenButton.style.cursor = 'pointer';\n listenButton.style.background = 'none';\n listenButton.style.border = 'none';\n listenButton.innerHTML = '🔊';\n buttonsDiv.appendChild(listenButton);\n \n // Add stop button (initially hidden) inside the buttons div\n const stopButton = document.createElement('button');\n stopButton.className = 'stop-audio-btn';\n stopButton.style.display = 'none';\n stopButton.style.marginLeft = '10px';\n stopButton.style.fontSize = '20px';\n stopButton.style.cursor = 'pointer';\n stopButton.style.background = 'none';\n stopButton.style.border = 'none';\n stopButton.innerHTML = '⏹️';\n buttonsDiv.appendChild(stopButton);\n \n // Add the buttons div to the message\n messageDiv.appendChild(buttonsDiv);\n \n // Create audio controls div (now just for the audio element)\n const audioControlsDiv = document.createElement('div');\n audioControlsDiv.className = 'audio-controls';\n audioControlsDiv.style.display = 'none'; // Hide this div\n \n // Add audio element\n const audioElement = document.createElement('audio');\n audioElement.style.display = 'none';\n \n if (senderType === 'ai' && message.audio_url) {\n audioElement.src = message.audio_url;\n if (message === messagesContainer.lastElementChild) {\n audioElement.setAttribute('autoplay', '');\n }\n }\n \n audioControlsDiv.appendChild(audioElement);\n \n // Add the audio controls div to the message\n messageDiv.appendChild(audioControlsDiv);\n \n // Add to the container\n messagesContainer.appendChild(messageDiv);\n \n // Scroll to the bottom to ensure the new message is visible\n scrollToBottom(messagesContainer);\n \n // Add an additional scroll after a short delay for both user and AI messages\n // This helps in case there are any layout shifts or dynamic content changes\n setTimeout(() => {\n scrollToBottom(messagesContainer);\n \n // For AI messages, add one more scroll with a longer delay\n // to account for potential audio loading or other async operations\n if (senderType === 'ai') {\n setTimeout(() => {\n scrollToBottom(messagesContainer);\n }, 300);\n }\n }, 100);\n \n return messageDiv;\n}\n\n/**\n * Update button visibility based on the last message\n */\nfunction updateButtonVisibility() {\n const recordButton = document.getElementById('record-button');\n const stopButton = document.getElementById('stop-button');\n const continueButton = document.querySelector('.continue-button');\n \n if (!recordButton || !continueButton) return;\n \n // Get all messages\n const messages = document.querySelectorAll('.message');\n \n // If no messages, show record button\n if (messages.length === 0) {\n recordButton.style.display = 'inline-block';\n if (continueButton) continueButton.style.display = 'none';\n return;\n }\n \n // Get the last message\n const lastMessage = messages[messages.length - 1];\n \n // Check if it's an AI or user message\n const isAiMessage = lastMessage.classList.contains('ai-message');\n \n if (isAiMessage) {\n // If last message is from AI, show record button\n recordButton.style.display = 'inline-block';\n if (continueButton) continueButton.style.display = 'none';\n } else {\n // If last message is from user, show continue button\n recordButton.style.display = 'none';\n if (continueButton) continueButton.style.display = 'inline-block';\n }\n}\n\n/**\n * Ensure message button visibility is correctly applied\n */\nfunction updateMessageButtonsVisibility() {\n const messages = document.querySelectorAll('.message');\n if (messages.length === 0) return;\n \n // Make sure the last message's buttons are always visible\n // This is a backup to the CSS selector in case the DOM is manipulated\n const lastMessage = messages[messages.length - 1];\n \n // Force refresh of the hover state by triggering a reflow\n document.querySelector('.messages-container').style.display = 'flex';\n document.querySelector('.messages-container').offsetHeight; // Force reflow\n document.querySelector('.messages-container').style.display = '';\n}\n\n/**\n * Translate a message if needed\n */\nfunction translateMessageIfNeeded(messageContent, conversationId) {\n // Only translate if the message is from the user (not the AI)\n if (!messageContent || messageContent.trim() === '') return Promise.resolve(messageContent);\n \n return fetch(`/conversations/${conversationId}/messages/translate_to_target_language`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ content: messageContent })\n })\n .then(response => response.json())\n .then(data => {\n return data.translated_content;\n })\n .catch(error => {\n console.error('Error translating message:', error);\n return messageContent; // Return original if translation fails\n });\n}\n\n/**\n * Send a message\n */\nfunction sendMessage(event) {\n event.preventDefault();\n const messageInput = document.getElementById('message_content');\n const messageContent = messageInput.value.trim();\n const conversationId = document.getElementById('conversation-container').dataset.conversationId;\n \n if (messageContent === '') return;\n \n // First display the user's message\n appendUserMessage(messageContent);\n messageInput.value = '';\n \n // Then translate if needed and send to backend\n translateMessageIfNeeded(messageContent, conversationId)\n .then(translatedContent => {\n // Send both original and translated content to the server\n return fetch(`/conversations/${conversationId}/messages`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ \n message: { \n content: messageContent,\n translated_content: translatedContent \n } \n })\n });\n })\n .then(response => response.json())\n .then(data => {\n // Update the displayed user message with the translated version if needed\n if (data.translated_content && data.translated_content !== messageContent) {\n updateUserMessageWithTranslation(data.id, data.translated_content);\n }\n \n // Handle AI response\n appendAiMessage(data.ai_response);\n })\n .catch(error => {\n console.error('Error:', error);\n });\n}\n\n/**\n * Update the displayed message with translation\n */\nfunction updateUserMessageWithTranslation(messageId, translatedContent, highlightedTranslation) {\n const messageElement = document.querySelector(`.message[data-message-id=\"${messageId}\"]`);\n if (messageElement) {\n const contentElement = messageElement.querySelector('.message-content');\n if (contentElement) {\n // Use highlighted translation if available, otherwise use regular translated content\n const displayContent = highlightedTranslation || translatedContent;\n contentElement.innerHTML = displayContent;\n }\n }\n}\n\n/**\n * Replace the original message with the translated version\n */\nfunction updateMessageWithTranslation(messageElement, translatedContent, highlightedTranslation) {\n if (!messageElement || !translatedContent) return;\n \n const contentElement = messageElement.querySelector('.message-content');\n if (contentElement) {\n // Use highlighted translation if available, otherwise use regular translation\n const displayContent = highlightedTranslation || translatedContent;\n \n // Set the content with HTML to preserve bold tags\n contentElement.innerHTML = displayContent;\n \n console.log(\"Replaced message with translation:\", messageElement.dataset.messageId);\n }\n}\n\n/**\n * Check for translated content in messages\n */\nfunction checkForTranslatedContent() {\n console.log(\"Checking for translated content in messages\");\n \n document.querySelectorAll('.user-message').forEach(message => {\n const messageId = message.dataset.messageId;\n const translatedContent = message.dataset.translatedContent;\n const highlightedTranslation = message.dataset.highlightedTranslation;\n \n console.log(`Message ${messageId} translated content:`, translatedContent);\n \n if (translatedContent && translatedContent.trim() !== '') {\n updateMessageWithTranslation(message, translatedContent, highlightedTranslation);\n }\n });\n}\n\n/**\n * Apply highlighted content to messages\n */\nfunction applyHighlightedContent() {\n console.log(\"Checking for highlighted content in messages\");\n \n document.querySelectorAll('.user-message').forEach(message => {\n const messageId = message.dataset.messageId;\n const highlightedTranslation = message.dataset.highlightedTranslation;\n \n if (highlightedTranslation && highlightedTranslation.trim() !== '') {\n console.log(`Message ${messageId} has highlighted translation:`, highlightedTranslation);\n \n const contentElement = message.querySelector('.message-content');\n if (contentElement) {\n // Set the content with HTML to preserve bold tags\n contentElement.innerHTML = highlightedTranslation;\n console.log(`Applied highlighted content to message ${messageId}`);\n }\n }\n });\n}\n\n/**\n * Ensure all messages are visible\n */\nfunction ensureAllMessagesVisible() {\n const messagesContainer = document.querySelector('.messages-container');\n if (!messagesContainer) return;\n \n // Make sure all messages are visible\n document.querySelectorAll('.message').forEach(message => {\n message.style.display = 'block';\n message.style.visibility = 'visible';\n message.style.opacity = '1';\n });\n \n // Scroll to the bottom to ensure the last message is visible\n scrollToBottom(messagesContainer);\n}\n\n/**\n * Scroll to the bottom of a container\n */\nfunction scrollToBottom(container) {\n if (!container) return;\n container.scrollTop = container.scrollHeight;\n console.log('DEBUG: Scrolled to bottom of messages container');\n}\n\n/**\n * Restore scroll position when returning to conversation\n */\nfunction restoreScrollPosition() {\n const messagesContainer = document.querySelector('.messages-container');\n if (!messagesContainer) return;\n \n const savedPosition = sessionStorage.getItem('messagesScrollPosition');\n if (savedPosition) {\n messagesContainer.scrollTop = parseInt(savedPosition);\n // Clear the saved position\n sessionStorage.removeItem('messagesScrollPosition');\n } else {\n // If no saved position, scroll to bottom\n scrollToBottom(messagesContainer);\n }\n}\n\n/**\n * Setup continue button handlers\n */\nfunction setupContinueButtonHandlers() {\n document.addEventListener('click', function(event) {\n if (event.target.matches('.continue-button')) {\n const button = event.target;\n const messageId = button.getAttribute('data-message-id');\n const conversationId = window.location.pathname.split('/').pop();\n \n // Disable the button to prevent multiple clicks\n button.disabled = true;\n button.textContent = 'Loading...';\n \n // Fetch the AI response\n fetch(`/conversations/${conversationId}/continue`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ message_id: messageId })\n })\n .then(response => {\n // Check if the response is ok\n if (!response.ok) {\n if (response.status === 402) { // Payment Required status code\n return response.json().then(data => {\n console.log('DEBUG: Out of credits response:', data);\n // Update credits to 0\n userCredits = 0;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n // Throw error to stop the chain\n throw new Error('Out of credits');\n });\n }\n \n return response.text().then(text => {\n console.log('DEBUG: Error response body:', text);\n throw new Error(`Server responded with ${response.status}: ${text}`);\n });\n }\n \n return response.json();\n })\n .then(data => {\n console.log('DEBUG: Response from continue:', data);\n \n // Update user credits from the response\n if (data.credits !== undefined) {\n userCredits = data.credits;\n // Update the credit counter display\n updateCreditCounter(userCredits);\n // Check credits and update button state\n checkCreditsAndUpdateButton();\n }\n \n if (data.ai_response) {\n // Instead of reloading the page, add the AI response to the DOM\n console.log('DEBUG: AI response received, adding to DOM');\n \n // Add the AI message to the DOM\n addMessageToDOM(data.ai_response, 'ai');\n \n // Update button visibility\n updateButtonVisibility();\n updateMessageButtonsVisibility();\n \n // Re-enable the button\n button.textContent = 'Continue';\n button.disabled = false;\n } else {\n console.error('No AI response received');\n button.textContent = 'Continue';\n button.dataset.state = 'next';\n button.disabled = false;\n }\n })\n .catch(error => {\n console.error('Error fetching AI response:', error);\n button.textContent = 'Try Again';\n button.dataset.state = 'next';\n button.disabled = false;\n });\n }\n });\n}\n\n/**\n * Setup retry button handlers\n */\nfunction setupRetryButtonHandlers() {\n // Only set up the event listener once\n if (window.retryButtonHandlersInitialized) {\n return;\n }\n window.retryButtonHandlersInitialized = true;\n \n document.addEventListener('click', function(event) {\n if (event.target.matches('.retry-button')) {\n console.log('DEBUG: Retry button clicked');\n \n // Set the isRetry flag to true\n window.isRetry = true;\n \n // Get the main button and change it to Record state to restart the recording process\n const mainButton = document.getElementById('below-messages-button');\n if (mainButton) {\n mainButton.textContent = 'Record';\n mainButton.dataset.state = 'record';\n // Trigger a click on the main button to start recording\n setTimeout(() => {\n console.log('DEBUG: Auto-clicking Record button');\n mainButton.click();\n }, 100);\n }\n }\n });\n}\n\n/**\n * Add retry button to the last user message if it's the last message in the conversation\n */\nfunction addRetryButtonToLastUserMessage() {\n const messages = document.querySelectorAll('.message');\n if (messages.length === 0) return;\n \n const lastMessage = messages[messages.length - 1];\n \n // Only add retry button if the last message is from the user\n if (lastMessage.classList.contains('user-message')) {\n const messageId = lastMessage.dataset.messageId;\n \n // Check if this message already has a retry button\n if (!lastMessage.querySelector('.retry-button')) {\n console.log(`Adding retry button to last user message ${messageId}`);\n \n // Check if the main button is in 'next' state (Continue)\n const mainButton = document.getElementById('below-messages-button');\n if (!mainButton || mainButton.dataset.state !== 'next') {\n console.log('Main button not in continue state, not adding retry button');\n return;\n }\n \n // Find the message buttons container\n const buttonsContainer = lastMessage.querySelector('.message-buttons');\n if (!buttonsContainer) {\n console.log('Message buttons container not found');\n return;\n }\n \n // Create the retry button container\n const retryContainer = document.createElement('div');\n retryContainer.className = 'tooltip-container retry-container';\n retryContainer.style.marginLeft = '15px';\n \n // Create the retry button\n const retryButton = document.createElement('span');\n retryButton.className = 'retry-button';\n retryButton.style.cursor = 'pointer';\n retryButton.style.color = '#C8AC93';\n retryButton.style.fontSize = '18px';\n retryButton.style.background = 'none';\n retryButton.style.border = 'none';\n retryButton.innerHTML = '🔄';\n retryButton.setAttribute('data-message-id', messageId);\n \n // Create the tooltip text\n const tooltipText = document.createElement('span');\n tooltipText.className = 'tooltip-text';\n tooltipText.textContent = 'Retry';\n \n // Add elements to the container\n retryContainer.appendChild(retryButton);\n retryContainer.appendChild(tooltipText);\n \n // Add the container to the buttons container\n buttonsContainer.appendChild(retryContainer);\n }\n }\n}\n\n/**\n * Initialize the message handling functionality\n */\nexport function setupMessageHandling(debugFunction) {\n // Set up debug function\n debug = debugFunction;\n \n // Initialize all the message handling functionality\n setupContinueButtonHandlers();\n setupRetryButtonHandlers();\n \n // Check for translated content in messages\n setTimeout(checkForTranslatedContent, 100);\n setTimeout(checkForTranslatedContent, 500);\n \n // Apply highlighted content to messages\n setTimeout(applyHighlightedContent, 500);\n setTimeout(applyHighlightedContent, 1500);\n \n // Ensure all messages are visible\n setTimeout(ensureAllMessagesVisible, 100);\n setTimeout(ensureAllMessagesVisible, 500);\n \n // Return the public API\n return {\n addMessageToDOM,\n updateButtonVisibility,\n updateMessageButtonsVisibility,\n translateMessageIfNeeded,\n sendMessage,\n updateUserMessageWithTranslation,\n updateMessageWithTranslation,\n checkForTranslatedContent,\n applyHighlightedContent,\n ensureAllMessagesVisible,\n scrollToBottom,\n restoreScrollPosition,\n addRetryButtonToLastUserMessage\n };\n}\n","/**\n * Nudge functionality for the conversation interface\n * Manages the display of helpful tips to users\n */\n\n// Debug helper (imported from main file)\nlet debug;\n\n// Local storage keys\nconst SELECTION_NUDGE_DISMISSED_KEY = 'selection_nudge_dismissed';\nconst SELECTION_NUDGE_SHOWN_COUNT_KEY = 'selection_nudge_shown_count';\nconst LANGUAGE_NUDGE_DISMISSED_KEY = 'language_nudge_dismissed';\nconst DIFFERENT_LANGUAGE_USAGE_COUNT_KEY = 'different_language_usage_count';\nconst LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY = 'language_nudge_conversation_count';\nconst LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY = 'language_nudge_shown_conversations';\n\n/**\n * Check if the current device is mobile\n */\nfunction isMobileDevice() {\n return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\n}\n\n/**\n * Check if the selection nudge should be shown\n */\nfunction shouldShowSelectionNudge() {\n // Never show nudges on mobile devices\n if (isMobileDevice()) {\n if (debug) {\n debug('Selection nudge not shown on mobile devices');\n }\n return false;\n }\n \n // If user has already used the selection feature, don't show the nudge\n if (localStorage.getItem(SELECTION_NUDGE_DISMISSED_KEY) === 'true') {\n if (debug) {\n debug('Selection nudge already dismissed permanently');\n }\n return false;\n }\n \n return true;\n}\n\n/**\n * Check if the language nudge should be shown\n */\nfunction shouldShowLanguageNudge() {\n // Never show nudges on mobile devices\n if (isMobileDevice()) {\n if (debug) {\n debug('Language nudge not shown on mobile devices');\n }\n return false;\n }\n \n // If user has already used a different language twice, don't show the nudge\n if (localStorage.getItem(LANGUAGE_NUDGE_DISMISSED_KEY) === 'true') {\n if (debug) {\n debug('Language nudge already dismissed permanently');\n }\n return false;\n }\n \n // Check if we've already shown the nudge in 3 conversations\n const conversationCount = parseInt(localStorage.getItem(LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY) || '0');\n if (conversationCount >= 3) {\n if (debug) {\n debug('Language nudge already shown in 3 conversations');\n }\n return false;\n }\n \n // Get the current conversation ID\n const conversationContainer = document.querySelector('.conversation-container');\n if (!conversationContainer) return true;\n \n const conversationId = conversationContainer.dataset.conversationId;\n if (!conversationId) return true;\n \n // Check if we've already shown the nudge in this conversation\n const shownConversations = JSON.parse(localStorage.getItem(LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY) || '[]');\n if (shownConversations.includes(conversationId)) {\n if (debug) {\n debug('Language nudge already shown in this conversation');\n }\n return false;\n }\n \n return true;\n}\n\n/**\n * Mark that the user has used the selection feature\n */\nfunction dismissSelectionNudge() {\n localStorage.setItem(SELECTION_NUDGE_DISMISSED_KEY, 'true');\n hideSelectionNudge();\n \n if (debug) {\n debug('Selection nudge dismissed permanently');\n }\n}\n\n/**\n * Mark that the user has used a different language\n */\nfunction trackDifferentLanguageUsage() {\n const currentCount = parseInt(localStorage.getItem(DIFFERENT_LANGUAGE_USAGE_COUNT_KEY) || '0');\n const newCount = currentCount + 1;\n localStorage.setItem(DIFFERENT_LANGUAGE_USAGE_COUNT_KEY, newCount.toString());\n \n if (debug) {\n debug(`Different language usage tracked (count: ${newCount})`);\n }\n \n // If the user has used a different language twice, dismiss the nudge permanently\n if (newCount >= 2) {\n dismissLanguageNudge();\n }\n}\n\n/**\n * Mark that the language nudge should be dismissed permanently\n */\nfunction dismissLanguageNudge() {\n localStorage.setItem(LANGUAGE_NUDGE_DISMISSED_KEY, 'true');\n hideLanguageNudge();\n \n if (debug) {\n debug('Language nudge dismissed permanently');\n }\n}\n\n/**\n * Show the selection nudge\n */\nfunction showSelectionNudge() {\n const nudgeElement = document.getElementById('selection-nudge');\n if (nudgeElement && shouldShowSelectionNudge()) {\n // Hide the language nudge if it's visible to avoid overlap\n hideLanguageNudge();\n \n nudgeElement.style.display = 'block';\n \n // Increment the shown count\n const currentCount = parseInt(localStorage.getItem(SELECTION_NUDGE_SHOWN_COUNT_KEY) || '0');\n localStorage.setItem(SELECTION_NUDGE_SHOWN_COUNT_KEY, (currentCount + 1).toString());\n \n if (debug) {\n debug(`Selection nudge shown (count: ${currentCount + 1})`);\n }\n }\n}\n\n/**\n * Show the language nudge\n */\nfunction showLanguageNudge() {\n const nudgeElement = document.getElementById('language-nudge');\n if (nudgeElement && shouldShowLanguageNudge()) {\n // Hide the selection nudge if it's visible to avoid overlap\n hideSelectionNudge();\n \n nudgeElement.style.display = 'block';\n \n // Track that we've shown the nudge in this conversation\n const conversationContainer = document.querySelector('.conversation-container');\n if (conversationContainer) {\n const conversationId = conversationContainer.dataset.conversationId;\n if (conversationId) {\n // Get the list of conversations where we've shown the nudge\n const shownConversations = JSON.parse(localStorage.getItem(LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY) || '[]');\n \n // Add this conversation to the list if it's not already there\n if (!shownConversations.includes(conversationId)) {\n shownConversations.push(conversationId);\n localStorage.setItem(LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY, JSON.stringify(shownConversations));\n \n // Increment the conversation count\n const conversationCount = parseInt(localStorage.getItem(LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY) || '0');\n localStorage.setItem(LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY, (conversationCount + 1).toString());\n \n if (debug) {\n debug(`Language nudge shown in conversation ${conversationId} (total: ${conversationCount + 1})`);\n }\n \n // If we've shown the nudge in 3 conversations, dismiss it permanently\n if (conversationCount + 1 >= 3) {\n if (debug) {\n debug('Language nudge shown in 3 conversations, dismissing permanently');\n }\n // We don't call dismissLanguageNudge() here because we still want to show the nudge in this conversation\n // We just won't show it in any future conversations\n }\n }\n }\n }\n \n if (debug) {\n debug('Language nudge shown');\n }\n }\n}\n\n/**\n * Hide the selection nudge\n */\nfunction hideSelectionNudge() {\n const nudgeElement = document.getElementById('selection-nudge');\n if (nudgeElement) {\n nudgeElement.style.display = 'none';\n \n if (debug) {\n debug('Selection nudge hidden');\n }\n }\n}\n\n/**\n * Hide the language nudge\n */\nfunction hideLanguageNudge() {\n const nudgeElement = document.getElementById('language-nudge');\n if (nudgeElement) {\n nudgeElement.style.display = 'none';\n \n if (debug) {\n debug('Language nudge hidden');\n }\n }\n}\n\n/**\n * Check if we should show the nudge based on message count\n * The nudge should appear after the second AI message\n */\nfunction checkMessageCountForNudge() {\n if (!shouldShowSelectionNudge()) {\n return;\n }\n \n const messages = document.querySelectorAll('.message');\n let aiMessageCount = 0;\n \n // Count AI messages\n messages.forEach(message => {\n if (message.classList.contains('ai-message')) {\n aiMessageCount++;\n }\n });\n \n // Show nudge after the second AI message\n if (aiMessageCount === 2) {\n showSelectionNudge();\n }\n}\n\n/**\n * Setup event listeners for text selection actions\n */\nfunction setupSelectionNudgeListeners() {\n // Create a global event for selection toolbar actions\n window.addEventListener('selectionToolbarAction', function(e) {\n if (debug) {\n debug('Selection toolbar action event received: ' + e.detail.action);\n }\n dismissSelectionNudge();\n });\n \n // Track when the selection toolbar appears and when actions are clicked\n document.addEventListener('mouseup', function() {\n // Small delay to ensure selection is complete\n setTimeout(function() {\n const selection = window.getSelection();\n const selectionText = selection.toString().trim();\n \n // If there's a valid selection, we'll temporarily hide the nudge\n if (selectionText.length > 0) {\n // Only temporarily hide the nudge when text is selected\n hideSelectionNudge();\n }\n }, 10);\n });\n \n // Listen for clicks on the explain button in the selection toolbar\n document.addEventListener('click', function(event) {\n // Check if the user clicked on the explain question mark in the selection toolbar\n if (event.target.closest('.explain-question-mark')) {\n if (debug) {\n debug('User clicked explain in selection toolbar');\n }\n \n // Dispatch a custom event that we can listen for\n window.dispatchEvent(new CustomEvent('selectionToolbarAction', {\n detail: { action: 'explain' }\n }));\n \n dismissSelectionNudge();\n }\n \n // Check if the user clicked on the listen button in the selection toolbar\n if (event.target.closest('.listen-selection-btn')) {\n if (debug) {\n debug('User clicked listen in selection toolbar');\n }\n \n // Dispatch a custom event that we can listen for\n window.dispatchEvent(new CustomEvent('selectionToolbarAction', {\n detail: { action: 'listen' }\n }));\n \n dismissSelectionNudge();\n }\n });\n}\n\n/**\n * Setup event listeners for language nudge\n */\nfunction setupLanguageNudgeListeners() {\n if (debug) {\n debug('Setting up language nudge listeners');\n }\n \n // Reset language nudge for testing\n // Uncomment these lines to reset the language nudge for testing\n // localStorage.removeItem('different_language_usage_count');\n // localStorage.removeItem('language_nudge_dismissed');\n // localStorage.removeItem('language_nudge_conversation_count');\n // localStorage.removeItem('language_nudge_shown_conversations');\n \n // Find the record button\n const recordButton = document.getElementById('record-button');\n const belowMessagesButton = document.getElementById('below-messages-button');\n const actualRecordButton = recordButton || belowMessagesButton;\n \n if (actualRecordButton) {\n if (debug) {\n debug('Found record button with ID: ' + actualRecordButton.id);\n }\n \n // Listen for the record button click to show the language nudge\n actualRecordButton.addEventListener('click', function() {\n if (debug) {\n debug('Record button clicked, state: ' + actualRecordButton.dataset.state);\n }\n \n // Only show the language nudge for the first message in a conversation\n const messages = document.querySelectorAll('.message.user-message');\n if (debug) {\n debug('User messages count: ' + messages.length);\n }\n \n // Check if this is the first user message and the button is in record state\n if (messages.length === 0) {\n if (debug) {\n debug('This is the first user message');\n }\n \n // Check if the button is in record state\n if (actualRecordButton.dataset.state === 'record' || \n actualRecordButton.textContent.trim().toLowerCase() === 'record' ||\n actualRecordButton.classList.contains('record-button')) {\n if (debug) {\n debug('Showing language nudge');\n }\n showLanguageNudge();\n }\n // Check if the button is in stop state\n else if (actualRecordButton.dataset.state === 'stop' || \n actualRecordButton.textContent.trim().toLowerCase() === 'stop' ||\n actualRecordButton.classList.contains('stop-button')) {\n if (debug) {\n debug('Hiding language nudge');\n }\n hideLanguageNudge();\n }\n }\n });\n } else {\n if (debug) {\n debug('Record button not found!');\n }\n }\n \n // Also look for the stop button\n const stopButton = document.getElementById('stop-button');\n if (stopButton) {\n if (debug) {\n debug('Found stop button');\n }\n \n stopButton.addEventListener('click', function() {\n if (debug) {\n debug('Stop button clicked, hiding language nudge');\n }\n hideLanguageNudge();\n });\n }\n \n // Listen for the custom event when a message is detected in a different language\n window.addEventListener('differentLanguageDetected', function(e) {\n if (debug) {\n debug('Different language detected event received');\n }\n trackDifferentLanguageUsage();\n });\n}\n\n/**\n * Initialize the nudge functionality\n */\nexport function setupNudgeHandling(debugFunction) {\n // Set up the debug function\n debug = debugFunction;\n \n if (debug) {\n debug('Setting up nudge handling...');\n debug('Selection nudge dismissed status: ' + localStorage.getItem(SELECTION_NUDGE_DISMISSED_KEY));\n debug('Language nudge dismissed status: ' + localStorage.getItem(LANGUAGE_NUDGE_DISMISSED_KEY));\n debug('Different language usage count: ' + localStorage.getItem(DIFFERENT_LANGUAGE_USAGE_COUNT_KEY));\n debug('Language nudge conversation count: ' + localStorage.getItem(LANGUAGE_NUDGE_CONVERSATION_COUNT_KEY));\n debug('Language nudge shown conversations: ' + localStorage.getItem(LANGUAGE_NUDGE_SHOWN_CONVERSATIONS_KEY));\n }\n \n // Setup event listeners\n setupSelectionNudgeListeners();\n setupLanguageNudgeListeners();\n \n // Check if we should show the nudge based on current message count\n setTimeout(() => {\n checkMessageCountForNudge();\n }, 500); // Small delay to ensure DOM is fully loaded\n \n // Setup observer to detect when new messages are added\n const messagesContainer = document.querySelector('.messages-container');\n if (messagesContainer) {\n const observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(mutation) {\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n // Check if we should show the nudge\n checkMessageCountForNudge();\n }\n });\n });\n \n observer.observe(messagesContainer, { childList: true });\n }\n \n return {\n shouldShowSelectionNudge,\n dismissSelectionNudge,\n showSelectionNudge,\n hideSelectionNudge,\n shouldShowLanguageNudge,\n dismissLanguageNudge,\n showLanguageNudge,\n hideLanguageNudge,\n trackDifferentLanguageUsage\n };\n}\n","/**\n * Explanation functionality for the conversation interface\n * Manages text selection, explanation popups, and related functionality\n */\n\n// Debug helper (imported from main file)\nlet debug;\n\n/**\n * Initialize explanation chunks\n */\nfunction initializeExplanationChunks() {\n const explanationChunks = document.querySelectorAll('.explanation-chunk');\n \n explanationChunks.forEach(chunk => {\n // Add hover effect to highlight related content\n chunk.addEventListener('mouseenter', () => {\n chunk.classList.add('highlight');\n });\n \n chunk.addEventListener('mouseleave', () => {\n chunk.classList.remove('highlight');\n });\n });\n}\n\n/**\n * Setup text selection explanation functionality\n */\nfunction setupTextSelectionExplain() {\n console.log('Setting up text selection explain feature');\n \n // Create a button element that will be shown when text is selected\n const button = document.createElement('button');\n button.textContent = 'Explain Selection';\n button.className = 'selection-explain-btn';\n button.style.position = 'absolute';\n button.style.maxWidth = '500px';\n button.style.whiteSpace = 'normal';\n button.style.textAlign = 'left';\n button.style.display = 'none';\n button.style.zIndex = '9999';\n button.style.backgroundColor = '#D9BAA0';\n button.style.color = 'white';\n button.style.border = 'none';\n button.style.borderRadius = '4px';\n button.style.padding = '10px 18px';\n button.style.cursor = 'pointer';\n button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)';\n button.style.fontSize = '18px';\n document.body.appendChild(button);\n \n // Store the selected text for use in the click handler\n let currentSelectedText = '';\n let currentSenderType = '';\n let messageElement = null;\n let translationLoaded = false;\n let translationExplanation = '';\n let isButtonInteraction = false;\n \n // Function to show the button near the selected text\n function showButtonNearSelection() {\n // If the user is interacting with the button, don't reload the translation\n if (isButtonInteraction) {\n isButtonInteraction = false;\n return;\n }\n \n const selection = window.getSelection();\n if (!selection.rangeCount) return;\n \n currentSelectedText = selection.toString().trim();\n \n if (currentSelectedText.length === 0) {\n button.style.display = 'none';\n return;\n }\n \n // Check if selection is within a message\n let node = selection.anchorNode;\n let isInMessage = false;\n \n while (node && node !== document.body) {\n if (node.nodeType === 1) { // Element node\n if (node.classList && \n (node.classList.contains('message') || \n node.classList.contains('message-content') || \n node.classList.contains('ai-message') || \n node.classList.contains('user-message'))) {\n isInMessage = true;\n messageElement = node.classList.contains('message') ? node : node.closest('.message');\n break;\n }\n }\n node = node.parentNode;\n }\n \n if (!isInMessage || !messageElement) {\n button.style.display = 'none';\n return;\n }\n \n // Determine sender type from the message element\n currentSenderType = messageElement.classList.contains('user-message') ? 'user' : 'ai';\n \n console.log('Valid selection detected:', currentSelectedText);\n \n // Get position of the selection\n const range = selection.getRangeAt(0);\n const rect = range.getBoundingClientRect();\n \n // Position the button above the selection\n button.style.left = `${rect.left + window.scrollX}px`;\n button.style.top = `${rect.top + window.scrollY - 40}px`;\n button.style.display = 'block';\n \n // Reset translation state\n translationLoaded = false;\n translationExplanation = '';\n \n // Initially show \"Loading...\" text with proper icons and add click handlers immediately\n updateButtonContent('Loading...');\n \n // Get the conversation ID\n const conversationId = document.querySelector('.conversation-container').dataset.conversationId;\n \n // Send selected text to the server for explanation\n fetch(`/conversations/${conversationId}/selection_explanations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').content\n },\n body: JSON.stringify({ \n selected_text: currentSelectedText,\n message_id: messageElement ? messageElement.dataset.messageId : null\n })\n })\n .then(response => response.json())\n .then(data => {\n // Store the translation explanation\n translationLoaded = true;\n translationExplanation = data.explanation;\n \n // Update the button to show translation on left, vertical line, question mark, vertical line, and listen button on right\n updateButtonContent(data.explanation);\n })\n .catch(error => {\n console.error('Error:', error);\n translationLoaded = true;\n translationExplanation = 'Translation unavailable';\n updateButtonContent('Translation unavailable');\n });\n \n console.log('Button positioned at:', button.style.left, button.style.top);\n }\n \n // Helper function to update button content and add event listeners\n function updateButtonContent(translationText) {\n button.innerHTML = `\n