| document.addEventListener('DOMContentLoaded', () => { |
| const startBtn = document.getElementById('start-mic-btn'); |
| const stopBtn = document.getElementById('stop-mic-btn'); |
| const clearBtn = document.getElementById('clear-btn'); |
| const serviceSelect = document.getElementById('service-select'); |
| const langSelect = document.getElementById('lang-select'); |
| const deeplKeyInput = document.getElementById('deepl-key'); |
| const deeplLabel = document.getElementById('deepl-label'); |
|
|
| const englishOutput = document.getElementById('english-output'); |
| const realtimeOutput = document.getElementById('realtime-output'); |
| const detailedOutput = document.getElementById('detailed-output'); |
| const statusLabel = document.getElementById('status-label'); |
|
|
| let isRecording = false; |
| let audioContext; |
| let processor; |
| let eventSource = null; |
| let lastEnglishText = ""; |
| let lastRealtimeText = ""; |
|
|
| |
| serviceSelect.addEventListener('change', (e) => { |
| if (e.target.value === 'DeepL') { |
| deeplKeyInput.style.display = 'inline-block'; |
| deeplLabel.style.display = 'inline-block'; |
| } else { |
| deeplKeyInput.style.display = 'none'; |
| deeplLabel.style.display = 'none'; |
| } |
| }); |
|
|
| |
| function sendAudioToServer(data) { |
| if (!isRecording) return; |
| fetch('/upload_audio', { |
| method: 'POST', |
| body: data, |
| headers: { |
| 'Content-Type': 'application/octet-stream' |
| } |
| }).catch(error => console.error('Error sending audio:', error)); |
| } |
| |
| |
| function startEventSource() { |
| const params = new URLSearchParams({ |
| target_lang: langSelect.value, |
| service: serviceSelect.value, |
| deepl_key: deeplKeyInput.value |
| }); |
| |
| eventSource = new EventSource(`/stream_results?${params.toString()}`); |
| |
| eventSource.onmessage = (event) => { |
| const data = JSON.parse(event.data); |
| const asrText = data.english; |
| const asrType = data.type; |
| const translation = data.translation; |
| |
| if (asrType === "partial") { |
| |
| englishOutput.textContent = lastEnglishText + asrText; |
| realtimeOutput.textContent = lastRealtimeText + translation; |
|
|
| } else if (asrType === "final") { |
| |
| lastEnglishText += asrText + "\n"; |
| lastRealtimeText += translation + "\n"; |
|
|
| |
| detailedOutput.textContent += asrText + " --> " + translation + "\n"; |
| |
| |
| englishOutput.textContent = lastEnglishText; |
| realtimeOutput.textContent = lastRealtimeText; |
| } |
| englishOutput.scrollTop = englishOutput.scrollHeight; |
| realtimeOutput.scrollTop = realtimeOutput.scrollHeight; |
| detailedOutput.scrollTop = detailedOutput.scrollHeight; |
| }; |
| |
| eventSource.onerror = (err) => { |
| console.error("EventSource hatası:", err); |
| statusLabel.textContent = "🔴 Hata: Bağlantı kesildi!"; |
| statusLabel.style.color = "#ff453a"; |
| if (eventSource) eventSource.close(); |
| stopRecording(); |
| }; |
| } |
| |
| function stopEventSource() { |
| if (eventSource) { |
| eventSource.close(); |
| eventSource = null; |
| } |
| } |
|
|
| |
| startBtn.addEventListener('click', async () => { |
| if (isRecording) return; |
| isRecording = true; |
| startBtn.style.display = 'none'; |
| stopBtn.style.display = 'block'; |
| statusLabel.textContent = "🟢 Kaydediyor..."; |
| statusLabel.style.color = "#30d158"; |
| |
| |
| englishOutput.textContent = ""; |
| realtimeOutput.textContent = ""; |
| detailedOutput.textContent = ""; |
| lastEnglishText = ""; |
| lastRealtimeText = ""; |
|
|
| try { |
| const stream = await navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 16000 } }); |
| audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 }); |
| const source = audioContext.createMediaStreamSource(stream); |
| |
| const bufferSize = 4096; |
| processor = audioContext.createScriptProcessor(bufferSize, 1, 1); |
| |
| source.connect(processor); |
| processor.connect(audioContext.destination); |
|
|
| processor.onaudioprocess = (e) => { |
| if (!isRecording) return; |
| const pcmData = e.inputBuffer.getChannelData(0); |
| const pcm16 = new Int16Array(pcmData.length); |
| for (let i = 0; i < pcmData.length; i++) { |
| pcm16[i] = Math.max(-1, Math.min(1, pcmData[i])) * 0x7FFF; |
| } |
| sendAudioToServer(pcm16.buffer); |
| }; |
|
|
| await fetch('/start', { method: 'POST' }); |
| startEventSource(); |
|
|
| } catch (err) { |
| console.error('Mikrofon erişimi reddedildi veya hata oluştu:', err); |
| statusLabel.textContent = "🔴 Hata: Mikrofon erişimi reddedildi!"; |
| statusLabel.style.color = "#ff453a"; |
| isRecording = false; |
| startBtn.style.display = 'block'; |
| stopBtn.style.display = 'none'; |
| } |
| }); |
|
|
| stopBtn.addEventListener('click', () => { |
| stopRecording(); |
| }); |
|
|
| function stopRecording() { |
| if (!isRecording) return; |
| isRecording = false; |
| if (audioContext) { |
| audioContext.close(); |
| audioContext = null; |
| } |
| |
| startBtn.style.display = 'block'; |
| stopBtn.style.display = 'none'; |
| statusLabel.textContent = "🔴 Hazır - 'Başlat' butonuna basın"; |
| statusLabel.style.color = "#30d158"; |
| |
| stopEventSource(); |
| fetch('/stop', { method: 'POST' }); |
| } |
|
|
| clearBtn.addEventListener('click', () => { |
| englishOutput.textContent = ""; |
| realtimeOutput.textContent = ""; |
| detailedOutput.textContent = ""; |
| lastEnglishText = ""; |
| lastRealtimeText = ""; |
| statusLabel.textContent = "🟢 Tüm veriler temizlendi."; |
| }); |
| }); |