Spaces:
Running
A newer version of the Streamlit SDK is available:
1.41.1
title: RealTimeAsyncASR
emoji: π
colorFrom: red
colorTo: red
sdk: streamlit
sdk_version: 1.40.2
app_file: app.py
pinned: true
license: mit
import streamlit as st import datetime import os import base64
Initialize session state variables
if 'transcript_history' not in st.session_state: st.session_state.transcript_history = []
Function to create a download link for a string
def get_download_link(text, filename): b64 = base64.b64encode(text.encode()).decode() return f'Download Transcript'
Create the main layout
st.title("Speech Recognition with Transcript History")
col1, col2 = st.columns([2, 1])
with col1: html = """
<script>
if (!('webkitSpeechRecognition' in window)) {
alert('Speech recognition not supported');
} else {
const recognition = new webkitSpeechRecognition();
const startButton = document.getElementById('start');
const stopButton = document.getElementById('stop');
const clearButton = document.getElementById('clear');
const status = document.getElementById('status');
const output = document.getElementById('output');
let fullTranscript = '';
let lastUpdateTime = Date.now();
// Configure recognition
recognition.continuous = true;
recognition.interimResults = true;
// Function to start recognition
const startRecognition = () => {
try {
recognition.start();
status.textContent = 'Listening...';
startButton.disabled = true;
stopButton.disabled = false;
} catch (e) {
console.error(e);
status.textContent = 'Error: ' + e.message;
}
};
// Auto-start on load
window.addEventListener('load', () => {
setTimeout(startRecognition, 1000); // Delay start by 1 second to ensure everything is loaded
});
startButton.onclick = startRecognition;
stopButton.onclick = () => {
recognition.stop();
status.textContent = 'Stopped';
startButton.disabled = false;
stopButton.disabled = true;
};
clearButton.onclick = () => {
fullTranscript = '';
output.textContent = '';
// Send clear signal to Streamlit
window.parent.postMessage({type: 'clear'}, '*');
};
recognition.onresult = (event) => {
let interimTranscript = '';
let finalTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
const transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) {
finalTranscript += transcript + '\\n';
} else {
interimTranscript += transcript;
}
}
if (finalTranscript || (Date.now() - lastUpdateTime > 5000)) {
if (finalTranscript) {
fullTranscript += finalTranscript;
// Send to Streamlit
window.parent.postMessage({
type: 'transcript',
text: finalTranscript
}, '*');
}
lastUpdateTime = Date.now();
}
output.textContent = fullTranscript + (interimTranscript ? '... ' + interimTranscript : '');
output.scrollTop = output.scrollHeight;
};
recognition.onend = () => {
if (!stopButton.disabled) {
try {
recognition.start();
console.log('Restarted recognition');
} catch (e) {
console.error('Failed to restart recognition:', e);
status.textContent = 'Error restarting: ' + e.message;
startButton.disabled = false;
stopButton.disabled = true;
}
}
};
recognition.onerror = (event) => {
console.error('Recognition error:', event.error);
status.textContent = 'Error: ' + event.error;
if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {
startButton.disabled = false;
stopButton.disabled = true;
}
};
// Listen for messages from Streamlit
window.addEventListener('message', (event) => {
if (event.data.type === 'clear') {
fullTranscript = '';
output.textContent = '';
}
});
}
</script>
</body>
</html>
"""
# Display the HTML component
component = st.components.v1.html(html, height=400)
with col2: # Display transcript history st.subheader("Transcript History")
# Function to save transcript
def save_transcript(text):
if not os.path.exists('transcripts'):
os.makedirs('transcripts')
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f"transcripts/transcript_{timestamp}.md"
with open(filename, 'w', encoding='utf-8') as f:
f.write(text)
return filename
# Display transcript
if st.session_state.transcript_history:
full_transcript = "\n".join(st.session_state.transcript_history)
st.text_area("Full Transcript", value=full_transcript, height=300)
# Save transcript to file
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f"transcript_{timestamp}.md"
# Create download link
st.markdown(get_download_link(full_transcript, filename), unsafe_allow_html=True)
# Save to file system
if st.button("Save to File"):
saved_file = save_transcript(full_transcript)
st.success(f"Saved to {saved_file}")
Handle transcript updates from JavaScript
if component: try: data = component if isinstance(data, dict) and data.get('type') == 'transcript': st.session_state.transcript_history.append(data['text']) st.experimental_rerun() elif isinstance(data, dict) and data.get('type') == 'clear': st.session_state.transcript_history = [] st.experimental_rerun() except Exception as e: st.error(f"Error processing transcript: {e}")