How can I use user entered text as a filename in Streamlit?

Question:

I am trying to let the user enter a filename and use that text as the filename of the file that has to be uploaded to a GCS bucket.
This is what my code looks like:

user_input = str(st.text_input("Name your file: "))

sweep_string = "_exponential_sweep_.wav"
inv_filter_string = "_inverse_filter_.wav"
ir_string = "_impulse_response_.wav"

if user_input:

    wavfile.write(os.path.join(audio_files_path,
                               user_input + sweep_string), sample_rate, sweep)
    wavfile.write(os.path.join(audio_files_path,
                               user_input + inv_filter_string), sample_rate, inverse)
    wavfile.write(os.path.join(audio_files_path,
                               user_input + ir_string), sample_rate, ir)

I tried to add the two strings together in a variable before the wavfile.write but nothing changes. If I remove user_input from the wavefile.write it works, but I need the user to be able to name the files.

******* EDIT *******

Editing the question as a solution was proposed but it still does not work. Here’s a longer extract of the code I’m using:

def select_sweep_time():
    sweep_duration_option = st.selectbox('Select the duration of the sweep',
                                         ('3s', '7s', '14s'))
    max_reverb_option = st.selectbox('Select the expected maximum reverb decay time',
                                     ('1s', '2s', '3s', '5s', '10s'))
    st.caption('''
        Note that longer sweeps provide more accuacy,
        but even short sweeps can be used to measure long decays
        ''')

    if sweep_duration_option == '3s':
        sweep_duration = 3
    elif sweep_duration_option == '7s':
        sweep_duration = 7
    elif sweep_duration_option == '14s':
        sweep_duration = 14

    if max_reverb_option == '1s':
        max_reverb_option = 1
    elif max_reverb_option == '2s':
        max_reverb_option = 2
    elif max_reverb_option == '3s':
        max_reverb_option = 3
    elif max_reverb_option == '5s':
        max_reverb_option = 5
    elif max_reverb_option == '10s':
        max_reverb_option = 10

    return sweep_duration_option, max_reverb_option

def write_wav_file(file_name, rate, data):
    audio_files_path = r'data/audio_files'
    """Write wav file base on input"""
    save_file_path = os.path.join(audio_files_path, file_name)

    wavfile.write(save_file_path, rate, data)
    st.success(
        f"File successfully written to audio_files_path as:>> {file_name}")

def sweep_save():
    if st.button("Play"):
        sweep = generate_exponential_sweep(sweep_duration, sample_rate)
        inverse = generate_inverse_filter(
            sweep_duration, sample_rate, sweep)
        ir = deconvolve(sweep, inverse)

        user_input = str(st.text_input("Name your file: "))

        if user_input:
            sweep_string = user_input + "_exponential_sweep_.wav"
            inv_filter_string = user_input + "_inverse_filter_.wav"
            ir_string = user_input + "_impulse_response_.wav"

            write_wav_file(file_name=sweep_string,
                           rate=sample_rate, data=sweep)

            write_wav_file(file_name=inv_filter_string,
                           rate=sample_rate, data=inverse)

            write_wav_file(file_name=ir_string, rate=sample_rate, data=ir)

def irm_tab():
    tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8, tab9 = st.tabs(
        ["Impulse",
         "ETC",
         "Schroeder Integral",
         "EDT",
         "T20",
         "T30",
         "Clarity C50",
         "Clarity C80",
         "FFT"]
    )

    with tab1:
        st.header("Impulse")
        st.markdown(
            """
            The impulse plot shows the decay of the IR visually.
            """
        )

        select_sweep_time()
        sweep_save()

The irm_tab() function is then called in a page file as per the multi-page setup displayed on the streamlit docs:

import streamlit as st
from utils import head_impulse_response, irm_tab


head_impulse_response()
irm_tab()

I don’t know why but this method, even if correct in theory, does not work. If I remove if user_input: then it does work, but obviously it only saves the files with the default name, which is not what I want.

Asked By: Ettore Carlessi

||

Answers:

Assign a file name to the path before you write, I will recommend a function to take care of this task. Also you can just st.text_input() instead of str(st.text_input()) because text_input returns a string.

import streamlit as st
import os


def write_wav_file(file_name, rate, data):
    """Write wav file base on input"""
    audio_files_path = "/audio_files_path/here"
    save_file_path = os.path.join(audio_files_path, file_name)
    
    wavfile.write(save_file_path, rate, data)
    st.success(f"File successfully written to audio_files_path as:>> {file_name}")
    

user_input = st.text_input("Name your file: ")

if user_input:
    sweep_string = user_input + "_exponential_sweep_.wav"
    inv_filter_string = user_input + "_inverse_filter_.wav"
    ir_string = user_input + "_impulse_response_.wav"
    
    write_wav_file(file_name=sweep_string, rate=sample_rate, data=sweep)
    
    write_wav_file(file_name=inv_filter_string, rate=sample_rate, data=inverse)
    
    write_wav_file(file_name=ir_string, rate=sample_rate, data=ir)

Edition:
Now we can see that the problem is caused by if st.button("Play"): in your sweep_save():. Streamlit button has no callback, that means whenever a user makes any entry under a button, the page will reload and the data will be lost. In order to handle such problem, you will have to initialize a session state for the button.

I add few lines of code to your sweep_save(): to initialize the button

def sweep_save():
    playbtn = st.button("Play")
    if "playbtn_state" not in st.session_state:
        st.session_state.playbtn_state = False

    if playbtn or st.session_state.playbtn_state:
        st.session_state.playbtn_state = True
    
        sweep = generate_exponential_sweep(sweep_duration, sample_rate)
        ...

I think this should resolve the problem now.

Answered By: Jamiu Shaibu
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.