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 |
+
|