change all of the UI elements to streamlit, DO NOT ADJUST ANY OF THE PROCESSING FUNCTION, only the ui functions that DISPLAYS the app, all of the processing pipeline should stay EXACTLY the same :'import gradio as gr
import subprocess
import os
import time
import threading
import queue
import yaml
import logging

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def read_config(*config_files):
    config = {}
    for file in config_files:
        with open(file, 'r') as f:
            config.update(yaml.safe_load(f))
    return config

def upload_agent(agent, agent_file, config_file, custom_agent_name, learning_rate, batch_size, epochs, gamma,
                epsilon, epsilon_min, epsilon_decay, ngpu, thread_num, seed, debug, interface, delay_type,
                task, world, network, dataset, prefix):
    workspace_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
    agent_dir = os.path.join(workspace_dir, 'agent')
    config_dir = os.path.join(workspace_dir, 'configs', 'tsc')

    logging.info(f"Workspace directory: {workspace_dir}")
    logging.info(f"Agent directory: {agent_dir}")
    logging.info(f"Config directory: {config_dir}")

    # Ensure directories exist
    os.makedirs(agent_dir, exist_ok=True)
    os.makedirs(config_dir, exist_ok=True)

    if agent == "custom":
        logging.info("Handling custom agent upload")
        if not agent_file or not config_file or not custom_agent_name:
            error_msg = "Error: Custom agent requires agent file, config file, and custom agent name."
            logging.error(error_msg)
            return error_msg

        agent_filename = os.path.basename(agent_file.name)
        config_filename = os.path.basename(config_file.name)
        env_agent = custom_agent_name
    else:
        logging.info(f"Handling predefined agent: {agent}")
        agent_filename = f"{agent}.py"
        config_filename = f"{agent}.yml"
        env_agent = agent

    agent_rel_path = os.path.join('agent', agent_filename)
    config_rel_path = os.path.join('configs', 'tsc', config_filename)

    logging.info("Environment variables set for deployment.")

    output_queue = queue.Queue()

    def run_subprocess():
        try:
            command = [
                'python', 'SimTrafficOpt/core/drl_deployment.py',
                '--agent', agent_filename[:-3],
                '--agent_file', agent_rel_path,
                '--config_file', config_rel_path,
                '--ngpu', ngpu,
                '--thread_num', str(thread_num),
                '--prefix', prefix,
                '--seed', str(seed) if seed is not None else '',
                '--debug', str(debug).lower(),
                '--interface', interface,
                '--delay_type', delay_type,
                '-t', task,
                '-w', world,
                '-n', network,
                '-d', dataset
            ]

            drl_process = subprocess.Popen(
                command,
                cwd=workspace_dir,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                env=os.environ,
                bufsize=1,
                universal_newlines=True
            )

            for line in drl_process.stdout:
                output_queue.put(line)
            for line in drl_process.stderr:
                output_queue.put(f"ERROR: {line}")

            drl_process.wait()
            output_queue.put(f"Subprocess exited with error code {drl_process.returncode}")
        except Exception as e:
            output_queue.put(f"Error running subprocess: {str(e)}")

    subprocess_thread = threading.Thread(target=run_subprocess)
    subprocess_thread.start()

    output = ""
    start_time = time.time()
    while subprocess_thread.is_alive() or not output_queue.empty():
        try:
            line = output_queue.get_nowait()
            output += line
            yield output
        except queue.Empty:
            time.sleep(0.1)
        if time.time() - start_time > 300:  # 5 minutes timeout
            yield "Deployment timed out after 5 minutes."
            break

    subprocess_thread.join()
    yield output

def load_config_file(config_file):
    if config_file is None:
        return [gr.update()] * 7  # Return updates for 7 fields

    try:
        new_config = yaml.safe_load(config_file.read())
        return (
            gr.update(value=new_config.get('model', {}).get('learning_rate', 0.001)),
            gr.update(value=new_config.get('model', {}).get('batch_size', 64)),
            gr.update(value=new_config.get('trainer', {}).get('episodes', 200)),
            gr.update(value=new_config.get('model', {}).get('gamma', 0.95)),
            gr.update(value=new_config.get('model', {}).get('epsilon', 0.5)),
            gr.update(value=new_config.get('model', {}).get('epsilon_min', 0.05)),
            gr.update(value=new_config.get('model', {}).get('epsilon_decay', 0.99))
        )
    except Exception as e:
        logging.error(f"Error loading config file: {str(e)}")
        return [gr.update()] * 7  # Return updates for 7 fields

