From 3b3b613ed60ff4ab80e60c241165532aed1cc4b6 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Wed, 6 May 2026 03:43:08 +0200 Subject: [PATCH] Remove microphone recording and audio transcription functionality --- src/App.jsx | 199 ---------------------------------------------------- 1 file changed, 199 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 5e3cb8a..f3fd9a6 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -458,205 +458,6 @@ export default function App() { } } - function clearAudioTimers() { - if (audioTickTimerRef.current) { - window.clearInterval(audioTickTimerRef.current) - audioTickTimerRef.current = null - } - if (audioAutoStopTimerRef.current) { - window.clearTimeout(audioAutoStopTimerRef.current) - audioAutoStopTimerRef.current = null - } - } - - function cleanupAudioRecorder(stream = audioStreamRef.current) { - clearAudioTimers() - stopMediaStream(stream) - if (audioStreamRef.current === stream) { - audioStreamRef.current = null - } - audioRecorderRef.current = null - } - - async function transcribeRecordedAudio(blob, mimeType) { - if (!backendApiUrl) { - throw new Error('The Heimgeist backend is not configured.') - } - - const controller = new AbortController() - audioTranscriptionAbortRef.current = controller - setIsTranscribingAudio(true) - - try { - const dataUrl = await readFileAsDataUrl(blob) - const commaIndex = dataUrl.indexOf(',') - if (commaIndex <= 5) { - throw new Error('Recorded audio could not be encoded for upload.') - } - const header = dataUrl.slice(0, commaIndex) - const payload = dataUrl.slice(commaIndex + 1) - if (!/^data:[^,]+;base64$/i.test(header) || !payload) { - throw new Error('Recorded audio could not be encoded for upload.') - } - const detectedMimeType = header - .slice(5) - .replace(/;base64$/i, '') - .trim() - - const response = await fetch(`${backendApiUrl}/audio/transcribe`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - signal: controller.signal, - body: JSON.stringify({ - mime_type: mimeType || detectedMimeType || 'audio/webm', - audio_base64: payload, - model: transcriptionModel || null, - language: audioInputLanguage || null, - }), - }) - const data = await expectBackendJson(response) - const transcript = String(data?.text || '').trim() - - if (!transcript) { - window.alert('No speech was detected. Try again and speak closer to the selected microphone.') - return - } - - setInput(prev => appendTranscriptToComposer(prev, transcript)) - requestAnimationFrame(() => textareaRef.current?.focus()) - } catch (error) { - if (isAbortError(error)) { - return - } - throw error - } finally { - if (audioTranscriptionAbortRef.current === controller) { - audioTranscriptionAbortRef.current = null - } - setIsTranscribingAudio(false) - } - } - - async function stopAudioRecording(options = {}) { - const { shouldTranscribe = true } = options - const recorder = audioRecorderRef.current - const stopPromise = audioStopPromiseRef.current - const mimeType = audioRecorderMimeTypeRef.current || recorder?.mimeType || 'audio/webm' - - if (!recorder || !stopPromise) { - return - } - - setIsRecordingAudio(false) - clearAudioTimers() - - try { - if (recorder.state !== 'inactive') { - recorder.stop() - } - - const blob = await stopPromise - if (!shouldTranscribe) { - return - } - if (!blob || blob.size <= 0) { - throw new Error('Recorded audio was empty.') - } - await transcribeRecordedAudio(blob, mimeType) - } catch (error) { - if (shouldTranscribe) { - console.error('Failed to stop microphone recording', error) - window.alert(`Microphone transcription failed: ${getErrorText(error)}`) - } - } finally { - audioStopPromiseRef.current = null - audioChunksRef.current = [] - audioRecorderMimeTypeRef.current = '' - audioStartedAtRef.current = 0 - setAudioRecordingMs(0) - } - } - - async function startAudioRecording() { - if (!audioInputEnabled || !audioInputRuntimeReady || isRecordingAudio || isTranscribingAudio || isSending) { - return - } - if (!supportsAudioInputCapture()) { - window.alert('Microphone capture is not available in this environment.') - return - } - - let stream = null - try { - stream = await navigator.mediaDevices.getUserMedia(getAudioInputConstraints(audioInputDeviceId)) - } catch (error) { - console.error('Failed to access microphone', error) - window.alert(`Microphone access failed: ${getErrorText(error)}`) - return - } - - const preferredMimeType = getPreferredAudioRecorderMimeType() - let recorder = null - try { - recorder = preferredMimeType - ? new MediaRecorder(stream, { mimeType: preferredMimeType }) - : new MediaRecorder(stream) - } catch (error) { - cleanupAudioRecorder(stream) - console.error('Failed to create audio recorder', error) - window.alert(`Microphone recording is not available: ${getErrorText(error)}`) - return - } - - audioStreamRef.current = stream - audioRecorderRef.current = recorder - audioChunksRef.current = [] - audioRecorderMimeTypeRef.current = recorder.mimeType || preferredMimeType || 'audio/webm' - audioStartedAtRef.current = Date.now() - setAudioRecordingMs(0) - setIsRecordingAudio(true) - - recorder.ondataavailable = (event) => { - if (event.data && event.data.size > 0) { - audioChunksRef.current.push(event.data) - } - } - - audioStopPromiseRef.current = new Promise((resolve, reject) => { - recorder.onstop = () => { - const blob = new Blob(audioChunksRef.current, { - type: recorder.mimeType || audioRecorderMimeTypeRef.current || 'audio/webm', - }) - cleanupAudioRecorder(stream) - resolve(blob) - } - recorder.onerror = (event) => { - cleanupAudioRecorder(stream) - reject(event?.error || new Error('Audio recording failed.')) - } - }) - - audioTickTimerRef.current = window.setInterval(() => { - setAudioRecordingMs(Date.now() - audioStartedAtRef.current) - }, AUDIO_RECORDING_TICK_MS) - audioAutoStopTimerRef.current = window.setTimeout(() => { - stopAudioRecording() - }, MAX_AUDIO_RECORDING_MS) - - recorder.start() - } - - async function toggleAudioRecording() { - if (isTranscribingAudio) { - return - } - if (isRecordingAudio) { - await stopAudioRecording() - return - } - await startAudioRecording() - } - async function handleComposerImageSelection(event) { const files = event.target?.files try {