tommymarto's picture
wip update
7832cd9
raw
history blame
14.7 kB
import datetime
import os
import json
import gradio as gr
import requests
import firebase_admin
from itertools import chain
from firebase_admin import db, credentials
def clamp(x, minimum, maximum):
return max(minimum, min(x, maximum))
#################################################################################################################################################
# API calls
#################################################################################################################################################
# read secret api key
API_KEY = os.environ['ApiKey']
FIREBASE_API_KEY = os.environ['FirebaseSecret']
FIREBASE_URL = os.environ['FirebaseURL']
SETUP_MODEL = os.environ['SETUP_MODEL']
# creds = credentials.Certificate(json.loads(FIREBASE_API_KEY))
# firebase_app = firebase_admin.initialize_app(creds, {'databaseURL': FIREBASE_URL})
# firebase_data_ref = db.reference("data")
# firebase_current_ref = None
BASE_URL = "https://skapi.polyglot-edu.com/"
##################################################################
# Data Layer
##################################################################
levels = ["Primary School", "Middle School", "High School", "College", "Academy"]
languages = ["English", "Italian", "French", "German", "Spanish"]
type_of_exercise = ["Open Question", "Short Answer Question", "True or False", "Fill in the Blanks", "Single Choice", "Multiple Choice", "Debate", "Essay", "Brainstorming", "Knoledge Exposition"]
def generation_to_dict(experiment, skip=False):
info = {
# experiment info
**experiment,
# chosen image set info
"corrupted_filename": experiment["corrupted"]["name"],
"options": [img["name"] for img in experiment["options"]],
}
if skip:
info = {
**info,
# selected image info
"selected_image": "None",
"selected_algo": "None",
}
else:
info = {
**info,
# selected image info
"selected_image": experiment["options"][experiment["selected_image"]]["name"],
"selected_algo": experiment["options"][experiment["selected_image"]]["algo"],
}
return info
def generate_new_experiment():
pass
# wanted_corruptions = ["spatter", "impulse_noise", "speckle_noise", "gaussian_noise", "pixelate", "jpeg_compression", "elastic_transform"]
# corruption = random.choice([f for f in list(Path(f"./images/{DATASET}").glob("*/*")) if f.is_dir() and f.name in wanted_corruptions])
# image_id = random.choice(list(corruption.glob("*")))
# imgs_to_sample = (NUMBER_OF_IMAGES_PER_ROW * NUMBER_OF_ROWS) // 2
# corrupted_image = {"name": str(random.choice(list(image_id.glob("*corrupted*"))))}
# sdedit_images = [
# {"name": str(img), "algo": "SDEdit"}
# for img in random.sample(list((image_id / "sde").glob(f"*")), imgs_to_sample)
# ]
# odedit_images = [
# {"name": str(img), "algo": "ODEdit"}
# for img in random.sample(list((image_id / "ode").glob(f"*")), imgs_to_sample)
# ]
# total_images = sdedit_images + odedit_images
# random.shuffle(total_images)
# return Experiment(
# DATASET,
# corruption.name,
# image_id.name,
# corrupted_image,
# total_images,
# )
def save(experiment, corrupted_component, *img_components, mode):
if mode == "save" and (experiment is None or experiment["selected_image"] is None):
gr.Warning("You must select an image before submitting")
return [experiment, corrupted_component, *img_components]
if mode == "skip":
experiment["selected_image"] = None
dict_to_save = {
**generation_to_dict(experiment, skip=(mode=="skip")),
"timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
# firebase_data_ref.push(dict_to_save)
print("=====================")
print(dict_to_save)
print("=====================")
gr.Info("Your choice has been saved to Firebase")
return next()
def analyze_resource(url):
response = requests.post(
BASE_URL + "Analyser/analyseMaterial",
headers={"ApiKey": API_KEY, "SetupModel": str(SETUP_MODEL)},
json={
"material": url
},
timeout=20
)
if response.status_code != 200:
raise gr.Error(f"Failed to analyze resource: {response.text}")
return response.json()
def generate_learning_objective(topic, context, level):
response = requests.post(
BASE_URL + "LOGenerator/generatelearningobjective",
headers={"ApiKey": API_KEY, "SetupModel": str(SETUP_MODEL)},
json={
"topic": topic,
"context": context,
"level": levels.index(level)
},
timeout=20
)
print(topic, context, level)
if response.status_code != 200:
raise gr.Error(f"Failed to generate learning objective: {response.text}")
return response.json()
def generate_exercise(state):
def find_key(d, item):
for key, value in d.items():
if item in value:
return key
return None
step3 = requests.post(
BASE_URL + "Exercises/GenerateExercise",
headers={"ApiKey": API_KEY, "SetupModel": str(SETUP_MODEL)},
json={
# filled in with the data from the previous steps
"macroSubject": state['MacroSubject'],
"title": state['Title'],
"level": state['level'],
"learningObjective": state['learningObjective'],
"bloomLevel": find_key(state["learningObjectiveList"], state['learningObjective']),
"language": state['Language'],
"material": state['material_url'],
"assignmentType": [topic['Type'] for topic in state['MainTopics'] if topic['Topic'] == state['topic']][0],
"topic": state['topic'],
"temperature": 0,
# to be filled in manually
"correctAnswersNumber": 0,
"distractorsNumber": 0,
"easilyDiscardableDistractorsNumber": 0,
"typeOfExercise": 0
},
timeout=20
)
##################################################################
# UI Layer
##################################################################
def format_output(output, exercise_type):
if type_of_exercise[exercise_type] in ["Open Question", "Short Answer Question"]:
return f"<div class='markdown-body'><h3>{output['Assignment']}</h3><p>{output['Solutions'][0]}</p></div>"
return f"<div class='markdown-body'><h3>Ouput (unknown type)</h3><p>{output['Solutions'][0]}</p></div>"
def reset_UI():
return [
{"level": levels[-1], "language": "English"},
]
def next():
new_experiment = generate_new_experiment()
new_img_components = [
gr.Image(value=img["name"], label=f"{i}", elem_id="unsel", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
for i, img in enumerate(new_experiment["options"])
]
new_corrupted_component = gr.Image(value=new_experiment["corrupted"]["name"], label="corr", elem_id="corrupted", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
return [new_experiment, new_corrupted_component, *new_img_components]
def on_url_change(url, state):
material = analyze_resource(url)
topics = [topic['Topic'] for topic in material['MainTopics']]
components = reset_UI()
state = components[0]
state = state | material
state['material_url'] = url
return [gr.Radio(label="Topic", choices=topics, interactive=True), state]
def on_topic_change(topic, old_state):
old_state['topic'] = topic
learning_objective = generate_learning_objective(topic, f"A {old_state['level']} class", old_state["level"])
old_state['learningObjectiveList'] = learning_objective
possible_objectives = list(chain.from_iterable(learning_objective.values()))
return [gr.Dropdown(label="Learning Objective", choices=possible_objectives, value=possible_objectives[0], interactive=True), old_state]
css = """
body, html {
margin: 0;
height: 100%; /* Full height */
width: 100%; /* Full width */
overflow: hidden; /* Prevent scrolling */
}
.interface, .block-container {
display: flex;
flex-direction: column;
height: 100%; /* Full height */
width: 100%; /* Full width */
}
.row-content {
height: 90vh; /* Full height */
}
.column-content {
display: flex;
flex-direction: column;
flex: 1; /* Flexibly take up available space */
height: 100%; /* Full height */
}
iframe.second-row {
width: 100%; /* Full width */
height: 50vh; /* Full height */
border: none; /* No border */
background-color: #f9f9f9; /* Light background */
}
/* Base style for Markdown content */
.markdown-body {
font-family: 'Helvetica Neue', Arial, sans-serif; /* Clean and modern font */
line-height: 1.6; /* Ample line height for readability */
font-size: 16px; /* Standard font size for readability */
color: #333; /* Dark grey color for text for less strain */
background-color: #f9f9f9; /* Light background to reduce glare */
padding: 20px; /* Padding around text */
border-radius: 8px; /* Slightly rounded corners for a softer look */
box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* Subtle shadow for depth */
max-width: 800px; /* Max width to maintain optimal line length */
margin: 20px auto; /* Center align the Markdown content */
}
/* Headings with increased weight and spacing for clear hierarchy */
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
color: #2a2a2a; /* Slightly darker than the text color */
margin-top: 24px;
margin-bottom: 16px;
font-weight: bold;
}
.markdown-body h1 {
font-size: 2em; /* Larger size for main titles */
}
.markdown-body h2 {
font-size: 1.5em;
}
.markdown-body h3 {
font-size: 1.17em;
}
/* Paragraphs with bottom margin for better separation */
.markdown-body p {
margin-bottom: 16px;
}
/* Links with a subtle color to stand out */
.markdown-body a {
color: #0656b5;
text-decoration: none; /* No underline */
}
.markdown-body a:hover,
.markdown-body a:focus {
text-decoration: underline; /* Underline on hover/focus for visibility */
}
/* Lists styled with padding and margin for clarity */
.markdown-body ul,
.markdown-body ol {
padding-left: 20px;
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body li {
margin-bottom: 8px; /* Space between list items */
}
/* Blockquotes with a left border and padding for emphasis */
.markdown-body blockquote {
padding: 10px 20px;
margin: 0;
border-left: 5px solid #ccc; /* Subtle grey line to indicate quotes */
background-color: #f0f0f0; /* Very light background for contrast */
font-style: italic;
}
/* Code styling for inline and blocks */
.markdown-body code {
font-family: monospace;
background-color: #eee; /* Light grey background */
padding: 2px 4px;
border-radius: 3px; /* Rounded corners for code blocks */
font-size: 90%;
}
.markdown-body pre {
background-color: #f4f4f4; /* Slightly different background for distinction */
border: 1px solid #ddd; /* Border for definition */
padding: 10px; /* Padding inside code blocks */
overflow: auto; /* Auto-scroll for overflow */
line-height: 1.45;
border-radius: 5px;
}
"""
with gr.Blocks(title="Educational AI", css=css) as demo:
state = gr.State({"level": levels[-1], "language": "English"})
with gr.Row(elem_classes=["row-content"]):
with gr.Column(scale=3, elem_classes=["column-content"]):
language_component = gr.Dropdown(languages, label="Exercise Language", value="English")
level_component = gr.Dropdown(label="Level", choices=levels, value=levels[-1])
url_component = gr.Textbox(label="Input URL", placeholder="Enter URL here...")
iframe_component = gr.HTML("<iframe class='second-row' src='' allowfullscreen></iframe>")
with gr.Column(scale=3):
topic_component = gr.Radio(label="Topic", choices=["placeholder"], interactive=False)
lo_component = gr.Dropdown(label="Learning Objective", choices=[], value="placeholder", interactive=False)
question_type_component = gr.Dropdown(label="Question Type", choices=type_of_exercise, type="index")
correct_answers_component = gr.Number(value=1, minimum=1, maximum=3, step=1, label="Number of correct answers", interactive=False)
easy_distractors_component = gr.Number(value=1, minimum=0, maximum=8, step=1, label="Number of easy distractors", interactive=False)
distractors_component = gr.Number(value=1, minimum=0, maximum=8, step=1, label="Number of distractors", interactive=False)
with gr.Column(scale=3):
generate_btn = gr.Button("Generate Question")
output_component = gr.HTML("<div class='markdown-body'><h3>Output</h3>Placeholder for output</div>")
# on language change
language_component.change(lambda x, old_state: old_state | {"language": x}, [language_component, state], [state])
# on level change
level_component.change(lambda x, old_state: old_state | {"level": x}, [level_component, state], [state])
# on url change
url_component.change(lambda x: gr.HTML(f"<iframe class='second-row' src='{x}' allowfullscreen></iframe>"), [url_component], [iframe_component])
url_component.change(lambda x: gr.Info(f"Analyzing resource at {x}..."), [url_component], [])
url_component.change(on_url_change, [url_component, state], [topic_component, state])
# on topic change
topic_component.change(lambda x: gr.Info(f"Generating learning objective for {x}..."), [topic_component], [])
topic_component.change(on_topic_change, [topic_component, state], [lo_component, state])
# on lo change
lo_component.change(lambda x, old_state: old_state | {"learningObjective": x}, [lo_component, state], [state])
# on question type change
question_type_component.change(lambda x, old_state: old_state | {"typeOfExercise": x}, [question_type_component, state], [state])
# on generate question
generate_btn.click(lambda: gr.Info("Generating question..."))
generate_btn.click(generate_exercise, [state], [output_component])
demo.launch(show_api=False)