|
from pathlib import Path |
|
import zipfile |
|
from typing import List, Tuple, Optional, Set |
|
import json |
|
import dataclasses |
|
import gradio as gr |
|
import asyncio |
|
from openai import AsyncOpenAI |
|
import tempfile |
|
import os |
|
import argparse |
|
import gradio as gr |
|
import random |
|
import os |
|
from pathlib import Path |
|
import time |
|
import matplotlib.pyplot as plt |
|
import io |
|
|
|
|
|
API_KEY = os.getenv("API_KEY") |
|
|
|
BASE_URL = "https://api.openai.com" |
|
print(f"BASE_URL: {BASE_URL}") |
|
print(f"API_KEY: {API_KEY}") |
|
if not BASE_URL or not API_KEY: |
|
raise ValueError("BASE_URL or API_KEY environment variables are not set") |
|
|
|
client = AsyncOpenAI(api_key=API_KEY) |
|
|
|
|
|
|
|
|
|
|
|
async def run_command(cmd, timeout=5): |
|
process = await asyncio.create_subprocess_exec( |
|
*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE |
|
) |
|
try: |
|
stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=timeout) |
|
return ( |
|
stdout.decode("utf-8", errors="ignore"), |
|
stderr.decode("utf-8", errors="ignore"), |
|
process.returncode, |
|
) |
|
except asyncio.TimeoutError: |
|
process.kill() |
|
return None, None, None |
|
|
|
|
|
|
|
|
|
|
|
async def chatgpt(prompt, history): |
|
messages = [ |
|
{"role": "system", "content": ""} |
|
] |
|
print(history) |
|
if history: |
|
messages += history |
|
messages += [{"role": "user", "content": prompt}] |
|
try: |
|
response = await client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=messages |
|
) |
|
except Exception as e: |
|
print(e) |
|
return "I'm sorry, I'm having trouble. Could you please try again?" |
|
return response.choices[0].message.content |
|
|
|
async def process_submission(finished_code, user_state): |
|
|
|
print("Compiling and plotting code") |
|
print(f"Code: {finished_code}") |
|
with tempfile.NamedTemporaryFile(delete=True, suffix=".py") as f: |
|
f.write(finished_code.encode("utf-8")) |
|
f.flush() |
|
stdout, stderr, exit_code = await run_command(["python", f.name], timeout=5) |
|
|
|
|
|
print(f"Result: {stdout}") |
|
|
|
|
|
if f"temp_plot_{user_state}.png" in os.listdir(): |
|
return f"temp_plot_{user_state}.png", stdout, stderr |
|
else: |
|
return "No plot generated", stdout, stderr |
|
|
|
|
|
|
|
def create_zip_file(jsonl_path, image_path, zip_path): |
|
with zipfile.ZipFile(zip_path, 'w') as zipf: |
|
zipf.write(jsonl_path, arcname=Path(jsonl_path).name) |
|
zipf.write(image_path, arcname=Path(image_path).name) |
|
|
|
|
|
def pick_random_image_for_user(users, images): |
|
assigned_images = {} |
|
for user in users: |
|
assigned_images[user] = random.sample(images, 5) |
|
|
|
return assigned_images |
|
|
|
|
|
|
|
|
|
|
|
def create_interface(users): |
|
max_num_submissions = 5 |
|
plot_time_limit = 130 |
|
|
|
dialogue_time_limit = 600 |
|
|
|
|
|
with gr.Blocks() as demo: |
|
user_state = gr.State() |
|
notes_state = gr.State([]) |
|
dialogue_state = gr.State([]) |
|
submission_count = gr.State(0) |
|
produced_codes = gr.State([]) |
|
previous_text = gr.State("") |
|
random.seed(time.time()) |
|
|
|
folder_path = "ChartMimic/dataset/ori_500" |
|
images = [f for f in os.listdir(folder_path) if f.endswith(('png', 'jpg', 'jpeg'))] |
|
chosen_image = os.path.join(folder_path, random.choice(images)) |
|
assigned_images = pick_random_image_for_user(users, images) |
|
|
|
reference_code = chosen_image.replace(".png", ".py") |
|
chosen_image_state = gr.State(chosen_image) |
|
reference_code_state = gr.State(reference_code) |
|
|
|
expertise_survey_responses = gr.State({}) |
|
uncertainty_survey_part_1_responses = gr.State({}) |
|
uncertainty_survey_part_2_responses = gr.State({}) |
|
uncertainty_survey_part_3_responses = gr.State({}) |
|
demographic_survey_responses = gr.State({}) |
|
|
|
|
|
|
|
|
|
|
|
with gr.Column(visible=True) as login_row: |
|
instructions_text = gr.Markdown(f"## Instructions\n\nWelcome to Learning Games! PLEASE READ THE FOLLOWING INSTRUCTIONS CAREFULLY. \ |
|
\n\nThis game consists of three parts:\n\n**Part 1: Inspection of the Chart**\n\nYou will be given \ |
|
an image of a scientific chart. Please inspect it carefully and think about ways to reproduce it in \ |
|
Python. You will have access to this plot throughout the experiment. You can take notes while \ |
|
inspecting, a notepad will be given to you. At the end of the game, you will be asked to write \ |
|
the code to recreate this chart. \n\n**Part 2: Chatting with a Teacher**\n\nIn this part, \ |
|
you will have access to a teacher LLM! This interaction will be limited to only {int(dialogue_time_limit/60)}\ |
|
minutes. You can use it to help you learn how to code this chart. Please be wise of your time \ |
|
with the teacher LLM; by the end of this part, you will not be able to interact with the \ |
|
LLM again. \n\n**Part 3: Writing the Code for the Chart**\n\nThis is the final crucial step. You will \ |
|
have {max_num_submissions} attempts to reproduce the plot by writing, compiling, and running Python \ |
|
code. You will be given a code skeleton to help you out, where you will fill in some required coding \ |
|
components. You will be given only {max_num_submissions} attempts to compile your plot. \n\n Throughout \ |
|
your interactions, you will be asked three times to rank your uncertainty: once during the inspection \ |
|
of the chart, once after interacting with the LLM, and once after you submit your code. \ |
|
\n\nAt the end of the game, you will be asked to fill out a short demographic survey. \ |
|
Then you will be able to download your session data. Please download and send the zip file to <inan.m@northeastern.edu>. \ |
|
\n\n**WARNING: You will not be able to go back to previous parts once you proceed, or reload the page.** \ |
|
\n\n**Reminder: this is just a game; your performance will not affect your grade in the class in \ |
|
any form.** \n\n \n\n ### Please login to start the game. We will first ask some questions about your \ |
|
expertise, and part 1 will start immediately afterwards.") |
|
username_input = gr.Textbox(label="Username") |
|
login_button = gr.Button("Login") |
|
login_error_message = gr.Markdown(visible=False) |
|
|
|
|
|
with gr.Column(visible=False) as expertise_survey: |
|
gr.Markdown("### Student Expertise Survey") |
|
gr.Markdown("Here is a short questionnaire before you get started. Please answer the following questions as accurately as possible.") |
|
expertise_survey_question1 = gr.CheckboxGroup( |
|
["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"], |
|
label="Question 1: On a scale of 1-5, what is your experience level of coding in Python? " |
|
) |
|
expertise_survey_question2 = gr.CheckboxGroup( |
|
["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"], |
|
label="Question 2: On a scale of 1-5, what is your experience level of using the Matplotlib library? " |
|
) |
|
expertise_survey_submit_button = gr.Button("Submit") |
|
|
|
|
|
|
|
with gr.Column(visible=False) as instructions_page: |
|
instructions_text = gr.Markdown(f"## Part 1: Inspection of the Chart \n\nBelow, you are given a scientific chart. \ |
|
Please inspect it carefully and think about ways to reproduce it in Python. You will \ |
|
have access to this plot throughout the experiment. At the end of the game, you will \ |
|
be asked to write the code to recreate this chart. You will be given a code skeleton \ |
|
and the necessary data at the end. You can take notes below. You will have \ |
|
{int(plot_time_limit/60)} minutes to take a look at this plot, starting now…") |
|
instruction_image_1 = gr.Image(show_label=False, height=500) |
|
plot_time_remaining = gr.Textbox(value=f"{(int(plot_time_limit/60)):02}:{(plot_time_limit%60):02}", label="Time Remaining", interactive=False) |
|
|
|
|
|
|
|
with gr.Column(visible=False) as uncertainty_survey_part_1: |
|
instruction_image_2 = gr.Image(show_label=False, height=300) |
|
gr.Markdown("### Uncertainty Survey") |
|
gr.Markdown("Here is a short questionnaire before you get started. Please answer the following questions as accurately as possible.") |
|
uncertainty_survey_part_1_question1 = gr.CheckboxGroup( |
|
["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"], |
|
label="Question 1: On a scale of 1-5, how certain are you that you can code this plot? " |
|
) |
|
|
|
uncertainty_survey_part_1_submit_button = gr.Button("Submit") |
|
|
|
|
|
with gr.Column(visible=False) as dialogue_page: |
|
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. \ |
|
The countdown starts when you send your first message. You can use it to help you learn \ |
|
how to code this chart. But be wise of your time; by the end of this part, \ |
|
you will not be able to interact with the LLM again. Please use your time with \ |
|
the LLM wisely, and think through your code solution before committing.\ |
|
\n\n **You may want to prompt the LLM to teach you how to produce code for this chart** \ |
|
**rather than having it output code directly. Please think about how to prompt the LLM to do this.**") |
|
with gr.Row(): |
|
instruction_image_3 = gr.Image(show_label=False, height=400) |
|
with gr.Column(): |
|
|
|
chatbot = gr.ChatInterface(chatgpt, type="messages", examples=["Teach me how to ...", "I want to learn step-by-step ...", "Explain to me slowly ..."]) |
|
chatbot.chatbot.height = 400 |
|
chatbot.chatbot.label = "Teacher LLM" |
|
|
|
part_2_time_remaining = gr.Textbox(value=f"{(int(dialogue_time_limit/60)):02}:{(dialogue_time_limit%60):02}", label="Time Remaining", interactive=False) |
|
|
|
|
|
with gr.Column(visible=False) as uncertainty_survey_part_2: |
|
instruction_image_4 = gr.Image(show_label=False, height=500) |
|
gr.Markdown("### Uncertainty Survey") |
|
gr.Markdown("Here is a short questionnaire after you have interacted with the teacher LLM. \ |
|
Please answer the following questions as accurately as possible.") |
|
uncertainty_survey_part_2_question1 = gr.CheckboxGroup( |
|
["1 - Not at all", "2 - Slightly", "3 - Moderately", "4 - Very", "5 - Extremely"], |
|
label="Question 1: On a scale of 1-5, how much did the teacher LLM help you in learning how to code this plot? " |
|
) |
|
uncertainty_survey_part_2_question2 = gr.CheckboxGroup( |
|
["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"], |
|
label="Question 2: On a scale of 1-5, how certain are you that you can code this plot now? " |
|
) |
|
uncertainty_survey_part_2_question3 = gr.CheckboxGroup( |
|
["1 - Not certain", "2 - Somewhat certain", "3 - Moderately certain", "4 - Somewhat certain", "5 - Very certain"], |
|
label="Question 3: On a scale of 1-5, how certain are you that you can code this plot even without the teacher LLM? " |
|
) |
|
uncertainty_survey_part_2_question4 = gr.CheckboxGroup( |
|
["1 - Not on topic at all", "2 - Somewhat not on topic", "3 - Moderately on topic", "4 - Somewhat on topic", "5 - Mostly on topic"], |
|
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)?" |
|
) |
|
uncertainty_survey_part_2_submit_button = gr.Button("Submit") |
|
|
|
|
|
with gr.Column(visible=False) as final_page: |
|
instruction_text = gr.Markdown(f"## Part 3: Writing the Code for the Chart \n\nThis is the final crucial step. \ |
|
You need to reproduce the original plot by writing, compiling, and running Python code. \ |
|
You are given a code skeleton below to help you, where you will fill in the \ |
|
required coding components. When you compile, you will be able to see the output of \ |
|
your code, in addition to the plot. You will be given only {max_num_submissions} attempts to compile your plot.") |
|
instruction_image_5 = gr.Image(show_label=False, height=400) |
|
code_editor = gr.Code(language="python", label="Code Editor") |
|
run_code_button = gr.Button("Compile & Run Code") |
|
processing_message = gr.Textbox(value="Processing...", visible=False) |
|
with gr.Row(): |
|
retry_button = gr.Button("Retry", visible=False) |
|
finished_button = gr.Button("Finished", visible=False) |
|
with gr.Row(): |
|
stdout_message = gr.Textbox(visible=True, label="Code Output", value="") |
|
submission_counter = gr.Number(visible=True, label="Number of Remaining Submissions", value=max_num_submissions) |
|
plot_output = gr.Image(visible=False, height=400) |
|
|
|
|
|
with gr.Column(visible=False) as uncertainty_survey_part_3: |
|
with gr.Row(): |
|
instruction_image_6 = gr.Image(label="Original Chart", height=300) |
|
generated_image = gr.Image(label="Your Generated Chart", height=300) |
|
gr.Markdown("### Uncertainty Survey") |
|
gr.Markdown("Here is a short questionnaire after you have finalized your code. Please answer the following questions as accurately as possible.") |
|
uncertainty_survey_part_3_question1 = gr.CheckboxGroup( |
|
["1 - Not at all", "2 - Slightly", "3 - Moderately", "4 - Very", "5 - Extremely"], |
|
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? " |
|
) |
|
uncertainty_survey_part_3_question2 = gr.CheckboxGroup( |
|
["1 - Much harder", "2 - Harder", "3 - As expected", "4 - Easier", "5 - Much easier"], |
|
label="Question 2: On a scale of 1-5, was the task easier or harder than you expected? " |
|
) |
|
uncertainty_survey_part_3_question3 = gr.CheckboxGroup( |
|
["1 - Could not produce", "2 - Very inaccurate", "3 - Moderately inaccurate", "4 - Somewhat accurate", "5 - Very accurate"], |
|
label="Question 3: On a scale of 1-5, how accurate is your chart compared to the original? " |
|
) |
|
uncertainty_survey_part_3_question4 = gr.CheckboxGroup( |
|
["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"], |
|
label="Question 4: On a scale of 1-5, how would you rate your experience in Python now? " |
|
) |
|
uncertainty_survey_part_3_question5 = gr.CheckboxGroup( |
|
["1 - No experience", "2 - Beginner", "3 - Intermediate", "4 - Advanced", "5 - Expert"], |
|
label="Question 5: On a scale of 1-5, how would you rate your experience in using the Matplotlib library now? " |
|
) |
|
uncertainty_survey_part_3_question6 = gr.CheckboxGroup( |
|
["1 - Very ambiguous", "2 - Somewhat ambiguous", "3 - Neither ambiguous nor clear", "4 - Somewhat clear", "5 - Very clear"], |
|
label="Question 5: On a scale of 1-5, throughout this experiment how ambigous were the instructions?" |
|
) |
|
uncertainty_survey_part_3_question7 = gr.CheckboxGroup( |
|
["1 - Very ambiguous", "2 - Somewhat ambiguous", "3 - Neither ambiguous nor clear", "4 - Somewhat clear", "5 - Very clear"], |
|
label="Question 5: On a scale of 1-5, throughout this experiment how ambigous was the given plot?" |
|
) |
|
uncertainty_survey_part_3_submit_button = gr.Button("Submit") |
|
|
|
|
|
with gr.Column(visible=False) as demographic_survey: |
|
gr.Markdown("### Demographic Survey") |
|
gr.Markdown("Please answer the following questions to help us understand your background.") |
|
demographic_survey_question1 = gr.CheckboxGroup( |
|
["Undergraduate", "Graduate", "PhD", "Postdoc", "Faculty", "Industry Professional", "Other"], |
|
label="What is your current academic status?" |
|
) |
|
demographic_survey_question2 = gr.CheckboxGroup( |
|
["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"], |
|
label="What is your college?" |
|
) |
|
demographic_survey_question3 = gr.CheckboxGroup( |
|
["18-23", "23-27", "27-31", "31-35", "35-43", "43+"], |
|
label="What is your age group?" |
|
) |
|
demographic_survey_question4 = gr.CheckboxGroup( |
|
["Woman", "Man", "Transgender", "Non-binary", "Prefer not to say"], |
|
label="What is your gender identity?" |
|
) |
|
demographic_survey_question5 = gr.CheckboxGroup( |
|
["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"], |
|
label="What is your ethnicity? (Select all that apply)" |
|
) |
|
demographic_survey_submit_button = gr.Button("Submit") |
|
|
|
|
|
with gr.Column(visible=False) as exit_page: |
|
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>.") |
|
download_button = gr.Button("Download Session Data") |
|
file_to_download = gr.File(label="Download Results") |
|
|
|
|
|
|
|
with gr.Column(visible=False) as notepad_column: |
|
notepad = gr.Textbox(lines=10, placeholder="Take notes here", value="", label="Notepad", elem_id="notepad") |
|
|
|
|
|
|
|
|
|
|
|
def on_login(users: Set[str], folder_path, assigned_images): |
|
def callback(username): |
|
if username not in users: |
|
return ( |
|
gr.update(visible=True), |
|
gr.update(visible=False), |
|
gr.update(visible=True, value="Username not found"), |
|
"", |
|
gr.update(), |
|
gr.update(), |
|
) |
|
chosen_image = os.path.join(folder_path, random.choice(assigned_images[username])) |
|
return ( |
|
gr.update(visible=False), |
|
gr.update(visible=True), |
|
gr.update(visible=False), |
|
username, |
|
chosen_image, |
|
chosen_image.replace(".png", ".py") |
|
) |
|
|
|
return callback |
|
|
|
def update_all_instruction_images(chosen_image): |
|
return ( |
|
gr.update(value=chosen_image), |
|
gr.update(value=chosen_image), |
|
gr.update(value=chosen_image), |
|
gr.update(value=chosen_image), |
|
gr.update(value=chosen_image), |
|
gr.update(value=chosen_image) |
|
) |
|
|
|
def extract_code_context(reference_code, user_state): |
|
with open(reference_code, "r") as f: |
|
code_context = f.read() |
|
print(code_context) |
|
|
|
start_index = code_context.find("# ===================\n# Part 3: Plot Configuration and Rendering\n# ===================") |
|
end_index = code_context.find("# ===================\n# Part 4: Saving Output\n# ===================") |
|
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:] |
|
|
|
end_index = code_context.find("plt.savefig") |
|
code_context = code_context[:end_index] |
|
|
|
code_context += f"plt.savefig('temp_plot_{user_state}.png')\n" |
|
|
|
return code_context |
|
|
|
def handle_expertise_survey_response(q1, q2): |
|
|
|
response = { |
|
"Question 1": q1, |
|
"Question 2": q2 |
|
} |
|
return response |
|
|
|
|
|
def handle_part1_survey_response(q1): |
|
|
|
response = { |
|
"Question 1": q1 |
|
} |
|
return response |
|
|
|
def handle_part2_survey_response(q1, q2, q3, q4): |
|
|
|
response = { |
|
"Question 1": q1, |
|
"Question 2": q2, |
|
"Question 3": q3, |
|
"Question 4": q4 |
|
} |
|
return response |
|
|
|
def handle_final_survey_response(q1, q2, q3, q4, q5, q6, q7): |
|
|
|
response = { |
|
"Question 1": q1, |
|
"Question 2": q2, |
|
"Question 3": q3, |
|
"Question 4": q4, |
|
"Question 5": q5, |
|
"Question 6": q6, |
|
"Question 7": q7 |
|
} |
|
return response |
|
|
|
def handle_demographic_survey_response(q1, q2, q3, q4, q5): |
|
|
|
response = { |
|
"Question 1": q1, |
|
"Question 2": q2, |
|
"Question 3": q3, |
|
"Question 4": q4, |
|
"Question 5": q5 |
|
} |
|
return response |
|
|
|
|
|
def plot_countdown_timer(): |
|
time_limit = plot_time_limit |
|
start_time = time.time() |
|
while time.time() - start_time < time_limit: |
|
mins, secs = divmod(time_limit - int(time.time() - start_time), 60) |
|
yield f"{mins:02}:{secs:02}", gr.update(), gr.update(visible=False) |
|
yield "00:00", gr.update(visible=False), gr.update(visible=True) |
|
|
|
|
|
def dialogue_countdown_timer(): |
|
time_limit = dialogue_time_limit |
|
start_time = time.time() |
|
while time.time() - start_time < time_limit: |
|
mins, secs = divmod(time_limit - int(time.time() - start_time), 60) |
|
yield f"{mins:02}:{secs:02}", gr.update(visible=True), gr.update(visible=False) |
|
yield "00:00", gr.update(visible=False), gr.update(visible=True) |
|
|
|
|
|
def save_dialogue_state(dialogue, dialogue_state): |
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") |
|
print(dialogue) |
|
print(dialogue_state) |
|
return dialogue_state + [timestamp, dialogue] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_download_link(user_state, chosen_image, notes_state, dialogue_state, |
|
produced_codes, reference_code, survey1, survey2, survey3, survey4, survey5): |
|
jsonl_path = Path(f"session_data_{user_state}.jsonl") |
|
with open(jsonl_path, "w") as f: |
|
f.write( |
|
json.dumps( |
|
{ |
|
"username": user_state, |
|
"chosen_image": chosen_image, |
|
"notes": notes_state, |
|
"dialogue_state": dialogue_state, |
|
"produced_codes": produced_codes, |
|
"reference_code": reference_code, |
|
"expertise_survey": survey1, |
|
"uncertainty_survey_part1": survey2, |
|
"uncertainty_survey_part2": survey3, |
|
"uncertainty_survey_part3": survey4, |
|
"demographics_survey": survey5 |
|
} |
|
) |
|
+ "\n" |
|
) |
|
|
|
image_path = Path(f"temp_plot_{user_state}.png") |
|
zip_path = Path(f"session_data_{user_state}.zip") |
|
create_zip_file(jsonl_path, image_path, zip_path) |
|
|
|
if not zip_path.exists(): |
|
return None |
|
return gr.File(value=str(zip_path), visible=True) |
|
|
|
async def on_submit(finished_code, submission_count, produced_codes, user_state): |
|
if (max_num_submissions-(submission_count+1)) == 0: |
|
|
|
yield ( |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=True), |
|
gr.update(visible=False), |
|
submission_count, |
|
produced_codes, |
|
gr.update(visible=False), |
|
gr.update(visible=False) |
|
) |
|
raise gr.Error("Max submissions reached") |
|
else: |
|
submission_count += 1 |
|
|
|
yield ( |
|
gr.update(visible=True), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
submission_count, |
|
produced_codes, |
|
gr.update(visible=False), |
|
gr.update(value=max_num_submissions-submission_count) |
|
) |
|
|
|
|
|
plot_output, stdout, stderr = await process_submission(finished_code, user_state) |
|
|
|
|
|
yield ( |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True, value=plot_output), |
|
submission_count, |
|
produced_codes + [finished_code], |
|
gr.update(visible=True, value=stdout+stderr), |
|
gr.update() |
|
) |
|
|
|
def on_retry(finished_code, produced_codes): |
|
|
|
yield ( |
|
gr.update(visible=False), |
|
gr.update(visible=True), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
produced_codes + [finished_code] |
|
) |
|
|
|
def filter_paste(previous_text, new_text): |
|
|
|
print(f"New text: {new_text}") |
|
changed_text = new_text.replace(previous_text, "") |
|
if len(changed_text) > 10: |
|
return previous_text, previous_text |
|
previous_text = new_text |
|
print(f"Previous text: {previous_text}") |
|
return previous_text, new_text |
|
|
|
def save_notes_with_timestamp(notes, notes_state): |
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") |
|
notes_state.append(f"{timestamp}: {notes}") |
|
return notes_state |
|
|
|
|
|
|
|
|
|
|
|
login_button.click( |
|
on_login(users, folder_path, assigned_images), |
|
inputs=[username_input], |
|
outputs=[login_row, expertise_survey, login_error_message, user_state, chosen_image_state, reference_code_state], |
|
) |
|
|
|
|
|
|
|
|
|
|
|
expertise_survey_submit_button.click( |
|
handle_expertise_survey_response, |
|
inputs=[expertise_survey_question1, expertise_survey_question2], |
|
outputs=[expertise_survey_responses] |
|
) |
|
|
|
expertise_survey_submit_button.click( |
|
lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=True)), |
|
inputs=[], outputs=[expertise_survey, instructions_page, notepad_column] |
|
) |
|
|
|
expertise_survey_submit_button.click( |
|
update_all_instruction_images, |
|
inputs=[chosen_image_state], outputs=[instruction_image_1, instruction_image_2, |
|
instruction_image_3, instruction_image_4, |
|
instruction_image_5, instruction_image_6] |
|
) |
|
|
|
expertise_survey_submit_button.click(plot_countdown_timer, outputs=[plot_time_remaining, instructions_page, uncertainty_survey_part_1]) |
|
|
|
uncertainty_survey_part_1_submit_button.click( |
|
handle_part1_survey_response, |
|
inputs=[uncertainty_survey_part_1_question1], |
|
outputs=[uncertainty_survey_part_1_responses] |
|
) |
|
|
|
uncertainty_survey_part_1_submit_button.click( |
|
lambda: (gr.update(visible=False), gr.update(visible=True)), |
|
inputs=[], outputs=[uncertainty_survey_part_1, dialogue_page] |
|
) |
|
|
|
chatbot.chatbot.change( |
|
dialogue_countdown_timer, |
|
outputs=[part_2_time_remaining, dialogue_page, uncertainty_survey_part_2], |
|
trigger_mode = "once" |
|
) |
|
|
|
|
|
chatbot.chatbot.change( |
|
save_dialogue_state, |
|
inputs=[chatbot.chatbot, dialogue_state], |
|
outputs=[dialogue_state] |
|
) |
|
|
|
uncertainty_survey_part_2_submit_button.click( |
|
handle_part2_survey_response, |
|
inputs=[uncertainty_survey_part_2_question1, uncertainty_survey_part_2_question2, |
|
uncertainty_survey_part_2_question3, uncertainty_survey_part_2_question4], |
|
outputs=[uncertainty_survey_part_2_responses] |
|
) |
|
|
|
uncertainty_survey_part_2_submit_button.click( |
|
lambda: (gr.update(visible=False), gr.update(visible=True)), |
|
inputs=[], outputs=[uncertainty_survey_part_2, final_page] |
|
) |
|
|
|
uncertainty_survey_part_2_submit_button.click( |
|
extract_code_context, |
|
inputs=[reference_code_state, user_state], outputs=[code_editor] |
|
) |
|
|
|
run_code_button.click( |
|
on_submit, |
|
inputs=[code_editor, submission_count, produced_codes, user_state], |
|
outputs=[ |
|
processing_message, |
|
run_code_button, |
|
retry_button, |
|
finished_button, |
|
plot_output, |
|
submission_count, |
|
produced_codes, |
|
stdout_message, |
|
submission_counter |
|
], |
|
) |
|
|
|
retry_button.click( |
|
on_retry, |
|
inputs=[code_editor, produced_codes], |
|
outputs=[ |
|
processing_message, |
|
run_code_button, |
|
retry_button, |
|
finished_button, |
|
plot_output, |
|
produced_codes, |
|
], |
|
) |
|
|
|
finished_button.click( |
|
lambda user_state: (gr.update(visible=False), gr.update(visible=True), f"temp_plot_{user_state}.png"), |
|
inputs=[user_state], outputs=[final_page, uncertainty_survey_part_3, generated_image] |
|
) |
|
|
|
uncertainty_survey_part_3_submit_button.click( |
|
handle_final_survey_response, |
|
inputs=[uncertainty_survey_part_3_question1, uncertainty_survey_part_3_question2, |
|
uncertainty_survey_part_3_question3, uncertainty_survey_part_3_question4, |
|
uncertainty_survey_part_3_question5, uncertainty_survey_part_3_question6, |
|
uncertainty_survey_part_3_question7], |
|
outputs=[uncertainty_survey_part_3_responses] |
|
) |
|
|
|
uncertainty_survey_part_3_submit_button.click( |
|
lambda: (gr.update(visible=False), gr.update(visible=True)), |
|
inputs=[], outputs=[uncertainty_survey_part_3, demographic_survey] |
|
) |
|
|
|
demographic_survey_submit_button.click( |
|
handle_demographic_survey_response, |
|
inputs=[demographic_survey_question1, demographic_survey_question2, demographic_survey_question3, demographic_survey_question4, demographic_survey_question5], |
|
outputs=[demographic_survey_responses] |
|
) |
|
|
|
demographic_survey_submit_button.click( |
|
lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)), |
|
inputs=[], outputs=[demographic_survey, exit_page, download_button, notepad] |
|
) |
|
|
|
|
|
|
|
|
|
|
|
demographic_survey_submit_button.click(save_notes_with_timestamp, |
|
inputs=[notepad, notes_state], |
|
outputs=[notes_state]) |
|
|
|
download_button.click( |
|
get_download_link, |
|
inputs=[user_state, chosen_image_state, notes_state, |
|
dialogue_state, produced_codes, reference_code_state, |
|
expertise_survey_responses, |
|
uncertainty_survey_part_1_responses, |
|
uncertainty_survey_part_2_responses, |
|
uncertainty_survey_part_3_responses, |
|
demographic_survey_responses], |
|
outputs=[file_to_download] |
|
) |
|
|
|
demo.load( |
|
lambda: gr.update(visible=True), |
|
outputs=login_row, |
|
) |
|
|
|
return demo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
users = Path("users.txt").read_text().splitlines() |
|
users = set(user.strip() for user in users if user.strip()) |
|
|
|
|
|
|
|
demo = create_interface(users) |
|
|
|
demo.launch() |
|
|