Update src/streamlit_app.py
Browse files- src/streamlit_app.py +73 -21
src/streamlit_app.py
CHANGED
|
@@ -41,26 +41,6 @@ def load_context():
|
|
| 41 |
st.error("Context file not found!")
|
| 42 |
return ""
|
| 43 |
|
| 44 |
-
def record_audio():
|
| 45 |
-
"""Record audio and return the buffer."""
|
| 46 |
-
progress_bar = st.progress(0)
|
| 47 |
-
recording = sd.rec(int(RECORD_DURATION * SAMPLE_RATE),
|
| 48 |
-
samplerate=SAMPLE_RATE,
|
| 49 |
-
channels=1)
|
| 50 |
-
|
| 51 |
-
# Update progress bar while recording
|
| 52 |
-
for i in range(RECORD_DURATION * 10):
|
| 53 |
-
progress_bar.progress((i + 1) / (RECORD_DURATION * 10))
|
| 54 |
-
time.sleep(0.1)
|
| 55 |
-
|
| 56 |
-
sd.wait()
|
| 57 |
-
progress_bar.empty() # Remove progress bar after recording
|
| 58 |
-
|
| 59 |
-
buf = io.BytesIO()
|
| 60 |
-
scipy.io.wavfile.write(buf, SAMPLE_RATE, recording)
|
| 61 |
-
buf.seek(0)
|
| 62 |
-
return buf
|
| 63 |
-
|
| 64 |
def transcribe_audio(audio_buffer):
|
| 65 |
"""Transcribe audio using Whisper API."""
|
| 66 |
with open(TEMP_AUDIO_FILE, "wb") as f:
|
|
@@ -112,6 +92,12 @@ def handle_record_button():
|
|
| 112 |
info_placeholder.empty()
|
| 113 |
st.session_state.recorded_audio = audio_buffer
|
| 114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
def main():
|
| 116 |
st.title("Voice Bot")
|
| 117 |
|
|
@@ -126,7 +112,13 @@ def main():
|
|
| 126 |
|
| 127 |
with audio:
|
| 128 |
st.subheader("Audio Input")
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
# Create placeholder for processing status
|
| 132 |
process_placeholder = st.empty()
|
|
@@ -161,5 +153,65 @@ def main():
|
|
| 161 |
st.text_area("Context", value=st.session_state.context, height=270, disabled=False)
|
| 162 |
st.markdown("You can update the context in the `context.txt` file.")
|
| 163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
if __name__ == "__main__":
|
| 165 |
main()
|
|
|
|
|
|
| 41 |
st.error("Context file not found!")
|
| 42 |
return ""
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
def transcribe_audio(audio_buffer):
|
| 45 |
"""Transcribe audio using Whisper API."""
|
| 46 |
with open(TEMP_AUDIO_FILE, "wb") as f:
|
|
|
|
| 92 |
info_placeholder.empty()
|
| 93 |
st.session_state.recorded_audio = audio_buffer
|
| 94 |
|
| 95 |
+
def handle_recorded_audio(audio_bytes):
|
| 96 |
+
"""Handle the recorded audio data from browser"""
|
| 97 |
+
audio_buffer = io.BytesIO(base64.b64decode(audio_bytes))
|
| 98 |
+
st.session_state.recorded_audio = audio_buffer
|
| 99 |
+
st.session_state.processing = True
|
| 100 |
+
|
| 101 |
def main():
|
| 102 |
st.title("Voice Bot")
|
| 103 |
|
|
|
|
| 112 |
|
| 113 |
with audio:
|
| 114 |
st.subheader("Audio Input")
|
| 115 |
+
# Replace button with HTML/JS audio recorder
|
| 116 |
+
st.components.v1.html(get_audio_recorder_html(), height=100)
|
| 117 |
+
|
| 118 |
+
# Handle audio data from JavaScript
|
| 119 |
+
if st.session_state.get('browser_audio'):
|
| 120 |
+
handle_recorded_audio(st.session_state.browser_audio)
|
| 121 |
+
st.session_state.browser_audio = None
|
| 122 |
|
| 123 |
# Create placeholder for processing status
|
| 124 |
process_placeholder = st.empty()
|
|
|
|
| 153 |
st.text_area("Context", value=st.session_state.context, height=270, disabled=False)
|
| 154 |
st.markdown("You can update the context in the `context.txt` file.")
|
| 155 |
|
| 156 |
+
# Add JavaScript for audio recording
|
| 157 |
+
def get_audio_recorder_html():
|
| 158 |
+
return """
|
| 159 |
+
<script>
|
| 160 |
+
const audioRecorder = {
|
| 161 |
+
start: async function() {
|
| 162 |
+
this.mediaRecorder = null;
|
| 163 |
+
this.audioChunks = [];
|
| 164 |
+
|
| 165 |
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
| 166 |
+
this.mediaRecorder = new MediaRecorder(stream);
|
| 167 |
+
|
| 168 |
+
this.mediaRecorder.ondataavailable = (e) => {
|
| 169 |
+
if (e.data.size > 0) this.audioChunks.push(e.data);
|
| 170 |
+
};
|
| 171 |
+
|
| 172 |
+
this.mediaRecorder.onstop = () => {
|
| 173 |
+
const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
|
| 174 |
+
const reader = new FileReader();
|
| 175 |
+
reader.readAsDataURL(audioBlob);
|
| 176 |
+
reader.onloadend = () => {
|
| 177 |
+
const base64Audio = reader.result.split(',')[1];
|
| 178 |
+
window.parent.postMessage({type: 'AUDIO_DATA', data: base64Audio}, '*');
|
| 179 |
+
};
|
| 180 |
+
};
|
| 181 |
+
|
| 182 |
+
this.mediaRecorder.start();
|
| 183 |
+
},
|
| 184 |
+
|
| 185 |
+
stop: function() {
|
| 186 |
+
if (this.mediaRecorder) {
|
| 187 |
+
this.mediaRecorder.stop();
|
| 188 |
+
this.mediaRecorder.stream.getTracks().forEach(track => track.stop());
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
};
|
| 192 |
+
|
| 193 |
+
const startButton = document.getElementById('recordButton');
|
| 194 |
+
startButton.addEventListener('mousedown', () => audioRecorder.start());
|
| 195 |
+
startButton.addEventListener('mouseup', () => audioRecorder.stop());
|
| 196 |
+
</script>
|
| 197 |
+
<button id="recordButton" style="padding: 20px 40px; font-size: 16px;">🎙️ Hold to Record</button>
|
| 198 |
+
"""
|
| 199 |
+
|
| 200 |
+
# Add JavaScript message handler
|
| 201 |
+
js = """
|
| 202 |
+
<script>
|
| 203 |
+
window.addEventListener('message', function(e) {
|
| 204 |
+
if (e.data.type === 'AUDIO_DATA') {
|
| 205 |
+
window.parent.streamlit.setComponentValue({
|
| 206 |
+
'browser_audio': e.data.data
|
| 207 |
+
});
|
| 208 |
+
}
|
| 209 |
+
}, false);
|
| 210 |
+
</script>
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
st.components.v1.html(js, height=0)
|
| 214 |
+
|
| 215 |
if __name__ == "__main__":
|
| 216 |
main()
|
| 217 |
+
|