<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> <!-- Set up your HTML here --> <input id="myinput" value="" /> <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> <!-- Add the hidden input here --> <input type="hidden" id="streamlit-data" value=""> <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); }); startButton.onclick = startRecognition; stopButton.onclick = () => { recognition.stop(); status.textContent = 'Stopped'; startButton.disabled = false; stopButton.disabled = true; }; clearButton.onclick = () => { fullTranscript = ''; output.textContent = ''; window.parent.postMessage({ type: 'clear_transcript', }, '*'); }; 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; // Update the hidden input value document.getElementById('streamlit-data').value = fullTranscript; } lastUpdateTime = Date.now(); } output.textContent = fullTranscript + (interimTranscript ? '... ' + interimTranscript : ''); output.scrollTop = output.scrollHeight; document.getElementById('streamlit-data').value = fullTranscript; sendDataToPython({value: fullTranscript,dataType: "json",}); }; 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; } }; } // ---------------------------------------------------- // Just copy/paste these functions as-is: function sendMessageToStreamlitClient(type, data) { var outData = Object.assign({ isStreamlitMessage: true, type: type, }, data); window.parent.postMessage(outData, "*"); } function init() { sendMessageToStreamlitClient("streamlit:componentReady", {apiVersion: 1}); } function setFrameHeight(height) { sendMessageToStreamlitClient("streamlit:setFrameHeight", {height: height}); } // The `data` argument can be any JSON-serializable value. function sendDataToPython(data) { sendMessageToStreamlitClient("streamlit:setComponentValue", data); } // ---------------------------------------------------- // Now modify this part of the code to fit your needs: var myInput = document.getElementById("myinput"); var myOutput = document.getElementById("output"); // data is any JSON-serializable value you sent from Python, // and it's already deserialized for you. function onDataFromPython(event) { if (event.data.type !== "streamlit:render") return; myInput.value = event.data.args.my_input_value; // Access values sent from Python here! } myInput.addEventListener("change", function() { sendDataToPython({ value: myInput.value, dataType: "json", }); }) myOutput.addEventListener("change", function() { sendDataToPython({ value: myOutput.value, dataType: "json", }); }) // Hook things up! window.addEventListener("message", onDataFromPython); init(); // Hack to autoset the iframe height. window.addEventListener("load", function() { window.setTimeout(function() { setFrameHeight(document.documentElement.clientHeight) }, 0); }); // Optionally, if the automatic height computation fails you, give this component a height manually // by commenting out below: //setFrameHeight(200); </script> </body> </html>