Spaces:
Sleeping
Sleeping
File size: 4,662 Bytes
be77781 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
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<State> {
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 (
<span>
<div>
<button id='record' onClick={this.onClick_start}>
Start Recording
</button>
<button id='stop' onClick={this.onClick_stop}>
Stop
</button>
<button id='reset' onClick={this.onClick_reset}>
Reset
</button>
<button id='continue' onClick={this.onClick_continue}>
Download
</button>
<AudioReactRecorder
state={recordState}
onStop={this.onStop_audio}
type='audio/wav'
backgroundColor='rgb(255, 255, 255)'
foregroundColor='rgb(255,76,75)'
canvasWidth={450}
canvasHeight={100}
/>
<audio
id='audio'
controls
src={this.state.audioDataURL}
/>
</div>
</span>
)
}
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()
|