RealTimeAsyncASR / README.md
awacke1's picture
Update README.md
05a59a4 verified

A newer version of the Streamlit SDK is available: 1.41.1

Upgrade
metadata
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 = """ Continuous Speech Demo

Ready

    <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}")