|
import gradio as gr |
|
import json |
|
import os |
|
import sqlite3 |
|
from pathlib import Path |
|
from dotenv import load_dotenv |
|
|
|
""" |
|
Gradio app to accept student submissions. |
|
Reads os.getenv('SESSION_ID')/*.json files, each file contains one problem. Display the problems in one page and accept student submissions. |
|
json keys: |
|
"Problem_markdown" |
|
"Hint" |
|
"Template_Code" |
|
"Solution_markdown" |
|
"Solution_Code" |
|
"Testing_Code" |
|
|
|
Top of page display input box for student to enter his name and email. Then display all problems in the db/*.json files. |
|
For each problem, from top down to display the "Problem_markdown" as markdown, then a button to request showing "Hint" as markdown, then show input box with "Template_Code" prefilled. then show "Save" button to save student input for this problem in sqlite3 db. Then show "Testing_Code" as markdown (wrapped in ```python). Save button just saves the student input for this problem in sqlite3 db and student can still see his code. If student request hint, please record this in sqlite3 db. Multiple "save" overrides the previous submission. |
|
|
|
After all problems are displayed, show a "Submit" button to submit all student inputs to sqlite3 db. |
|
|
|
sqlite schema: |
|
table: student_submissions |
|
columns: session, name, email, problem_id, student_code, hint_requested |
|
|
|
problem_id is the json file name without the extension. |
|
session is a unique id for this session from env var SESSION_ID using dotenv and os.getenv('SESSION_ID') |
|
""" |
|
|
|
load_dotenv() |
|
SESSION_ID = os.getenv('SESSION_ID') |
|
|
|
def load_problems(): |
|
problems = [] |
|
db_path = Path(SESSION_ID) |
|
for json_file in db_path.glob('*.json'): |
|
with open(json_file) as f: |
|
problem = json.load(f) |
|
problem['id'] = json_file.stem |
|
problems.append(problem) |
|
return problems |
|
|
|
def save_submission(session, name, email, problem_id, code, hint_requested): |
|
conn = sqlite3.connect('submissions.db') |
|
c = conn.cursor() |
|
c.execute('''CREATE TABLE IF NOT EXISTS student_submissions |
|
(session TEXT, name TEXT, email TEXT, problem_id TEXT, |
|
student_code TEXT, hint_requested INTEGER)''') |
|
c.execute('''INSERT OR REPLACE INTO student_submissions VALUES (?, ?, ?, ?, ?, ?)''', |
|
(session, name, email, problem_id, code, hint_requested)) |
|
conn.commit() |
|
conn.close() |
|
|
|
def create_app(): |
|
problems = load_problems() |
|
|
|
with gr.Blocks() as app: |
|
name = gr.Textbox(label="Name") |
|
email = gr.Textbox(label="Email") |
|
|
|
for problem in problems: |
|
gr.Markdown("---") |
|
gr.Markdown(problem["Problem_markdown"]) |
|
|
|
hint_state = gr.State(value=False) |
|
hint_button = gr.Button("Show Hint") |
|
hint_text = gr.Markdown(visible=False) |
|
|
|
code_box = gr.Code(language="python", value=problem["Template_Code"]) |
|
save_button = gr.Button("Save") |
|
|
|
gr.Markdown(f"```python\n{problem['Testing_Code']}\n```") |
|
|
|
def show_hint(state): |
|
return not state, gr.update(visible=True) |
|
|
|
def save_code(name, email, code, hint_shown, prob_id=problem['id']): |
|
save_submission(SESSION_ID, name, email, prob_id, code, hint_shown) |
|
return "Saved!" |
|
|
|
hint_button.click(show_hint, hint_state, [hint_state, hint_text]) |
|
save_button.click(save_code, [name, email, code_box, hint_state]) |
|
|
|
submit_all = gr.Button("Submit All") |
|
|
|
return app |
|
|
|
if __name__ == "__main__": |
|
app = create_app() |
|
app.launch() |