import { Streamlit, StreamlitComponentBase, withStreamlitConnection, } from "streamlit-component-lib" import React, { ReactNode } from "react" import AudioReactRecorder, { RecordState } from 'audio-react-recorder' import 'audio-react-recorder/dist/index.css' interface State { isFocused: boolean recordState: null audioDataURL: string reset: boolean } class StAudioRec extends StreamlitComponentBase { public state = { isFocused: false, recordState: null, audioDataURL: '', reset: false} public render = (): ReactNode => { // Arguments that are passed to the plugin in Python are accessible // Streamlit sends us a theme object via props that we can use to ensure // that our component has visuals that match the active theme in a // streamlit app. const { theme } = this.props const style: React.CSSProperties = {} const { recordState } = this.state // compatibility with older vers of Streamlit that don't send theme object. if (theme) { // Use the theme object to style our button border. Alternatively, the // theme style is defined in CSS vars. const borderStyling = `1px solid ${ this.state.isFocused ? theme.primaryColor : "gray"}` style.border = borderStyling style.outline = borderStyling } return (
) } private onClick_start = () => { this.setState({ reset: false, audioDataURL: '', recordState: RecordState.START }) Streamlit.setComponentValue('') } private onClick_stop = () => { this.setState({ reset: false, recordState: RecordState.STOP }) } private onClick_reset = () => { this.setState({ reset: true, audioDataURL: '', recordState: RecordState.STOP }) Streamlit.setComponentValue('') } private onClick_continue = () => { if (this.state.audioDataURL !== '') { // get datetime string for filename let datetime = new Date().toLocaleString(); datetime = datetime.replace(' ', ''); datetime = datetime.replace(/_/g, ''); datetime = datetime.replace(',', ''); var filename = 'streamlit_audio_' + datetime + '.wav'; // auromatically trigger download const a = document.createElement('a'); a.style.display = 'none'; a.href = this.state.audioDataURL; a.download = filename; document.body.appendChild(a); a.click(); } } private onStop_audio = (data) => { if (this.state.reset === true) { this.setState({ audioDataURL: '' }) Streamlit.setComponentValue('') }else{ this.setState({ audioDataURL: data.url }) fetch(data.url).then(function(ctx){ return ctx.blob() }).then(function(blob){ // converting blob to arrayBuffer, this process step needs to be be improved // this operation's time complexity scales exponentially with audio length return (new Response(blob)).arrayBuffer() }).then(function(buffer){ Streamlit.setComponentValue({ "arr": new Uint8Array(buffer) }) }) } } } // "withStreamlitConnection" is a wrapper function. It bootstraps the // connection between your component and the Streamlit app, and handles // passing arguments from Python -> Component. // You don't need to edit withStreamlitConnection (but you're welcome to!). export default withStreamlitConnection(StAudioRec) // Tell Streamlit we're ready to start receiving data. We won't get our // first RENDER_EVENT until we call this function. Streamlit.setComponentReady() // Finally, tell Streamlit to update our initial height. We omit the // `height` parameter here to have it default to our scrollHeight. Streamlit.setFrameHeight()