def create_dynamic_agent_customization_ui():
    with gr.Blocks() as dynamic_agent_customization:
        gr.Markdown("## Dynamic Agent Customization")

        agent = gr.Dropdown(
            choices=["colight", "dqn", "presslight", "frap", "maxpressure", "mplight", "sotl", "custom"],
            value="dqn",
            label="Agent type"
        )

        with gr.Column(visible=False) as custom_agent_inputs:
            with gr.Row():
                agent_file = gr.File(label="Agent File (.py)", scale=2)
                config_file = gr.File(label="Config File (.yml)", scale=2)
            custom_agent_name = gr.Textbox(label="Custom Agent Name (e.g., TestLightAgent, CoLightAgent)", scale=1)
            load_config_button = gr.Button("Load Config")

        with gr.Accordion("Agent Settings", open=True):
            with gr.Row():
                learning_rate = gr.Slider(minimum=0.0001, maximum=0.1, label="Learning Rate", value=0.001, step=0.0001)
                batch_size = gr.Slider(minimum=8, maximum=256, step=8, label="Batch Size", value=64)
                epochs = gr.Slider(minimum=1, maximum=1000, step=1, label="Epochs", value=200)
            with gr.Row():
                gamma = gr.Slider(minimum=0.1, maximum=1.0, label="Gamma", value=0.95, step=0.01)
                epsilon = gr.Slider(minimum=0.0, maximum=1.0, label="Epsilon", value=0.5, step=0.01)
                epsilon_min = gr.Slider(minimum=0.0, maximum=1.0, label="Epsilon Min", value=0.05, step=0.01)
                epsilon_decay = gr.Slider(minimum=0.9, maximum=1.0, label="Epsilon Decay", value=0.99, step=0.01)

        with gr.Accordion("Simulation Settings"):
            with gr.Row():
                world = gr.Dropdown(choices=["cityflow", "sumo"], label="Simulator type", value="sumo")
                network = gr.Textbox(label="Network name", value="sumo1x1")
                dataset = gr.Textbox(label="Type of dataset in training process", value="onfly")
            with gr.Row():
                task = gr.Dropdown(choices=["tsc", "inference"], label="Task type to run", value="tsc")
                delay_type = gr.Dropdown(choices=["apx", "real"], label="Method of calculating delay", value="apx")
                interface = gr.Dropdown(choices=["libsumo", "traci"], label="Interface type", value="libsumo")

        with gr.Accordion("Advanced Settings"):
            with gr.Row():
                ngpu = gr.Textbox(label="GPU to be used", value="-1")
                thread_num = gr.Slider(minimum=1, maximum=16, step=1, label="Number of threads", value=4)
            with gr.Row():
                prefix = gr.Textbox(label="Prefix for this running process", value="test")
                seed = gr.Number(label="Seed for pytorch backend")
                debug = gr.Checkbox(label="Debug mode", value=True)

        with gr.Row():
            upload_button = gr.Button("Upload and Deploy Agent")
            reset_button = gr.Button("Reset")

        output = gr.Textbox(label="Output", lines=20, interactive=False)

        def toggle_custom_agent(choice):
            return gr.update(visible=(choice == "custom"))

        agent.change(fn=toggle_custom_agent, inputs=[agent], outputs=[custom_agent_inputs])

        upload_button.click(
            fn=upload_agent,
            inputs=[
                agent, agent_file, config_file, custom_agent_name, learning_rate, batch_size, epochs,
                gamma, epsilon, epsilon_min, epsilon_decay, ngpu, thread_num, seed, debug,
                interface, delay_type, task, world, network, dataset, prefix
            ],
            outputs=output,
            show_progress=True
        )

        load_config_button.click(
            fn=load_config_file,
            inputs=[config_file],
            outputs=[learning_rate, batch_size, epochs, gamma, epsilon, epsilon_min, epsilon_decay]
        )

        reset_button.click(fn=lambda: "", inputs=None, outputs=output)

    return dynamic_agent_customization"