How to capture console stream and display in Streamlit

I’ve been working on a program that involves Whisper AI.
Whisper will show progress information to the console\terminal and I have no control over what is presented. I need to capture this information and progress to the user. There are no hook\callbacks from Whisper for the progress, It is simply presented to the console.

Console output
100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 370639/370639 [03:47<00:00, 1625.89frames/s]

.
The above progress is going to the console but my program is GUI and does not directly have access to the console information. I did however redirect the console output.
.

Redirected console output
…
98%|#########7| 362652/370639 [03:36<00:04, 1636.68frames/s]
99%|#########8]| 365340/370639 [03:38<00:03, 1635.98frames/s]
99%|#########9| 368164/370639 [03:40<00:01, 1601.73frames/s]
100%|##########| 370639/370639 [03:42<00:00, 1570.82frames/s]
100%|##########| 370639/370639 [03:42<00:00, 1668.54frames/s]

# Create a custom Streamlit component to capture stdout and stderr
class StreamlitOutputRedirector:
    def __init__(self, placeholder):
        self.buffer = ""
        self.placeholder = placeholder

    def write(self, text):
        # Define a keyword to selectively redirect
        keyword_to_redirect = "frames/s]"

        # Check if the keyword is present in the text
        if keyword_to_redirect in text:
            # Redirect text containing the keyword to Streamlit
            # sys.__stdout__.write(text) # Testing

            # Split the input string at each "|"
            split_elements = text.split("|")
            left  = split_elements[0].strip() # contains percentage complete
            right = split_elements[2].strip() # contains "frames/s" information
            newText = left + " | " + right
            # self.setText(newText)
            self.buffer += newText
        else:
            # Print text without the keyword to the console
            sys.__stdout__.write(text)

    def flush(self):
        # Display the captured output
        self.placeholder.write(f"###### {self.buffer}") # markdown, write very small
        self.buffer = ""  

    def clear(self):
        # Clear the Streamlit screen by emptying the placeholder
        self.placeholder.empty()

    def setText(self, newText):
        # Write content into placeholder
        # self.placeholder.write(newText) # normal writing
        self.placeholder.write(f"###### {newText}") # markdown, write very small

    def replacePlaceholder(self, newPlaceholder):
         # Replace with the desired placeholder, which may not be initially known
         self.placeholder = newPlaceholder

# Create an empty placeholder for dynamic content
output_placeholder = st.empty()

# Create an instance of the custom StreamlitOutputRedirector
output_redirector = StreamlitOutputRedirector(output_placeholder)

# Redirect stdout and stderr to the custom redirector
sys.stdout = output_redirector
sys.stderr = output_redirector

def transcribeAudio():
    progress = st.sidebar.empty()                   # Create the desired placeholder for progress information
    output_redirector.replacePlaceholder(progress)  # Replace the existing placeholder
    output_redirector.setText("0% complete")        # Set the initial text
    results = model.transcribe(tempTargetPath, fp16=False, word_timestamps = True, verbose=False) 
   
   # ***The progress bar will now automatically capture and update the "progress" place holder***

This doesn’t work perfectly.

The updates to the console are not capture perfectly and I don’t understand why.
It should capture every update from 0…100 but the output will skip numbers and sometimes may not capture when it arrives at 100%.

100% | 27262/27262 [00:22<00:00, 1194.91frames/s]

The output automatically updates from the redirected text to look like the above.
I have checked to see if possibly, the process is too fast but that doesnt appear to be the case.

Any ideas on why I am not getting every update that is written to the console?

Hi @MrEdwards007

It seems that to be able to display the progress information in real-time, you’ll need access to Whisper AI’s progress hook as what you’ll seeing in the console/terminal is the standard output.

However, what you might be able to do is write your own progress information explicitly and use these messages within progress bar widgets that Streamlit provides.

Additionally, you can parse information or values from the standard output and relay that information back to the progress bar or status message. However, if the progress is happening fast then the act of reporting the progress information may only hinder or slow down the app processing of the calculation.

Some progress bars and status widgets that you can use in Streamlit is shown here: Display progress and status - Streamlit Docs

You can always fall back to resorting to using the progress bar to print out β€œProcessing …” if the procedure take a few seconds. If it takes significantly longer then parsing information and relaying that back to the app may also be the way to go. Unless Whisper AI provides a progress hook that can be accessed then this may require some heavy customization.

Hope this helps!

Yes, this helps.

This process could take from 30 seconds to 30 or more minutes depending on input factors, so I want the user to see the progress, to have a sense of how long the process may take.

I have parsed the data and used the output. Based that, I could take the information from and recreate or update an actual progress bar versus progress status or I could do both.

left  = split_elements[0].strip() # contains percentage complete

Thank you.