CoolFace
Apppublic

merterm/Learning-Games-Experiment-2

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
app.py774 linesDownload Raw Back to root
1from pathlib import Path2import zipfile3from typing import List, Tuple, Optional, Set4import json5import dataclasses6import gradio as gr7import asyncio8from openai import AsyncOpenAI9import tempfile10import os11import argparse12import gradio as gr13import random14import os15from pathlib import Path16import time17import matplotlib.pyplot as plt18import io19 20# BASE_URL = os.getenv("BASE_URL")21API_KEY = os.getenv("API_KEY")22 23BASE_URL = "https://api.openai.com"24print(f"BASE_URL: {BASE_URL}")25print(f"API_KEY: {API_KEY}")26if not BASE_URL or not API_KEY:27    raise ValueError("BASE_URL or API_KEY environment variables are not set")28 29client = AsyncOpenAI(api_key=API_KEY)30 31 32##########################################################################################################33#                                        HELPER FUNCTIONS                                                #34##########################################################################################################35async def run_command(cmd, timeout=5):36    process = await asyncio.create_subprocess_exec(37        *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE38    )39    try:40        stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=timeout)41        return (42            stdout.decode("utf-8", errors="ignore"),43            stderr.decode("utf-8", errors="ignore"),44            process.returncode,45        )46    except asyncio.TimeoutError:47        process.kill()48        return None, None, None49 50# def echo(message, history):51#     return random.choice(["Yes", "No"])52 53# Prompt chatgpt with a message54async def chatgpt(prompt, history):55    messages = [56            {"role": "system", "content": ""}57        ]58    print(history)59    if history:60        messages += history61    messages += [{"role": "user", "content": prompt}]62    try:63        response = await client.chat.completions.create(64            model="gpt-4o",65            messages=messages66        )67    except Exception as e:68        print(e)69        return "I'm sorry, I'm having trouble. Could you please try again?"70    return response.choices[0].message.content71 72async def process_submission(finished_code, user_state):73    # Compile and execute user code, generate plot74    print("Compiling and plotting code")75    print(f"Code: {finished_code}")76    with tempfile.NamedTemporaryFile(delete=True, suffix=".py") as f:77        f.write(finished_code.encode("utf-8"))78        f.flush()79        stdout, stderr, exit_code = await run_command(["python", f.name], timeout=5)80 81    # result = await run_python_code(finished_code)82    print(f"Result: {stdout}")83 84    # Check if plot was created85    if f"temp_plot_{user_state}.png" in os.listdir():86        return f"temp_plot_{user_state}.png", stdout, stderr87    else:88        return "No plot generated", stdout, stderr89        # return gr.update(value="No plot generated", visible=True), None90 91# Function to create a zip file92def create_zip_file(jsonl_path, image_path, zip_path):93    with zipfile.ZipFile(zip_path, 'w') as zipf:94        zipf.write(jsonl_path, arcname=Path(jsonl_path).name)95        zipf.write(image_path, arcname=Path(image_path).name)96 97# Function to assign plots to users randomly98def pick_random_image_for_user(users, images):99    assigned_images = {}100    for user in users:101        assigned_images[user] = random.sample(images, 5)102    # print(assigned_images)103    return assigned_images104 105##########################################################################################################106#                                        GRADIO INTERFACE SETUP                                          #107##########################################################################################################108# Define each page as a separate function109def create_interface(users):110    max_num_submissions = 5111    plot_time_limit = 130112    # plot_time_limit = 10113    dialogue_time_limit = 600114    # dialogue_time_limit = 10115    116    with gr.Blocks() as demo:117        user_state = gr.State()118        notes_state = gr.State([])119        dialogue_state = gr.State([])  # Store the conversation with the LLM120        submission_count = gr.State(0)  # Track number of code submissions121        produced_codes = gr.State([])122        previous_text = gr.State("")  # Track previous text in notepad123        random.seed(time.time())124 125        folder_path = "ChartMimic/dataset/ori_500"126        images = [f for f in os.listdir(folder_path) if f.endswith(('png', 'jpg', 'jpeg'))]127        chosen_image = os.path.join(folder_path, random.choice(images))128        assigned_images = pick_random_image_for_user(users, images)129 130        reference_code = chosen_image.replace(".png", ".py")131        chosen_image_state = gr.State(chosen_image)132        reference_code_state = gr.State(reference_code)133 134        expertise_survey_responses = gr.State({})135        uncertainty_survey_part_1_responses = gr.State({})  # Store responses to the uncertainty survey136        uncertainty_survey_part_2_responses = gr.State({})  # Store responses to the uncertainty survey137        uncertainty_survey_part_3_responses = gr.State({})  # Store responses to the uncertainty survey138        demographic_survey_responses = gr.State({})  # Store responses to the demographic survey139 140        ##########################################################################################################141        #                                        UI SETUP FOR EACH PAGE                                          #142        ##########################################################################################################143        # Page 1: Login, Add login components144        with gr.Column(visible=True) as login_row:145            instructions_text = gr.Markdown(f"## Instructions\n\nWelcome to Learning Games! PLEASE READ THE FOLLOWING INSTRUCTIONS CAREFULLY. \146                                             \n\nThis game consists of three parts:\n\n**Part 1: Inspection of the Chart**\n\nYou will be given \147                                            an image of a scientific chart. Please inspect it carefully and think about ways to reproduce it in \148                                            Python. You will have access to this plot throughout the experiment. You can take notes while \149                                            inspecting, a notepad will be given to you. At the end of the game, you will be asked to write \150                                            the code to recreate this chart. \n\n**Part 2: Chatting with a Teacher**\n\nIn this part, \151                                            you will have access to a teacher LLM! This interaction will be limited to only {int(dialogue_time_limit/60)}\152                                            minutes. You can use it to help you learn how to code this chart. Please be wise of your time \153                                            with the teacher LLM; by the end of this part, you will not be able to interact with the \154                                            LLM again. \n\n**Part 3: Writing the Code for the Chart**\n\nThis is the final crucial step. You will \155                                            have {max_num_submissions} attempts to reproduce the plot by writing, compiling, and running Python \156                                            code. You will be given a code skeleton to help you out, where you will fill in some required coding \157                                            components. You will be given only {max_num_submissions} attempts to compile your plot. \n\n Throughout \158                                            your interactions, you will be asked three times to rank your uncertainty: once during the inspection \159                                            of the chart, once after interacting with the LLM, and once after you submit your code. \160                                            \n\nAt the end of the game, you will be asked to fill out a short demographic survey. \161                                            Then you will be able to download your session data. Please download and send the zip file to <inan.m@northeastern.edu>. \162                                            \n\n**WARNING: You will not be able to go back to previous parts once you proceed, or reload the page.** \163                                            \n\n**Reminder: this is just a game; your performance will not affect your grade in the class in \164                                            any form.** \n\n \n\n ### Please login to start the game. We will first ask some questions about your \165                                            expertise, and part 1 will start immediately afterwards.")166            username_input = gr.Textbox(label="Username")167            login_button = gr.Button("Login")168            login_error_message = gr.Markdown(visible=False)169 170        # User Expertise Survey171        with gr.Column(visible=False) as expertise_survey:172            gr.Markdown("### Student Expertise Survey")173            gr.Markdown("Here is a short questionnaire before you get started. Please answer the following questions as accurately as possible.")174            expertise_survey_question1 = gr.CheckboxGroup(175                ["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"],176                label="Question 1: On a scale of 1-5, what is your experience level of coding in Python? "177            )178            expertise_survey_question2 = gr.CheckboxGroup(179                ["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"],180                label="Question 2: On a scale of 1-5, what is your experience level of using the Matplotlib library? "181            )182            expertise_survey_submit_button = gr.Button("Submit")183 184 185        # Instructions Page186        with gr.Column(visible=False) as instructions_page:187            instructions_text = gr.Markdown(f"## Part 1: Inspection of the Chart \n\nBelow, you are given a scientific chart. \188                                            Please inspect it carefully and think about ways to reproduce it in Python. You will \189                                            have access to this plot throughout the experiment. At the end of the game, you will \190                                            be asked to write the code to recreate this chart. You will be given a code skeleton \191                                            and the necessary data at the end. You can take notes below. You will have \192                                            {int(plot_time_limit/60)} minutes to take a look at this plot, starting now…")193            instruction_image_1 = gr.Image(show_label=False, height=500)194            plot_time_remaining = gr.Textbox(value=f"{(int(plot_time_limit/60)):02}:{(plot_time_limit%60):02}", label="Time Remaining", interactive=False)195            # questionnaire = gr.Form(["Question 1", "Question 2"], visible=False)196 197        # Uncertainty Survey Page198        with gr.Column(visible=False) as uncertainty_survey_part_1:199            instruction_image_2 = gr.Image(show_label=False, height=300)200            gr.Markdown("### Uncertainty Survey")201            gr.Markdown("Here is a short questionnaire before you get started. Please answer the following questions as accurately as possible.")202            uncertainty_survey_part_1_question1 = gr.CheckboxGroup(203                ["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"],204                label="Question 1: On a scale of 1-5, how certain are you that you can code this plot? "205            )206            207            uncertainty_survey_part_1_submit_button = gr.Button("Submit")208 209        # Dialogue Page with 5-minute timer210        with gr.Column(visible=False) as dialogue_page:211            instruction_text = gr.Markdown(f"## Part 2: Chatting with a Teacher \n\nNow, you will have access to a teacher LLM. This interaction will be limited to only {int(dialogue_time_limit/60)} minutes. \212                                           The countdown starts when you send your first message. You can use it to help you learn \213                                           how to code this chart. But be wise of your time; by the end of this part, \214                                           you will not be able to interact with the LLM again. Please use your time with \215                                           the LLM wisely, and think through your code solution before committing.\216                                           \n\n **You may want to prompt the LLM to teach you how to produce code for this chart** \217                                           **rather than having it output code directly. Please think about how to prompt the LLM to do this.**")218            with gr.Row():219                instruction_image_3 = gr.Image(show_label=False, height=400)220                with gr.Column():221                    # chatbot = gr.ChatInterface(echo, type="messages")222                    chatbot = gr.ChatInterface(chatgpt, type="messages", examples=["Teach me how to ...", "I want to learn step-by-step ...", "Explain to me slowly ..."])223                    chatbot.chatbot.height = 400224                    chatbot.chatbot.label = "Teacher LLM"225            # start_dialogue_button = gr.Button("Start Dialogue")226            part_2_time_remaining = gr.Textbox(value=f"{(int(dialogue_time_limit/60)):02}:{(dialogue_time_limit%60):02}", label="Time Remaining", interactive=False)227 228        # Uncertainty Survey Part 2229        with gr.Column(visible=False) as uncertainty_survey_part_2:230            instruction_image_4 = gr.Image(show_label=False, height=500)231            gr.Markdown("### Uncertainty Survey")232            gr.Markdown("Here is a short questionnaire after you have interacted with the teacher LLM. \233                        Please answer the following questions as accurately as possible.")234            uncertainty_survey_part_2_question1 = gr.CheckboxGroup(235                ["1 - Not at all", "2 - Slightly", "3 - Moderately", "4 - Very", "5 - Extremely"],236                label="Question 1: On a scale of 1-5, how much did the teacher LLM help you in learning how to code this plot? "237            )238            uncertainty_survey_part_2_question2 = gr.CheckboxGroup(239                ["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"],240                label="Question 2: On a scale of 1-5, how certain are you that you can code this plot now? "241            )242            uncertainty_survey_part_2_question3 = gr.CheckboxGroup(243                ["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"],244                label="Question 3: On a scale of 1-5, how certain are you that you can code this plot even without the teacher LLM? "245            )246            uncertainty_survey_part_2_question4 = gr.CheckboxGroup(247                ["1 - Not on topic at all", "2 - Somewhat not on topic", "3 - Moderately on topic", "4 - Somewhat on topic", "5 - Mostly on topic"],248                label="Question 4: On a scale of 1-5, how much did the LLM stay on topic (i.e. did it answer your questions specifically)?"249            )250            uncertainty_survey_part_2_submit_button = gr.Button("Submit")251 252        # Final Code Editor Page253        with gr.Column(visible=False) as final_page:254            instruction_text = gr.Markdown(f"## Part 3: Writing the Code for the Chart \n\nThis is the final crucial step. \255                                           You need to reproduce the original plot by writing, compiling, and running Python code. \256                                           You are given a code skeleton below to help you, where you will fill in the \257                                           required coding components. When you compile, you will be able to see the output of \258                                           your code, in addition to the plot. You will be given only {max_num_submissions} attempts to compile your plot.")259            instruction_image_5 = gr.Image(show_label=False, height=400)260            code_editor = gr.Code(language="python", label="Code Editor")261            run_code_button = gr.Button("Compile & Run Code")262            processing_message = gr.Textbox(value="Processing...", visible=False)263            with gr.Row():264                retry_button = gr.Button("Retry", visible=False)265                finished_button = gr.Button("Finished", visible=False)266            with gr.Row():267                stdout_message = gr.Textbox(visible=True, label="Code Output", value="")268                submission_counter = gr.Number(visible=True, label="Number of Remaining Submissions", value=max_num_submissions)269            plot_output = gr.Image(visible=False, height=400)270 271        # Uncertainty Survey Part 3272        with gr.Column(visible=False) as uncertainty_survey_part_3:273            with gr.Row():274                instruction_image_6 = gr.Image(label="Original Chart", height=300)275                generated_image = gr.Image(label="Your Generated Chart", height=300)276            gr.Markdown("### Uncertainty Survey")277            gr.Markdown("Here is a short questionnaire after you have finalized your code. Please answer the following questions as accurately as possible.")278            uncertainty_survey_part_3_question1 = gr.CheckboxGroup(279                ["1 - Not at all", "2 - Slightly", "3 - Moderately", "4 - Very", "5 - Extremely"],280                label="Question 1: On a scale of 1-5, how much did you rely on the teacher LLM and your notes to code this chart? "281            )282            uncertainty_survey_part_3_question2 = gr.CheckboxGroup(283                ["1 - Much harder", "2 - Harder", "3 - As expected", "4 - Easier", "5 - Much easier"],284                label="Question 2: On a scale of 1-5, was the task easier or harder than you expected? "285            )286            uncertainty_survey_part_3_question3 = gr.CheckboxGroup(287                ["1 - Could not produce", "2 - Very inaccurate", "3 - Moderately inaccurate", "4 - Somewhat accurate", "5 - Very accurate"],288                label="Question 3: On a scale of 1-5, how accurate is your chart compared to the original? "289            )290            uncertainty_survey_part_3_question4 = gr.CheckboxGroup(291                ["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"],292                label="Question 4: On a scale of 1-5, how would you rate your experience in Python now? "293            )294            uncertainty_survey_part_3_question5 = gr.CheckboxGroup(295                ["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"],296                label="Question 5: On a scale of 1-5, how would you rate your experience in using the Matplotlib library now? "297            )298            uncertainty_survey_part_3_question6 = gr.CheckboxGroup(299                ["1 - Very ambiguous", "2 - Somewhat ambiguous", "3 - Neither ambiguous nor clear", "4 - Somewhat clear", "5 - Very clear"],300                label="Question 5: On a scale of 1-5, throughout this experiment how ambigous were the instructions?"301            )302            uncertainty_survey_part_3_question7 = gr.CheckboxGroup(303                ["1 - Very ambiguous", "2 - Somewhat ambiguous", "3 - Neither ambiguous nor clear", "4 - Somewhat clear", "5 - Very clear"],304                label="Question 5: On a scale of 1-5, throughout this experiment how ambigous was the given plot?"305            )306            uncertainty_survey_part_3_submit_button = gr.Button("Submit")307 308        # Demographic Survey Page309        with gr.Column(visible=False) as demographic_survey:310            gr.Markdown("### Demographic Survey")311            gr.Markdown("Please answer the following questions to help us understand your background.")312            demographic_survey_question1 = gr.CheckboxGroup(313                ["Undergraduate", "Graduate", "PhD", "Postdoc", "Faculty", "Industry Professional", "Other"],314                label="What is your current academic status?"315            )316            demographic_survey_question2 = gr.CheckboxGroup(317                ["Bouvé College of Health Sciences", "College of Arts, Media and Design", "College of Engineering", "College of Professional Studies", "College of Science", "D'Amore-McKim School of Business", "Khoury College of Computer Sciences", "School of Law", "Mills College at Northeastern", "Other"],318                label="What is your college?"319            )320            demographic_survey_question3 = gr.CheckboxGroup(321                ["18-23", "23-27", "27-31", "31-35", "35-43", "43+"],322                label="What is your age group?"323            )324            demographic_survey_question4 = gr.CheckboxGroup(325                ["Woman", "Man", "Transgender", "Non-binary", "Prefer not to say"],326                label="What is your gender identity?"327            )328            demographic_survey_question5 = gr.CheckboxGroup(329                ["American Indian or Alaska Native", "Asian or Asian American", "Black or African American", "Hispanic or Latino/a/x", "Native Hawaiian or Other Pacific Islander", "Middle Eastern or North African", "White or European", "Other"],330                label="What is your ethnicity? (Select all that apply)"331            )332            demographic_survey_submit_button = gr.Button("Submit")333 334        # Exit Page335        with gr.Column(visible=False) as exit_page:336            gr.Markdown("## Thank you for participating in the Learning Games! \n\nYour responses have been recorded. Please download your session data below, and send the zip file to <inan.m@northeastern.edu>.")337            download_button = gr.Button("Download Session Data")338            file_to_download = gr.File(label="Download Results")339 340 341        # Adding the notepad available on all pages342        with gr.Column(visible=False) as notepad_column:343            notepad = gr.Textbox(lines=10, placeholder="Take notes here", value="", label="Notepad", elem_id="notepad")344            345        346        ##########################################################################################################347        #                           FUNCTION DEFINITIONS FOR EACH PAGE                                           #348        ##########################################################################################################349        def on_login(users: Set[str], folder_path, assigned_images):350            def callback(username):351                if username not in users:352                    return (353                        gr.update(visible=True),  # login still visible354                        gr.update(visible=False),  # main interface still not visible355                        gr.update(visible=True, value="Username not found"),356                        "",357                        gr.update(),                # for image state to change with the user358                        gr.update(),                # for ref code359                    )360                chosen_image = os.path.join(folder_path, random.choice(assigned_images[username]))361                return (362                    gr.update(visible=False),  # login hidden363                    gr.update(visible=True),  # main interface visible364                    gr.update(visible=False),  # login error message hidden365                    username,366                    chosen_image, # for image state367                    chosen_image.replace(".png", ".py")368                )369 370            return callback371        372        def update_all_instruction_images(chosen_image):373            return (374                gr.update(value=chosen_image),375                gr.update(value=chosen_image),376                gr.update(value=chosen_image),377                gr.update(value=chosen_image),378                gr.update(value=chosen_image),379                gr.update(value=chosen_image)380            )381        382        def extract_code_context(reference_code, user_state):383            with open(reference_code, "r") as f:384                code_context = f.read()385            print(code_context)386            # Remove everything between Part 3: Plot Configuration and Rendering and Part 4: Saving Output387            start_index = code_context.find("# ===================\n# Part 3: Plot Configuration and Rendering\n# ===================")388            end_index = code_context.find("# ===================\n# Part 4: Saving Output\n# ===================")389            code_context = code_context[:start_index] + "# ===================\n# Part 3: Plot Configuration and Rendering\n# ===================\n\n # TODO: YOUR CODE GOES HERE #\n\n\n" + code_context[end_index:]390            # plt.savefig is the last line of the code, remove it391            end_index = code_context.find("plt.savefig")392            code_context = code_context[:end_index]393            # and replace with plt.show()394            code_context += f"plt.savefig('temp_plot_{user_state}.png')\n"395            # code_context += "plt.show()\n"396            return code_context397        398        def handle_expertise_survey_response(q1, q2):399            # Example: Store responses in a dictionary or process as needed400            response = {401                "Question 1": q1,402                "Question 2": q2403            }404            return response405 406        # Function to handle form submission407        def handle_part1_survey_response(q1):408            # Example: Store responses in a dictionary or process as needed409            response = {410                "Question 1": q1411            }412            return response413        414        def handle_part2_survey_response(q1, q2, q3, q4):415            # Example: Store responses in a dictionary or process as needed416            response = {417                "Question 1": q1,418                "Question 2": q2,419                "Question 3": q3,420                "Question 4": q4421            }422            return response423        424        def handle_final_survey_response(q1, q2, q3, q4, q5, q6, q7):425            # Example: Store responses in a dictionary or process as needed426            response = {427                "Question 1": q1,428                "Question 2": q2,429                "Question 3": q3,430                "Question 4": q4,431                "Question 5": q5,432                "Question 6": q6,433                "Question 7": q7434            }435            return response436        437        def handle_demographic_survey_response(q1, q2, q3, q4, q5):438            # Example: Store responses in a dictionary or process as needed439            response = {440                "Question 1": q1,441                "Question 2": q2,442                "Question 3": q3,443                "Question 4": q4,444                "Question 5": q5445            }446            return response447        448        # Timer logic for instructions page449        def plot_countdown_timer():450            time_limit = plot_time_limit451            start_time = time.time()452            while time.time() - start_time < time_limit:453                mins, secs = divmod(time_limit - int(time.time() - start_time), 60)454                yield f"{mins:02}:{secs:02}", gr.update(), gr.update(visible=False)455            yield "00:00", gr.update(visible=False), gr.update(visible=True)456 457        # Timer logic for dialogue page458        def dialogue_countdown_timer():459            time_limit = dialogue_time_limit460            start_time = time.time()461            while time.time() - start_time < time_limit:462                mins, secs = divmod(time_limit - int(time.time() - start_time), 60)463                yield f"{mins:02}:{secs:02}", gr.update(visible=True), gr.update(visible=False)464            yield "00:00", gr.update(visible=False), gr.update(visible=True)465 466        # New function to save dialogue state467        def save_dialogue_state(dialogue, dialogue_state):468            timestamp = time.strftime("%Y-%m-%d %H:%M:%S")469            print(dialogue)470            print(dialogue_state)471            return dialogue_state + [timestamp, dialogue]472        473        # # Save notes, dialogue, and answers into a file for download474        # def prepare_download(notes, dialogue, answers):475        #     results = {476        #         "notes": notes,477        #         "dialogue": dialogue,478        #         "answers": answers479        #     }480        #     with open("session_data.json", "w") as f:481        #         json.dump(results, f)482        #     return "session_data.json"483 484        # Add download functionality485        def get_download_link(user_state, chosen_image, notes_state, dialogue_state, 486                            produced_codes, reference_code, survey1, survey2, survey3, survey4, survey5):487            jsonl_path = Path(f"session_data_{user_state}.jsonl")488            with open(jsonl_path, "w") as f:489                f.write(490                    json.dumps(491                        {492                            "username": user_state,493                            "chosen_image": chosen_image,494                            "notes": notes_state,495                            "dialogue_state": dialogue_state,496                            "produced_codes": produced_codes,497                            "reference_code": reference_code,498                            "expertise_survey": survey1,499                            "uncertainty_survey_part1": survey2,500                            "uncertainty_survey_part2": survey3,501                            "uncertainty_survey_part3": survey4,502                            "demographics_survey": survey5503                        }504                    )505                    + "\n"506                )507            508            image_path = Path(f"temp_plot_{user_state}.png")509            zip_path = Path(f"session_data_{user_state}.zip")510            create_zip_file(jsonl_path, image_path, zip_path)511            512            if not zip_path.exists():513                return None514            return gr.File(value=str(zip_path), visible=True)515            516        async def on_submit(finished_code, submission_count, produced_codes, user_state):517            if (max_num_submissions-(submission_count+1)) == 0:518                # raise gr.Error("Max submissions reached")519                yield (520                    gr.update(visible=False),521                    gr.update(visible=False),  # Hide run code button522                    gr.update(visible=False),  # Hide retry button523                    gr.update(visible=True),  # Show finished button524                    gr.update(visible=False),  # Hide plot output525                    submission_count,526                    produced_codes,527                    gr.update(visible=False),    # stdout528                    gr.update(visible=False) #submission counter529                )530                raise gr.Error("Max submissions reached")531            else:532                submission_count += 1533                # Show processing message and hide other elements534                yield (535                    gr.update(visible=True),  # Show processing message536                    gr.update(visible=False),  # Hide run code button537                    gr.update(visible=False),  # Hide retry button538                    gr.update(visible=False),  # Hide finished button539                    gr.update(visible=False),  # Hide plot output540                    submission_count,541                    produced_codes,542                    gr.update(visible=False),   # stdout543                    gr.update(value=max_num_submissions-submission_count) #submission counter544                )545 546                # Process the submission547                plot_output, stdout, stderr = await process_submission(finished_code, user_state)548 549                # Hide processing message and show result550                yield (551                    gr.update(visible=False),  # Hide processing message552                    gr.update(visible=False),  # Hide submit button553                    gr.update(visible=True),  # Show retry button554                    gr.update(visible=True),  # Show finished button555                    gr.update(visible=True, value=plot_output),  # Show plot output556                    submission_count,557                    produced_codes + [finished_code],558                    gr.update(visible=True, value=stdout+stderr),    # stdout559                    gr.update() #submission counter560                )561 562        def on_retry(finished_code, produced_codes):563            # Hide processing message and show result564            yield (565                gr.update(visible=False),  # Hide processing message566                gr.update(visible=True),  # Show submit button567                gr.update(visible=False),  # Hide retry button568                gr.update(visible=False),  # Hide finished button569                gr.update(visible=False),  # Hide plot output570                produced_codes + [finished_code]571            )572            573        def filter_paste(previous_text, new_text):574            # Check if the new input is a result of pasting (by comparing lengths or content)575            print(f"New text: {new_text}")576            changed_text = new_text.replace(previous_text, "")577            if len(changed_text) > 10:  # Paste generally increases length significantly578                return previous_text, previous_text  # Revert to previous text if paste is detected579            previous_text = new_text580            print(f"Previous text: {previous_text}")581            return previous_text, new_text582 583        def save_notes_with_timestamp(notes, notes_state):584            timestamp = time.strftime("%Y-%m-%d %H:%M:%S")585            notes_state.append(f"{timestamp}: {notes}")586            return notes_state587 588        ##########################################################################################################589        #                                      EVENT HANDLERS FOR EACH PAGE                                      #590        ##########################################################################################################591        # Page navigation592        login_button.click(593            on_login(users, folder_path, assigned_images),594            inputs=[username_input],595            outputs=[login_row, expertise_survey, login_error_message, user_state, chosen_image_state, reference_code_state],596        )597 598        # login_button.click(lambda: os.path.join(folder_path, random.choice(images)), outputs=[chosen_image_state])599 600        # login_button.click(lambda: chosen_image_state.replace(".png", ".py"), inputs=[chosen_image_state], outputs=[reference_code_state])601 602        expertise_survey_submit_button.click(603            handle_expertise_survey_response,604            inputs=[expertise_survey_question1, expertise_survey_question2],605            outputs=[expertise_survey_responses]606        )607 608        expertise_survey_submit_button.click(609            lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=True)), # Hide survey, show dialogue610            inputs=[], outputs=[expertise_survey, instructions_page, notepad_column]611        )612 613        expertise_survey_submit_button.click(614            update_all_instruction_images,615            inputs=[chosen_image_state], outputs=[instruction_image_1, instruction_image_2,616                                                  instruction_image_3, instruction_image_4,617                                                  instruction_image_5, instruction_image_6]618        )619 620        expertise_survey_submit_button.click(plot_countdown_timer, outputs=[plot_time_remaining, instructions_page, uncertainty_survey_part_1])621 622        uncertainty_survey_part_1_submit_button.click(623            handle_part1_survey_response,624            inputs=[uncertainty_survey_part_1_question1],625            outputs=[uncertainty_survey_part_1_responses]626        )627 628        uncertainty_survey_part_1_submit_button.click(629            lambda: (gr.update(visible=False), gr.update(visible=True)), # Hide survey, show dialogue630            inputs=[], outputs=[uncertainty_survey_part_1, dialogue_page]631        )632 633        chatbot.chatbot.change(634            dialogue_countdown_timer,635            outputs=[part_2_time_remaining, dialogue_page, uncertainty_survey_part_2],636            trigger_mode = "once"637        )638 639        # Update to save dialogue state on change640        chatbot.chatbot.change(641            save_dialogue_state,642            inputs=[chatbot.chatbot, dialogue_state],643            outputs=[dialogue_state]644        )645 646        uncertainty_survey_part_2_submit_button.click(647            handle_part2_survey_response,648            inputs=[uncertainty_survey_part_2_question1, uncertainty_survey_part_2_question2, 649                    uncertainty_survey_part_2_question3, uncertainty_survey_part_2_question4],650            outputs=[uncertainty_survey_part_2_responses]651        )652 653        uncertainty_survey_part_2_submit_button.click(654            lambda: (gr.update(visible=False), gr.update(visible=True)), # Hide survey, show final page655            inputs=[], outputs=[uncertainty_survey_part_2, final_page]656        )657 658        uncertainty_survey_part_2_submit_button.click(659            extract_code_context,660            inputs=[reference_code_state, user_state], outputs=[code_editor]661        )662 663        run_code_button.click(664            on_submit,665            inputs=[code_editor, submission_count, produced_codes, user_state],666            outputs=[667                processing_message,668                run_code_button,669                retry_button,670                finished_button,671                plot_output,672                submission_count,673                produced_codes,674                stdout_message,675                submission_counter676            ],677        )678 679        retry_button.click(680            on_retry,681            inputs=[code_editor, produced_codes],682            outputs=[683                processing_message,684                run_code_button,685                retry_button,686                finished_button,687                plot_output,688                produced_codes,689            ],690        )691 692        finished_button.click(693            lambda user_state: (gr.update(visible=False), gr.update(visible=True), f"temp_plot_{user_state}.png"), # Hide final page, show survey694            inputs=[user_state], outputs=[final_page, uncertainty_survey_part_3, generated_image]695        )696 697        uncertainty_survey_part_3_submit_button.click(698            handle_final_survey_response,699            inputs=[uncertainty_survey_part_3_question1, uncertainty_survey_part_3_question2, 700                    uncertainty_survey_part_3_question3, uncertainty_survey_part_3_question4, 701                    uncertainty_survey_part_3_question5, uncertainty_survey_part_3_question6,702                    uncertainty_survey_part_3_question7],703            outputs=[uncertainty_survey_part_3_responses]704        )705 706        uncertainty_survey_part_3_submit_button.click(707            lambda: (gr.update(visible=False), gr.update(visible=True)), # Hide survey, show demographic survey708            inputs=[], outputs=[uncertainty_survey_part_3, demographic_survey]709        )710 711        demographic_survey_submit_button.click(712            handle_demographic_survey_response,713            inputs=[demographic_survey_question1, demographic_survey_question2, demographic_survey_question3, demographic_survey_question4, demographic_survey_question5],714            outputs=[demographic_survey_responses]715        )716 717        demographic_survey_submit_button.click(718            lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)), # Hide survey, show exit page719            inputs=[], outputs=[demographic_survey, exit_page, download_button, notepad]720        )721 722        # notepad.change(filter_paste, 723        #                inputs=[previous_text, notepad], 724        #                outputs=[previous_text, notepad], trigger_mode="always_last")725 726        demographic_survey_submit_button.click(save_notes_with_timestamp, 727                       inputs=[notepad, notes_state],728                       outputs=[notes_state])729 730        download_button.click(731            get_download_link, 732            inputs=[user_state, chosen_image_state, notes_state, 733                    dialogue_state, produced_codes, reference_code_state,734                    expertise_survey_responses,735                    uncertainty_survey_part_1_responses, 736                    uncertainty_survey_part_2_responses, 737                    uncertainty_survey_part_3_responses, 738                    demographic_survey_responses],739            outputs=[file_to_download]740        )741 742        demo.load(743            lambda: gr.update(visible=True),  # Show login page744            outputs=login_row,745        )746 747    return demo748 749 750# if __name__ == "__main__":751#     users = Path("users.txt").read_text().splitlines()752#     users = set(user.strip() for user in users if user.strip())753#     chosen_image = pick_random_image()754#     reference_code = chosen_image.replace(".png", ".py")755#     # code_context = extract_code_context(reference_code)756#     demo = create_interface(users, chosen_image, reference_code)757 758#     # demo.launch(759#     #     server_name=args.server_name,760#     #     server_port=args.server_port,761#     #     share=args.share,762#     # )763 764#     demo.launch()765 766users = Path("users.txt").read_text().splitlines()767users = set(user.strip() for user in users if user.strip())768# chosen_image = pick_random_image()769# reference_code = chosen_image.replace(".png", ".py")770# code_context = extract_code_context(reference_code)771demo = create_interface(users)772 773demo.launch()774