I am considering refactoring this python Code to use SOLID Principles. How would you approach this?

```
import os
import webbrowser
from pathlib import Path

import streamlit as st
from st_ant_tree import st_ant_tree
import streamlit_antd_components as sac

import streamlit_components as stc
from data_handler import AppManager
from utils.utils import clone_repository
from utils.custom_logger import CustomLogger
from pycode_processor.data_processing import find_selected_method
from pycode_processor.data_processing import make_repo_tree_structure
from pycode_processor.data_processing import transform_module_to_tree

logger = CustomLogger.get_logger(__name__)


def handle_repo_url(repo_url: str, data: AppManager) -> AppManager:
    if not repo_url:
        return data

    if repo_url != data.repo_url:
        repo_path = f"cloned_repos/{repo_url.split('/')[-1]}"
        data.update_and_reset(repo_url=repo_url)
        data.update(repo_path=repo_path)
        st.session_state.file_path = None
        st.session_state.method_name = None
    else:
        repo_path = data.repo_path

    if os.path.isdir(repo_path):
        data.repo_cloned = True
        return data

    if "username" not in st.session_state and "password" not in st.session_state:
        stc.get_username_password()
    else:
        clone_output = clone_repository(
            repo_url,
            repo_path,
            st.session_state.username,
            st.session_state.password,
        )
        if clone_output:
            data.repo_cloned = True
            logger.info("Repository Cloning : Success !")
        else:
            logger.error("Repository Cloning : Error !")
            stc.toast("Repository Cloning : Error !", type="error")

    return data


def handle_language(language: str, data: AppManager) -> AppManager:
    if language != data.language:
        repo_states = {
            'repo_url': data.repo_url,
            'repo_path': data.repo_path,
            'repo_cloned': data.repo_cloned
        }
        prev_file_path = data.file_path
        data.update_and_reset(language=language)
        
        data.update(**repo_states)
        data = handle_file_path(prev_file_path, data)

    return data


def handle_file_path(file_path: str, data: AppManager) -> AppManager:
    if file_path != data.file_path:
        st.session_state.method_name = None
        if file_path.endswith(".py") or file_path.endswith(".java"):
            file_name = os.path.basename(file_path)
            packages, complete_methods = data.process_file(file_path)
            data.update_and_reset(file_path=file_path)
            data.update(
                file_path=file_path,
                file_name=file_name,
                packages=packages,
                complete_methods=complete_methods,
            )
    else:
        file_name = data.file_name
        packages = data.packages
        complete_methods = data.complete_methods

    return data


def handle_method_name(method_name: str, data: AppManager) -> AppManager:
    if method_name != data.method_name:
        selected_method_data = find_selected_method(
            nested_dict=data.complete_methods, target_key=method_name
        )
        if selected_method_data is not None:
            method_name, method_definition = selected_method_data
            data.update_and_reset(method_name=method_name)
            data.update(method_name=method_name, method_definition=method_definition)

    else:
        method_definition = data.method_definition

    return data


def display_chat_interface(data: AppManager) -> AppManager:
    chat_placeholder = st.empty()
    animation_placeholder = st.empty()
    with chat_placeholder.container():
        chat_window = stc.chat_window()
        chat_window.display_message_history(data.messages_history)
        if user_answer := st.chat_input("Your answer?"):
            chat_window.user_input(input=user_answer)
            data.answers.append(user_answer)
            data.messages_history.append({"role": "user", "content": user_answer})
    answers_len = len(data.answers)

    if answers_len < len(data.questions):
        with chat_placeholder.container():
            chat_window.assistant_output(output=data.questions[answers_len])
            data.messages_history.append(
                {
                    "role": "assistant",
                    "content": data.questions[answers_len],
                }
            )

    elif answers_len == len(data.questions):
        chat_placeholder.empty()
        with stc.LottieAnimation(
            "assets/Animation-1724036221793.json", "Generating Scenarios"
        ):
            if "user_input" in data.components:
                data.generate_results(step="clarifiction_completed")
            elif "verify_io_user_input" in data.components:
                data.generate_results(step="verified_io_types")
        st.rerun()

    return data


def start_code_generation(data: AppManager) :
    if data.repo_url is None or data.file_path is None or data.method_name is None:
        stc.toast("Please provide all the required information.", type="error")
        logger.warning("User did not provide required repo URL or file path.")
        return data
    elif not data.file_path.endswith(".py"):
        stc.toast("Please select a .py file.", type="error")
        return data
    elif data.language == "Java":
        stc.toast("Java is not supported. Please select Python.", type="warning")
        logger.warning("User selected unsupported language: Java.")
        return data
    else:
        CustomLogger.new_session()
        logger.info(
            f"Generating code for repo = {data.repo_url}, file = {data.file_name}, method = {data.method_name}"
        )
    with stc.LottieAnimation(
        "assets/Animation-1724036221793.json", "Identifying Dependencies"
    ):
        data.generate_results(step="start")

    return data


def display_test_scenarios(data: AppManager) -> AppManager:
    stc.markdown("Test scenarios", font_size="25px", font_weight="bold")
    with st.container(height=400, border=False):
        selected_scenarios = stc.multiselect(
            title="select test cases",
            options=data.test_cases,
            default=data.selected_scenarios,
        )
    codes_button = stc.st_button("Generate test codes", "codes_button", "right")
    if codes_button:
        data.update(selected_scenarios=selected_scenarios)
        with stc.LottieAnimation(
            "assets/Animation-1724036221793.json", "Generating Code"
        ):
            data.generate_results(step="code_generation")
    return data


def display_results(data: AppManager) -> AppManager:
    sac.divider(
        label="🎯 Test Results",
        align="center",
        size="xs",
        variant="dashed",
        color="gray",
    )
    stc.markdown("Pytest Results", font_size="25px", font_weight="bold")
    st.code(data.pytest_results, language=None)
    coverage_button_col, self_correction_button_col = st.columns(2, gap="large")

    with coverage_button_col:
        coverage_report_button = stc.st_button(
            "Detailed coverage report", "coverage_report_button"
        )
    with self_correction_button_col:
        self_correction_button = stc.st_button(
            "Self correction", "self_correction_button", "right"
        )

    if self_correction_button:
        with stc.LottieAnimation(
            "assets/Animation-1724036221793.json", "Correcting code"
        ):
            data.generate_results(step="self_correction")
        st.rerun()

    if coverage_report_button:
        webbrowser.open_new_tab(
            Path.cwd().joinpath(f"{data.repo_path}/htmlcov/index.html")
        )
    return data


def display_code(data: AppManager) -> AppManager:
    sac.divider(
        label="📋 Pytest Codes",
        align="center",
        size="xs",
        variant="dashed",
        color="gray",
    )
    generated_code_col, ground_truth_col = st.columns(
        2, gap="large", vertical_alignment="top"
    )

    with generated_code_col:
        code = stc.st_code_window(title="Generated test cases", code=data.pytest_codes)
        download_button_col, results_button_col = st.columns(2, gap="large")

        with results_button_col:
            results_button = stc.st_button("Run tests", "results_button", "right")

        with download_button_col:
            st.download_button(
                label="Download test files",
                data=data.pytest_codes,
                file_name=f"test_{data.method_name}_{data.file_name}",
                mime="text/plain",
            )

    with ground_truth_col:
        stc.markdown("Original test cases", font_size="25px", font_weight="bold")
        file_name = os.path.basename(data.file_path)
        if os.path.isfile(f"test_reference/test_{data.method_name}_{file_name}"):
            with open(
                f"test_reference/test_{data.method_name}_{file_name}", encoding="utf-8"
            ) as f:
                reference = f.read()
        else:
            reference = "### No reference file found."
        st.code(reference, language="python")

    if results_button:
        data.update(pytest_codes=code)
        with stc.LottieAnimation(
            "assets/Animation-1724036221793.json", "Running Tests"
        ):
            data.generate_results(step="run_pytest_code")

    return data


def main():
    try:
        st.set_page_config(
            page_title="Test Automation Assistant",
            page_icon="assets/carelon_icon.png",
            layout="wide",
        )
        st.logo("assets/carelon_logo.jpg")
        stc.markdown(
            "Test Automation Assistant",
            font_size="45px",
            font_weight="bold",
            font_color="#4d09ad",
        )

        if "app" not in st.session_state:
            st.session_state.app = AppManager()

        inputs_col, scenarios_col = st.columns(2, gap="large", vertical_alignment="top")

        with inputs_col:
            repo_url_col, lanuage_col = st.columns([0.7, 0.3], gap="small")
            repo_url = repo_url_col.text_input(
                "Enter BitBucket repo link here:", value=st.session_state.app.repo_url
            )
            st.session_state.app = handle_repo_url(repo_url, st.session_state.app)
            language = lanuage_col.selectbox(
                "Language", options=["Python", "Java"], index=0
            )
            st.session_state.app = handle_language(language, st.session_state.app)
            file_selection_col, method_selection_col = st.columns(2, gap="small")

            if st.session_state.app.repo_cloned:
                repo_tree_data = make_repo_tree_structure(
                    st.session_state.app.repo_path
                )
                disabled_treeview = False
            else:
                repo_tree_data = []
                disabled_treeview = True

            with file_selection_col:
                stc.markdown(
                    "Select the file you want to test :",
                    font_size="14px",
                    font_color="#454545",
                )
                file_path = stc.select_from_tree(
                    data=repo_tree_data,
                    disabled=disabled_treeview,
                    key="file_path",
                    placeholder="Choose a File",
                )

            if file_path is not None:
                st.session_state.app = handle_file_path(file_path, st.session_state.app)

            if file_path and not disabled_treeview:
                function_tree_data = transform_module_to_tree(
                    st.session_state.app.complete_methods
                )
                disabled_treeview = False
            else:
                function_tree_data = []
                disabled_treeview = True

            with method_selection_col:
                stc.markdown(
                    "Select the method/function you want to test:",
                    font_size="14px",
                    font_color="#454545",
                )
                method_name = stc.select_from_tree(
                    data=function_tree_data,
                    disabled=disabled_treeview,
                    key="method_name",
                    placeholder="Choose a method/function",
                )

            st.session_state.app = handle_method_name(method_name, st.session_state.app)

            objective = st.text_area("Provide additional info of the method (optional)")
            sample_data = st.text_area("Provide sample data for the method (optional)")
            st.session_state.app.update(objective=objective, sample_data=sample_data)
            scenario_button = stc.st_button(
                "Generate Test Scenarios", "scenario_button"
            )

        if len(st.session_state.app.components) == 0 and scenario_button:
            with scenarios_col:
                st.session_state.app = start_code_generation(data=st.session_state.app)

        if "user_input" in st.session_state.app.components:
            with scenarios_col:
                st.session_state.app = display_chat_interface(data=st.session_state.app)
        elif "verify_io_user_input" in st.session_state.app.components:
            with scenarios_col:
                st.session_state.app = display_chat_interface(data=st.session_state.app)
        # else:
        #     with scenarios_col:
        #         st.json(st.session_state.app.get_state(),expanded=False)
        st.json(st.session_state.app.get_state(),expanded=False)
        if "scenarios_section" in st.session_state.app.components:
            with scenarios_col:
                st.session_state.app = display_test_scenarios(data=st.session_state.app)
        if "code_section" in st.session_state.app.components:
            st.session_state.app = display_code(data=st.session_state.app)
        if "results_section" in st.session_state.app.components:
            st.session_state.app = display_results(data=st.session_state.app)

    except Exception as e:
        stc.show_exception(e)


if __name__ == "__main__":
    main()

```