dash-recording-components 1.0.3
A Dash component for recording audio from the browser
License: MIT
Requires Python: >=3.8,<3.12


# Overview
A Dash component for recording audio. The component is built using [microphone-stream](https://www.npmjs.com/package/microphone-stream). The component is a work in progress and is not yet ready for production use. 

# Installation
Simply install the package using pip:
```shell
pip install dash-recording-components
```

and import the `AudioRecorder` component:
```python
from dash_recording_components import AudioRecorder
```

# Use-Cases
Currently, there is only one Dash component being built: `AudioRecorder`, in the `dash_recording_components` package, which is built from the React component in `src/lib/components/AudioRecorder.react.js`. An example application using the component can be seen below (note this also uses the excellent library [soundfile](https://pypi.org/project/SoundFile/) and numpy to save the audio to a wav file for use in an `AudioPlayer`).

```python
import dash
from dash import html
from dash.dependencies import Input, Output, State
from dash_recording_components import AudioRecorder
import soundfile as sf
import numpy as np
import io
import base64

app = dash.Dash(__name__)

app.layout = html.Div([
    html.H1("Audio Recorder and Player"),
    html.Button("Record", id="record-button"),
    html.Button("Stop Recording", id="stop-button", n_clicks=0),
    html.Button("Play", id="play-button"),
    html.Div(id="audio-output"),
    html.Div(id="dummy-output", style={"display": "none"}),
    AudioRecorder(id="audio-recorder")
])

audio_samples = []  


@app.callback(
    Output("audio-recorder", "recording"),
    Input("record-button", "n_clicks"),
    Input("stop-button", "n_clicks"),
    State("audio-recorder", "recording"),
    prevent_initial_call=True
)
def control_recording(record_clicks, stop_clicks, recording):
    return record_clicks > stop_clicks


@app.callback(
    Output("audio-output", "children"),
    Input("play-button", "n_clicks"),
    prevent_initial_call=True
)
def play_audio(play_clicks):
    if play_clicks:
        if audio_samples:
            # when we play the audio we need to convert to b64 encoded wav and provide it as a data URI
            audio_array = np.array(audio_samples)
            with io.BytesIO() as wav_buffer:
                sf.write(wav_buffer, audio_array, 16000, format="WAV")
                wav_bytes = wav_buffer.getvalue()
                wav_base64 = base64.b64encode(wav_bytes).decode()
                audio_src = f"data:audio/wav;base64,{wav_base64}"
                return html.Audio(src=audio_src, controls=True)
    return ""


@app.callback(
    Output("dummy-output", "children"),
    Input("audio-recorder", "audio"),
    prevent_initial_call=True
)
def update_audio(audio):
    # running list of the audio samples, aggregated on the server
    global audio_samples
    if audio is not None:
        # Update the audio samples with the new audio
        audio_samples += list(audio.values())
    return ""


if __name__ == "__main__":
    app.run_server(debug=True)
```


# Development and Contributing
Contributions welcome! To get started, clone the repo and follow the steps below:

- Create a Poetry environment and install all required development dependencies: `poetry install --dev`
- Install [webpack](https://webpack.js.org/)
- Install `npm` 
- `npm install` to install the dependencies
- Build the js files: `npm run build:js`
- Build the Dash components (Python modules): `npm run build:py`

Changes in the React components  (`src/lib/components`), such as exposing new properties or updating audio collection logic require running steps 5 and 6 above. The existing autogenerated Python modules should not be edited.