awacke1's picture
Create app.py
f43e9df verified
raw
history blame
7.82 kB
import streamlit as st
import datetime
import os
# Initialize session state for transcript history if not exists
if 'transcript_history' not in st.session_state:
st.session_state.transcript_history = ""
# Create a container for the transcript history
history_container = st.empty()
text_area = st.empty()
html = """
<!DOCTYPE html>
<html>
<head>
<title>Continuous Speech Demo</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
button {
padding: 10px 20px;
margin: 10px 5px;
font-size: 16px;
}
#status {
margin: 10px 0;
padding: 10px;
background: #e8f5e9;
border-radius: 4px;
}
#output {
white-space: pre-wrap;
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
margin: 10px 0;
min-height: 100px;
max-height: 400px;
overflow-y: auto;
}
.controls {
margin: 10px 0;
}
</style>
</head>
<body>
<h1>Continuous Speech Recognition</h1>
<div class="controls">
<button id="start">Start Listening</button>
<button id="stop" disabled>Stop Listening</button>
<button id="clear">Clear Text</button>
</div>
<div id="status">Ready</div>
<div id="output"></div>
<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();
// Function to update Streamlit
function updateStreamlit(text, isFinal) {
// Create data object
const data = {
text: text,
isFinal: isFinal,
timestamp: new Date().toISOString()
};
// Send to Streamlit using the Streamlit component API
window.parent.postMessage({
type: 'streamlit:setComponentValue',
value: data
}, '*');
}
// Configure recognition
recognition.continuous = true;
recognition.interimResults = true;
startButton.onclick = () => {
try {
recognition.start();
status.textContent = 'Listening...';
startButton.disabled = true;
stopButton.disabled = false;
} catch (e) {
console.error(e);
status.textContent = 'Error: ' + e.message;
}
};
stopButton.onclick = () => {
recognition.stop();
status.textContent = 'Stopped';
startButton.disabled = false;
stopButton.disabled = true;
};
clearButton.onclick = () => {
fullTranscript = '';
output.textContent = '';
updateStreamlit('', true); // Clear Streamlit display
};
recognition.onresult = (event) => {
let interimTranscript = '';
let finalTranscript = '';
// Process results
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;
}
}
// Update if we have final results or it's been 5 seconds
if (finalTranscript || (Date.now() - lastUpdateTime > 5000)) {
if (finalTranscript) {
fullTranscript += finalTranscript;
updateStreamlit(finalTranscript, true); // Send final transcript to Streamlit
} else if (interimTranscript) {
fullTranscript += interimTranscript + '\\n';
updateStreamlit(interimTranscript, false); // Send interim transcript to Streamlit
}
lastUpdateTime = Date.now();
}
// Display results
output.textContent = fullTranscript + (interimTranscript ? '... ' + interimTranscript : '');
// Auto-scroll to bottom
output.scrollTop = output.scrollHeight;
};
recognition.onend = () => {
// Automatically restart if not manually stopped
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;
// Only reset buttons if it's a fatal error
if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {
startButton.disabled = false;
stopButton.disabled = true;
}
};
}
</script>
</body>
</html>
"""
# Create custom component
def speech_recognition():
component_value = st.components.v1.html(html, height=600)
return component_value
# Function to save transcript to file
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, 'a', encoding='utf-8') as f:
f.write(text + '\n')
# Main app
st.title("Speech Recognition with Transcript History")
# Get the speech recognition component value
result = speech_recognition()
# If we receive a new transcript
if result:
transcript_data = result
# Update the transcript history
if transcript_data.get('isFinal', False):
new_text = transcript_data.get('text', '')
st.session_state.transcript_history += new_text
# Save to file
save_transcript(new_text)
# Update the display
history_container.markdown(st.session_state.transcript_history)
text_area.text_area("Full Transcript", st.session_state.transcript_history, height=200)
# Add a download button for the full transcript
if st.session_state.transcript_history:
st.download_button(
label="Download Full Transcript",
data=st.session_state.transcript_history,
file_name=f"transcript_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
mime="text/markdown"
)