Audio recording feature in dash app

I would like to embed an audio recording feature in my dash app. If the user clicks a ‘RECORD’ button, the app should record the audio until a ‘STOP’ button is clicked and then I would like to process that audio file in the backend. Is that possible? I searched everywhere and I don’t find a relevant solution to my problem.

@chriddyp - Please suggest

Looks like there are a few React components out there that may do this:


Your best bet is wrapping these React components for use in Dash: https://plot.ly/dash/plugins

If you’re working at a company that has a budget for this work, Plotly could wrap them for you: https://plot.ly/products/react/

2 Likes

I couldn’t find an answer to the question myself, so I had to create one myself.

  1. create recorder.js file inside the assets directory
  • your_project
    • app.py
    • assets/recorder.js
  1. You will need to add two buttons to your application with ids start-button and stop-button, feel free to name it something different. Change the names in javascript as well then.

You will need to create something like

@app.server.route('/save-audio', methods=['POST'])
def save_audio():
    audio = request.files['audio']
    audio.save(os.path.join('your_desired_directory', 'audio.wav'))  # Replace with your desired directory
    return 'Audio file saved successfully!', 200

in you application to handle the audio output in the backend.

document.addEventListener('DOMContentLoaded', () => {
    document.addEventListener('click', (event) => {
        const startButton = event.target.closest('#start-button');
        const stopButton = event.target.closest('#stop-button');

        if (startButton) {
            // Logic for starting recording
            startRecording();
        }

        if (stopButton) {
            // Logic for stopping recording
            stopRecording();
        }
    });
});

let mediaRecorder;
let audioChunks = [];

function startRecording() {
    console.log('Start recording...');
    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(stream => {
            mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.ondataavailable = (event) => {
                if (event.data.size > 0) {
                    audioChunks.push(event.data);
                }
            };

            mediaRecorder.onstop = () => {
                saveAudioFile(audioChunks);
                audioChunks = [];
            };

            mediaRecorder.start();
            console.log('MediaRecorder started.');
        })
        .catch(error => console.error('Error accessing microphone:', error));
}

function stopRecording() {
    console.log('Stop recording.');
    if (mediaRecorder && mediaRecorder.state === 'recording') {
        mediaRecorder.stop();

        // Stop the MediaRecorder and release the microphone stream
        mediaRecorder.stop();
        const streamTracks = mediaRecorder.stream.getTracks();
        streamTracks.forEach(track => track.stop());

        mediaRecorder = null;  // Release the MediaRecorder
    }
}

function saveAudioFile(audioChunks) {
    const blob = new Blob(audioChunks, { type: 'audio/wav' });
    const formData = new FormData();
    formData.append('audio', blob, 'audio.wav');

    // Send an AJAX request to the server to save the audio
    const xhr = new XMLHttpRequest();
    xhr.open('POST', '/save-audio', true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            console.log('Audio file saved successfully.');

            // Clear the recorded audio chunks after saving
            audioChunks = [];
            console.log('Audio chuncks cleaned');
        } else {
            console.error('Error saving audio:', xhr.statusText);
        }
    };
    xhr.send(formData);
}

In case this helps anyone else, I have abstracted the audio recording work I’ve needed for projects in dash-recording-components · PyPI. It’s very basic and I need to add some more documentation, but I’m hoping this will help out the community. Also, props to @ed-the-great , this work is also excellent.