File size: 3,692 Bytes
d762a7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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()