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"

{output['Assignment']}

{output['Solutions'][0]}

" return f"

Ouput (unknown type)

{output['Solutions'][0]}

" 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("") 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("

Output

Placeholder for output
") # 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""), [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)