Update app.py
Browse files
app.py
CHANGED
@@ -4,125 +4,114 @@ import string
|
|
4 |
import time
|
5 |
from collections import defaultdict
|
6 |
|
7 |
-
# Global variables
|
8 |
-
students = {}
|
9 |
-
class_data = defaultdict(lambda: {"students": set(), "questions": []})
|
10 |
-
|
11 |
def generate_student_id():
|
12 |
return ''.join(random.choices(string.ascii_letters + string.digits, k=12))
|
13 |
|
14 |
-
def update_student_state(
|
15 |
-
if
|
16 |
-
students[
|
17 |
-
students[
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
-
def
|
22 |
-
|
23 |
-
|
24 |
|
25 |
-
|
26 |
-
class_students = [s for s in students.values() if s["class_id"] == class_id]
|
27 |
total_students = len(class_students)
|
28 |
-
active_students = sum(1 for s in class_students if s["color"] != "inactive")
|
29 |
color_counts = {"green": 0, "yellow": 0, "red": 0}
|
30 |
-
|
|
|
31 |
if student["color"] in color_counts:
|
32 |
color_counts[student["color"]] += 1
|
33 |
|
34 |
color_fractions = {color: count / (active_students or 1) for color, count in color_counts.items()}
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
"
|
39 |
-
"color_fractions
|
40 |
-
"
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
with gr.
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
color_buttons = [
|
53 |
gr.Button("π’ I'm following along", variant="primary"),
|
54 |
gr.Button("π‘ I need clarification", variant="secondary"),
|
55 |
gr.Button("π΄ I'm lost, please stop", variant="stop")
|
56 |
]
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
for button, color in zip(color_buttons, ["green", "yellow", "red"]):
|
65 |
button.click(
|
66 |
update_student_state,
|
67 |
-
inputs=[
|
68 |
-
outputs=status
|
69 |
)
|
70 |
|
71 |
submit_button.click(
|
72 |
submit_question,
|
73 |
-
inputs=[
|
74 |
-
outputs=question_status
|
75 |
)
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
color_chart = f"""
|
83 |
-
<div style="width: 100%; height: 60px; display: flex;">
|
84 |
-
<div style="width: {stats['color_fractions']['red']*100}%; background-color: #ff6b6b;"></div>
|
85 |
-
<div style="width: {stats['color_fractions']['yellow']*100}%; background-color: #feca57;"></div>
|
86 |
-
<div style="width: {stats['color_fractions']['green']*100}%; background-color: #5cd85c;"></div>
|
87 |
-
</div>
|
88 |
-
"""
|
89 |
-
stats_text = f"""
|
90 |
-
<h3>Class Statistics</h3>
|
91 |
-
<p>Total Students: {stats['total_students']}</p>
|
92 |
-
<p>Active Students: {stats['active_students']}</p>
|
93 |
-
"""
|
94 |
-
questions_text = "<h3>Student Questions</h3>"
|
95 |
-
for q in stats['questions']:
|
96 |
-
questions_text += f"<p><strong>Student {q['student_id'][:4]}...</strong>: {q['question']}</p>"
|
97 |
-
|
98 |
-
return f"{color_chart}<br>{stats_text}<br>{questions_text}"
|
99 |
-
|
100 |
-
with gr.Blocks() as teacher_interface:
|
101 |
-
gr.Markdown(f"## Teacher Interface - Class {class_id}")
|
102 |
-
gr.Markdown("Monitor student understanding and view questions.")
|
103 |
-
|
104 |
-
stats_html = gr.HTML()
|
105 |
-
refresh_button = gr.Button("Refresh Stats")
|
106 |
-
|
107 |
-
refresh_button.click(render_stats, inputs=[], outputs=[stats_html])
|
108 |
|
109 |
# Auto-refresh every 5 seconds
|
110 |
gr.HTML('<script>setInterval(function(){ document.querySelector("button[aria-label=\'Refresh Stats\']").click(); }, 5000);</script>')
|
111 |
|
112 |
-
return
|
113 |
-
|
114 |
-
def launch_app(class_id):
|
115 |
-
with gr.Blocks(theme=gr.themes.Soft()) as app:
|
116 |
-
gr.Markdown(f"# Fastcups - Class {class_id}")
|
117 |
-
|
118 |
-
with gr.Tabs():
|
119 |
-
with gr.TabItem("Student"):
|
120 |
-
create_student_interface(class_id)
|
121 |
-
with gr.TabItem("Teacher"):
|
122 |
-
create_teacher_interface(class_id)
|
123 |
-
|
124 |
-
app.launch(share=True)
|
125 |
|
126 |
if __name__ == "__main__":
|
127 |
-
|
128 |
-
|
|
|
4 |
import time
|
5 |
from collections import defaultdict
|
6 |
|
|
|
|
|
|
|
|
|
7 |
def generate_student_id():
|
8 |
return ''.join(random.choices(string.ascii_letters + string.digits, k=12))
|
9 |
|
10 |
+
def update_student_state(students, class_id, student_id, color):
|
11 |
+
if class_id not in students:
|
12 |
+
students[class_id] = {}
|
13 |
+
students[class_id][student_id] = {"color": color}
|
14 |
+
return students, f"Status updated to {color}"
|
15 |
+
|
16 |
+
def submit_question(questions, class_id, student_id, question):
|
17 |
+
if class_id not in questions:
|
18 |
+
questions[class_id] = []
|
19 |
+
questions[class_id].append({"student_id": student_id, "question": question})
|
20 |
+
return questions, "Question submitted successfully"
|
21 |
|
22 |
+
def get_class_stats(students, questions, class_id):
|
23 |
+
if class_id not in students:
|
24 |
+
return "No data available for this class."
|
25 |
|
26 |
+
class_students = students[class_id]
|
|
|
27 |
total_students = len(class_students)
|
28 |
+
active_students = sum(1 for s in class_students.values() if s["color"] != "inactive")
|
29 |
color_counts = {"green": 0, "yellow": 0, "red": 0}
|
30 |
+
|
31 |
+
for student in class_students.values():
|
32 |
if student["color"] in color_counts:
|
33 |
color_counts[student["color"]] += 1
|
34 |
|
35 |
color_fractions = {color: count / (active_students or 1) for color, count in color_counts.items()}
|
36 |
|
37 |
+
color_chart = f"""
|
38 |
+
<div style="width: 100%; height: 60px; display: flex;">
|
39 |
+
<div style="width: {color_fractions['red']*100}%; background-color: #ff6b6b;"></div>
|
40 |
+
<div style="width: {color_fractions['yellow']*100}%; background-color: #feca57;"></div>
|
41 |
+
<div style="width: {color_fractions['green']*100}%; background-color: #5cd85c;"></div>
|
42 |
+
</div>
|
43 |
+
"""
|
44 |
+
stats_text = f"""
|
45 |
+
<h3>Class Statistics</h3>
|
46 |
+
<p>Total Students: {total_students}</p>
|
47 |
+
<p>Active Students: {active_students}</p>
|
48 |
+
"""
|
49 |
+
questions_text = "<h3>Student Questions</h3>"
|
50 |
+
for q in questions.get(class_id, []):
|
51 |
+
questions_text += f"<p><strong>Student {q['student_id'][:4]}...</strong>: {q['question']}</p>"
|
52 |
+
|
53 |
+
return f"{color_chart}<br>{stats_text}<br>{questions_text}"
|
54 |
+
|
55 |
+
def create_interface():
|
56 |
+
with gr.Blocks(theme=gr.themes.Soft()) as app:
|
57 |
+
students = gr.State({})
|
58 |
+
questions = gr.State({})
|
59 |
+
class_id = gr.State("")
|
60 |
+
student_id = gr.State("")
|
61 |
+
|
62 |
+
gr.Markdown("# Fastcups")
|
63 |
|
64 |
+
with gr.Tab("Setup"):
|
65 |
+
class_input = gr.Textbox(label="Enter Class ID")
|
66 |
+
setup_button = gr.Button("Set Class ID")
|
67 |
+
|
68 |
+
with gr.Tab("Student"):
|
69 |
+
gr.Markdown("## Student Interface")
|
70 |
+
status = gr.Textbox(label="Current Status", interactive=False)
|
71 |
+
with gr.Row():
|
72 |
color_buttons = [
|
73 |
gr.Button("π’ I'm following along", variant="primary"),
|
74 |
gr.Button("π‘ I need clarification", variant="secondary"),
|
75 |
gr.Button("π΄ I'm lost, please stop", variant="stop")
|
76 |
]
|
77 |
+
question_input = gr.Textbox(label="Ask a question")
|
78 |
+
submit_button = gr.Button("Submit Question")
|
79 |
+
question_status = gr.Textbox(label="Question Status", interactive=False)
|
80 |
+
|
81 |
+
with gr.Tab("Teacher"):
|
82 |
+
gr.Markdown("## Teacher Interface")
|
83 |
+
stats_html = gr.HTML()
|
84 |
+
refresh_button = gr.Button("Refresh Stats")
|
85 |
+
|
86 |
+
def setup_class(class_id_input):
|
87 |
+
return class_id_input, generate_student_id()
|
88 |
+
|
89 |
+
setup_button.click(setup_class, inputs=[class_input], outputs=[class_id, student_id])
|
90 |
|
91 |
for button, color in zip(color_buttons, ["green", "yellow", "red"]):
|
92 |
button.click(
|
93 |
update_student_state,
|
94 |
+
inputs=[students, class_id, student_id, gr.State(color)],
|
95 |
+
outputs=[students, status]
|
96 |
)
|
97 |
|
98 |
submit_button.click(
|
99 |
submit_question,
|
100 |
+
inputs=[questions, class_id, student_id, question_input],
|
101 |
+
outputs=[questions, question_status]
|
102 |
)
|
103 |
|
104 |
+
refresh_button.click(
|
105 |
+
get_class_stats,
|
106 |
+
inputs=[students, questions, class_id],
|
107 |
+
outputs=[stats_html]
|
108 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
|
110 |
# Auto-refresh every 5 seconds
|
111 |
gr.HTML('<script>setInterval(function(){ document.querySelector("button[aria-label=\'Refresh Stats\']").click(); }, 5000);</script>')
|
112 |
|
113 |
+
return app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
if __name__ == "__main__":
|
116 |
+
app = create_interface()
|
117 |
+
app.launch()
|