(function() { var _inited = false; document.addEventListener('tabChanged', function(e) { if (e.detail.tab !== 'dictation' || _inited) return; _inited = true; var recordBtn = document.getElementById('dict-record-btn'); var pauseBtn = document.getElementById('dict-pause-btn'); var indicator = document.getElementById('dict-recording-indicator'); var timerEl = document.getElementById('dict-timer'); var transcript = document.getElementById('dict-transcript'); var clearBtn = document.getElementById('dict-clear'); var generateBtn = document.getElementById('dict-generate-btn'); var outputCard = document.getElementById('dict-output'); var hpiText = document.getElementById('dict-hpi-text'); var modelTag = document.getElementById('dict-model-tag'); var recorder = new AudioRecorder(); var timer = createTimer(timerEl); var isRecording = false; var isPaused = false; var recognition = createSpeechRecognition(); var finalText = ''; if (recognition) { recognition.onresult = function(e) { var interim = ''; for (var i = e.resultIndex; i < e.results.length; i++) { if (e.results[i].isFinal) finalText += e.results[i][0].transcript + ' '; else interim = e.results[i][0].transcript; } transcript.innerHTML = finalText + (interim ? '' + interim + '' : ''); }; recognition.onend = function() { if (isRecording && !isPaused) try { recognition.start(); } catch(e) {} }; } recordBtn.addEventListener('click', function() { if (!isRecording) { finalText = ''; recorder.start().then(function() { isRecording = true; isPaused = false; recordBtn.classList.add('recording'); recordBtn.querySelector('span').textContent = 'Stop'; if (pauseBtn) pauseBtn.classList.remove('hidden'); indicator.classList.remove('hidden'); timer.start(); if (recognition) try { recognition.start(); } catch(e) {} document.dispatchEvent(new CustomEvent('recording-started', { detail: { module: 'dict' } })); }).catch(function() { showToast('Microphone denied', 'error'); }); } else { isRecording = false; isPaused = false; var dur = timer.stop(); recordBtn.classList.remove('recording'); recordBtn.querySelector('span').textContent = 'Start Dictation'; if (pauseBtn) { pauseBtn.classList.add('hidden'); pauseBtn.innerHTML = ' Pause'; } indicator.classList.add('hidden'); if (recognition) try { recognition.stop(); } catch(e) {} document.dispatchEvent(new CustomEvent('recording-stopped', { detail: { module: 'dict' } })); showLoading('Transcribing...'); recorder.stop().then(function(blob) { if (!blob || blob.size === 0) { hideLoading(); if (finalText.trim()) transcript.textContent = finalText.trim(); return; } return transcribeAudio(blob).then(function(data) { hideLoading(); if (data.success) { transcript.textContent = data.text; showToast('Transcribed ' + dur + 's', 'success'); } else { if (finalText.trim()) transcript.textContent = finalText.trim(); } }); }).catch(function() { hideLoading(); if (finalText.trim()) transcript.textContent = finalText.trim(); }); } }); // Pause / Resume if (pauseBtn) { pauseBtn.addEventListener('click', function() { if (!isRecording) return; if (!isPaused) { if (recorder.mediaRecorder && recorder.mediaRecorder.state === 'recording') { recorder.mediaRecorder.pause(); timer.stop(); isPaused = true; pauseBtn.innerHTML = ' Resume'; pauseBtn.classList.add('btn-primary'); pauseBtn.classList.remove('btn-ghost'); if (recognition) try { recognition.stop(); } catch(e) {} showToast('Paused', 'info'); } } else { if (recorder.mediaRecorder && recorder.mediaRecorder.state === 'paused') { recorder.mediaRecorder.resume(); timer.start(); isPaused = false; pauseBtn.innerHTML = ' Pause'; pauseBtn.classList.remove('btn-primary'); pauseBtn.classList.add('btn-ghost'); if (recognition) try { recognition.start(); } catch(e) {} showToast('Resumed', 'info'); } } }); } clearBtn.addEventListener('click', function() { transcript.textContent = ''; finalText = ''; outputCard.classList.add('hidden'); window._savedEncId_dictation = null; var labelEl = document.getElementById('dict-label'); if (labelEl) labelEl.value = ''; }); generateBtn.addEventListener('click', function() { var text = transcript.innerText.trim(); if (!text) { showToast('No dictation', 'error'); return; } var outputType = document.getElementById('dict-output-type').value; var endpoint, bodyData; if (outputType === 'soap-full' || outputType === 'soap-subjective') { endpoint = '/api/generate-soap'; bodyData = { transcript: text, patientAge: document.getElementById('dict-age').value, patientGender: document.getElementById('dict-gender').value, type: outputType === 'soap-full' ? 'full' : 'subjective', model: getSelectedModel() }; } else { endpoint = '/api/generate-hpi-dictation'; bodyData = { transcript: text, patientAge: document.getElementById('dict-age').value, patientGender: document.getElementById('dict-gender').value, setting: document.getElementById('dict-setting').value, model: getSelectedModel() }; } showLoading('Generating...'); fetch(endpoint, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(bodyData) }) .then(function(r) { return r.json(); }) .then(function(data) { hideLoading(); if (data.success) { setOutputText(hpiText, data.hpi || data.soap); modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); outputCard.scrollIntoView({ behavior: 'smooth' }); showToast('Generated!', 'success'); } else showToast(data.error || 'Failed', 'error'); }) .catch(function(err) { hideLoading(); showToast(err.message, 'error'); }); }); document.getElementById('dict-refine-btn').addEventListener('click', function() { refineDocument('dict-hpi-text', 'dict-refine-input'); }); document.getElementById('dict-shorten-btn').addEventListener('click', function() { shortenDocument('dict-hpi-text'); }); // Register load handler if (typeof registerEncounterLoadHandler === 'function') { registerEncounterLoadHandler('dictation', function(enc) { if (enc.transcript) transcript.textContent = enc.transcript; if (enc.generated_note) { hpiText.textContent = enc.generated_note; outputCard.classList.remove('hidden'); } }); } console.log('✅ Dictation module loaded'); }); })();