jonels1988 commited on
Commit
4e80d3c
Β·
verified Β·
1 Parent(s): 056e26b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -471
app.py CHANGED
@@ -1,13 +1,10 @@
1
  import gradio as gr
2
  import pandas as pd
3
- import numpy as np
4
- from PIL import Image
5
- import os
6
  import json
 
7
  from datetime import datetime
8
- import uuid
9
 
10
- print("πŸš€ Teacher Assistant Starting...")
11
 
12
  # ============ DATA STORAGE ============
13
  DATA_DIR = "data"
@@ -18,7 +15,6 @@ EXAMS_FILE = os.path.join(DATA_DIR, "exams.json")
18
  GRADES_FILE = os.path.join(DATA_DIR, "grades.json")
19
 
20
  def load_json(filepath):
21
- """Load JSON data"""
22
  if os.path.exists(filepath):
23
  try:
24
  with open(filepath, 'r') as f:
@@ -28,98 +24,54 @@ def load_json(filepath):
28
  return {}
29
 
30
  def save_json(data, filepath):
31
- """Save JSON data"""
32
  with open(filepath, 'w') as f:
33
  json.dump(data, f, indent=2)
34
 
35
- def init_data():
36
- """Initialize data files"""
37
- for filepath in [STUDENTS_FILE, EXAMS_FILE, GRADES_FILE]:
38
- if not os.path.exists(filepath):
39
- save_json({}, filepath)
40
-
41
- init_data()
42
 
43
  # ============ TAB 1: QUESTION GENERATOR ============
44
- def generate_questions(topic, num_questions, question_type):
45
- """Generate sample questions"""
46
  if not topic:
47
- return "❌ Please enter a topic", "", ""
48
 
49
  questions = []
50
  answers = []
51
 
52
- templates = {
53
- "Multiple Choice": [
54
- "What is the capital of {topic}?",
55
- "Which of these is NOT related to {topic}?",
56
- "Who discovered {topic}?",
57
- "When was {topic} first studied?"
58
- ],
59
- "True or False": [
60
- "{topic} is always true.",
61
- "{topic} can be observed in nature.",
62
- "{topic} was discovered in the 20th century.",
63
- "{topic} has practical applications."
64
- ],
65
- "Identification": [
66
- "Define {topic}.",
67
- "Name the main component of {topic}.",
68
- "What principle governs {topic}?",
69
- "Identify the key characteristic of {topic}."
70
- ],
71
- "Essay": [
72
- "Discuss the importance of {topic}.",
73
- "Explain how {topic} functions.",
74
- "Analyze the impact of {topic}.",
75
- "Describe the historical development of {topic}."
76
- ],
77
- "Matching Type": [
78
- "Match terms related to {topic}.",
79
- "Connect concepts about {topic}.",
80
- "Pair examples of {topic}.",
81
- "Link definitions about {topic}."
82
- ]
83
- }
84
-
85
- question_list = templates.get(question_type, ["Question about {topic}"])
86
-
87
- for i in range(min(num_questions, len(question_list))):
88
- q_template = question_list[i]
89
- q = q_template.format(topic=topic)
90
-
91
- if question_type == "Multiple Choice":
92
- question_text = f"Q{i+1}: {q}\nA) Option A\nB) Option B\nC) Option C\nD) Option D"
93
- answer_text = f"A{i+1}: C"
94
- elif question_type == "True or False":
95
- question_text = f"Q{i+1}: {q} (True/False)"
96
- answer_text = f"A{i+1}: True"
97
- elif question_type == "Identification":
98
- question_text = f"Q{i+1}: {q} __________"
99
- answer_text = f"A{i+1}: Answer"
100
- elif question_type == "Essay":
101
- question_text = f"Q{i+1}: {q}\n\n[Write your essay here]"
102
- answer_text = f"A{i+1}: [Grading rubric: Content 10, Structure 5, Grammar 5]"
103
- elif question_type == "Matching Type":
104
- question_text = f"Q{i+1}: {q}\n\n1. Term 1 β†’ A. Definition 1\n2. Term 2 β†’ B. Definition 2\n3. Term 3 β†’ C. Definition 3"
105
- answer_text = f"A{i+1}: 1-A, 2-B, 3-C"
106
- else:
107
- question_text = f"Q{i+1}: {q}"
108
- answer_text = f"A{i+1}: Sample answer"
109
 
110
- questions.append(question_text)
111
- answers.append(answer_text)
112
 
113
- # Save exam
114
- exam_id = f"EXAM-{datetime.now().strftime('%Y%m%d%H%M%S')}"
115
  exam_data = {
116
  "id": exam_id,
117
  "topic": topic,
118
- "type": question_type,
119
  "questions": questions,
120
  "answers": answers,
121
- "created": datetime.now().isoformat(),
122
- "num_questions": num_questions
123
  }
124
 
125
  exams = load_json(EXAMS_FILE)
@@ -128,133 +80,91 @@ def generate_questions(topic, num_questions, question_type):
128
 
129
  return "\n\n".join(questions), "\n\n".join(answers), exam_id
130
 
131
- def save_exam_file(questions, exam_id):
132
- """Save exam as text file"""
133
- if not questions or not exam_id:
134
  return None
135
 
136
  filename = f"{exam_id}.txt"
137
- content = f"""EXAMINATION PAPER
138
- {'=' * 50}
139
- Exam ID: {exam_id}
140
- Date: {datetime.now().strftime('%B %d, %Y')}
141
- Time Allowed: 60 minutes
142
-
143
- INSTRUCTIONS:
144
- 1. Write your name and student ID
145
- 2. Answer all questions
146
- 3. No external help allowed
147
-
148
- QUESTIONS:
149
- {'=' * 50}
150
- {questions}
151
-
152
- END OF EXAM
153
- """
154
-
155
  with open(filename, 'w') as f:
156
- f.write(content)
157
-
158
  return filename
159
 
160
  # ============ TAB 2: STUDENT MANAGEMENT ============
161
- def add_student(student_id, first_name, last_name, class_name):
162
- """Add a new student"""
163
- if not student_id or not first_name or not last_name:
164
- return "❌ Please fill all required fields"
165
 
166
  students = load_json(STUDENTS_FILE)
167
 
168
- if student_id in students:
169
- return f"⚠ Student {student_id} already exists"
170
-
171
- student_data = {
172
- "id": student_id,
173
- "first_name": first_name,
174
- "last_name": last_name,
175
- "full_name": f"{first_name} {last_name}",
176
- "class": class_name,
177
- "date_added": datetime.now().isoformat(),
178
- "exams_taken": 0,
179
- "average_score": 0
180
  }
181
 
182
- students[student_id] = student_data
183
  save_json(students, STUDENTS_FILE)
184
-
185
- return f"βœ… Added: {first_name} {last_name} ({student_id})"
186
 
187
- def get_all_students():
188
- """Get all students as DataFrame"""
189
  students = load_json(STUDENTS_FILE)
190
  if not students:
191
- return pd.DataFrame(columns=["ID", "Name", "Class", "Exams", "Avg Score"])
192
 
193
  rows = []
194
  for sid, data in students.items():
195
- rows.append([
196
- sid,
197
- data["full_name"],
198
- data["class"],
199
- data["exams_taken"],
200
- f"{data['average_score']:.1f}%" if data["average_score"] > 0 else "N/A"
201
- ])
202
-
203
- return pd.DataFrame(rows, columns=["ID", "Name", "Class", "Exams", "Avg Score"])
204
 
205
- def delete_student(student_id):
206
- """Delete a student"""
207
  students = load_json(STUDENTS_FILE)
208
 
209
- if student_id in students:
210
- name = students[student_id]["full_name"]
211
- del students[student_id]
212
  save_json(students, STUDENTS_FILE)
213
- return f"βœ… Deleted: {name}"
214
 
215
- return f"❌ Student {student_id} not found"
216
 
217
- # ============ TAB 3: GRADING SYSTEM ============
218
- def record_grade(student_id, exam_id, score):
219
- """Record a student's grade"""
220
- if not student_id or not exam_id or score is None:
221
- return "❌ Please fill all fields", 0, "N/A"
222
 
223
  students = load_json(STUDENTS_FILE)
224
- if student_id not in students:
225
- return f"❌ Student {student_id} not found", 0, "N/A"
226
-
227
- # Calculate letter grade
228
- if score >= 90:
229
- grade = "A"
230
- elif score >= 80:
231
- grade = "B"
232
- elif score >= 70:
233
- grade = "C"
234
- elif score >= 60:
235
- grade = "D"
236
- else:
237
- grade = "F"
238
-
239
- # Update student record
240
- student = students[student_id]
241
- student["exams_taken"] += 1
242
-
243
- # Update average
244
- if student["average_score"] == 0:
245
- student["average_score"] = score
246
  else:
247
- student["average_score"] = (student["average_score"] + score) / 2
248
-
249
  save_json(students, STUDENTS_FILE)
250
 
251
- # Save grade record
252
- grade_id = f"GRADE-{datetime.now().strftime('%Y%m%d%H%M%S')}"
253
  grade_data = {
254
  "id": grade_id,
255
- "student_id": student_id,
256
- "student_name": student["full_name"],
257
- "exam_id": exam_id,
258
  "score": score,
259
  "grade": grade,
260
  "date": datetime.now().isoformat()
@@ -264,368 +174,193 @@ def record_grade(student_id, exam_id, score):
264
  grades[grade_id] = grade_data
265
  save_json(grades, GRADES_FILE)
266
 
267
- return f"βœ… Grade recorded for {student['full_name']}", score, grade
268
 
269
- def get_all_grades():
270
- """Get all grades as DataFrame"""
271
  grades = load_json(GRADES_FILE)
272
  if not grades:
273
  return pd.DataFrame(columns=["Student", "Exam", "Score", "Grade", "Date"])
274
 
275
  rows = []
276
  for gid, data in grades.items():
277
- rows.append([
278
- data["student_name"],
279
- data["exam_id"],
280
- f"{data['score']:.1f}%",
281
- data["grade"],
282
- data["date"][:10]
283
- ])
284
 
285
  return pd.DataFrame(rows, columns=["Student", "Exam", "Score", "Grade", "Date"])
286
 
287
  # ============ TAB 4: ANALYTICS ============
288
- def get_analytics():
289
- """Generate analytics report"""
290
  students = load_json(STUDENTS_FILE)
291
  grades = load_json(GRADES_FILE)
292
 
293
  if not students:
294
- return "πŸ“Š No student data available", pd.DataFrame()
295
 
296
  total_students = len(students)
297
  total_grades = len(grades)
298
 
299
- # Calculate class averages
300
- class_stats = {}
301
- for sid, student in students.items():
302
- class_name = student["class"]
303
- if class_name not in class_stats:
304
- class_stats[class_name] = {
305
- "students": [],
306
- "total_score": 0,
307
- "count": 0
308
- }
309
-
310
- class_stats[class_name]["students"].append(student["full_name"])
311
- if student["average_score"] > 0:
312
- class_stats[class_name]["total_score"] += student["average_score"]
313
- class_stats[class_name]["count"] += 1
314
-
315
- # Create report
316
  report = f"""
317
- πŸ“Š TEACHER ASSISTANT ANALYTICS
318
- {'=' * 50}
319
- πŸ‘₯ Total Students: {total_students}
320
- πŸ“ Exams Graded: {total_grades}
321
-
322
- πŸ“š CLASS PERFORMANCE:
323
  """
324
 
 
325
  rows = []
326
- for class_name, stats in class_stats.items():
327
- if stats["count"] > 0:
328
- average = stats["total_score"] / stats["count"]
329
- report += f"\n 🏫 {class_name}: {average:.1f}% average ({stats['count']} students)"
330
- rows.append([
331
- class_name,
332
- f"{average:.1f}%",
333
- stats["count"],
334
- ", ".join(stats["students"][:3]) + ("..." if len(stats["students"]) > 3 else "")
335
- ])
336
-
337
- df = pd.DataFrame(rows, columns=["Class", "Average", "Students", "Sample Names"])
338
  return report, df
339
 
340
  # ============ TAB 5: SETTINGS ============
341
- def save_settings(school_name, default_questions):
342
- """Save application settings"""
343
- settings = {
344
- "school": school_name,
345
- "default_questions": default_questions,
346
- "last_updated": datetime.now().isoformat()
347
  }
348
 
349
- settings_file = os.path.join(DATA_DIR, "settings.json")
350
- save_json(settings, settings_file)
351
-
352
- return f"βœ… Settings saved for {school_name}"
353
 
354
- def export_backup():
355
- """Export all data as backup"""
356
- backup_data = {
357
  "students": load_json(STUDENTS_FILE),
358
  "exams": load_json(EXAMS_FILE),
359
  "grades": load_json(GRADES_FILE),
360
- "export_date": datetime.now().isoformat()
361
  }
362
 
363
- filename = f"backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
364
  with open(filename, 'w') as f:
365
- json.dump(backup_data, f, indent=2)
366
 
367
- return f"βœ… Backup created: {filename}", filename
368
 
369
- # ============ CREATE INTERFACE ============
370
- def create_interface():
371
- """Create the Gradio interface"""
372
-
373
- # Custom CSS for better appearance
374
- custom_css = """
375
- .gradio-container {
376
- max-width: 1200px !important;
377
- margin: 0 auto !important;
378
- }
379
- .tab-nav {
380
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
381
- padding: 20px;
382
- border-radius: 10px;
383
- margin-bottom: 20px;
384
- color: white;
385
- }
386
- .success {
387
- background-color: #d4edda;
388
- color: #155724;
389
- padding: 10px;
390
- border-radius: 5px;
391
- margin: 10px 0;
392
- }
393
- .warning {
394
- background-color: #fff3cd;
395
- color: #856404;
396
- padding: 10px;
397
- border-radius: 5px;
398
- margin: 10px 0;
399
- }
400
- """
401
 
402
- # Create the app
403
- with gr.Blocks(css=custom_css) as app:
404
 
405
  # Header
406
- gr.HTML("""
407
- <div class="tab-nav">
408
- <h1 style="margin: 0; font-size: 28px;">🍎 Teacher Assistant</h1>
409
- <p style="margin: 5px 0 0 0; font-size: 16px; opacity: 0.9;">
410
- Simplify Your Teaching Workflow β€’ All Data Saved Locally
411
- </p>
412
- </div>
413
- """)
414
 
415
- # Main Tabs
416
  with gr.Tabs():
417
 
418
- # ===== TAB 1: Question Generator =====
419
  with gr.TabItem("πŸ“ Create Exam"):
420
  with gr.Row():
421
- with gr.Column():
422
- gr.Markdown("### Generate Questions")
423
- topic_input = gr.Textbox(label="Topic/Subject", placeholder="e.g., Mathematics, Science, History")
424
- num_q_input = gr.Slider(minimum=1, maximum=20, value=5, label="Number of Questions")
425
- q_type_input = gr.Dropdown(
426
- choices=["Multiple Choice", "True or False", "Identification", "Essay", "Matching Type"],
427
- value="Multiple Choice",
428
- label="Question Type"
429
- )
430
- generate_btn = gr.Button("Generate Questions", variant="primary")
431
-
432
- with gr.Column():
433
- gr.Markdown("### Generated Exam")
434
- questions_output = gr.Textbox(label="Questions", lines=12)
435
- answers_output = gr.Textbox(label="Answer Key", lines=8)
436
- exam_id_output = gr.Textbox(label="Exam ID", interactive=False)
437
-
438
- with gr.Row():
439
- download_btn = gr.Button("πŸ“₯ Download Exam")
440
- clear_btn = gr.Button("πŸ—‘οΈ Clear All")
441
 
442
- # Connect buttons
443
- generate_btn.click(
444
- generate_questions,
445
- [topic_input, num_q_input, q_type_input],
446
- [questions_output, answers_output, exam_id_output]
447
- )
448
 
449
- download_btn.click(
450
- save_exam_file,
451
- [questions_output, exam_id_output],
452
- outputs=gr.File(label="Download")
453
- )
454
 
455
- clear_btn.click(
456
- lambda: ("", 5, "Multiple Choice", "", "", ""),
457
- [topic_input, num_q_input, q_type_input, questions_output, answers_output, exam_id_output]
458
- )
459
 
460
- # ===== TAB 2: Student Management =====
461
- with gr.TabItem("πŸ‘₯ Manage Students"):
462
  with gr.Row():
463
- with gr.Column():
464
- gr.Markdown("### Add New Student")
465
- s_id_input = gr.Textbox(label="Student ID*", placeholder="STU001")
466
- s_first_input = gr.Textbox(label="First Name*", placeholder="John")
467
- s_last_input = gr.Textbox(label="Last Name*", placeholder="Doe")
468
- s_class_input = gr.Textbox(label="Class*", placeholder="Grade 10")
469
- add_s_btn = gr.Button("βž• Add Student", variant="primary")
470
- add_status = gr.Markdown("")
471
-
472
- with gr.Column():
473
- gr.Markdown("### Student Database")
474
- students_table = gr.Dataframe(
475
- headers=["ID", "Name", "Class", "Exams", "Avg Score"],
476
- interactive=False
477
- )
478
- refresh_btn = gr.Button("πŸ”„ Refresh")
479
-
480
- gr.Markdown("### Delete Student")
481
- del_id_input = gr.Textbox(label="Student ID to Delete")
482
- del_btn = gr.Button("πŸ—‘οΈ Delete Student", variant="stop")
483
- del_status = gr.Markdown("")
484
 
485
- # Connect buttons
486
- add_s_btn.click(
487
- add_student,
488
- [s_id_input, s_first_input, s_last_input, s_class_input],
489
- add_status
490
- ).then(
491
- get_all_students,
492
- None,
493
- students_table
494
- )
495
 
496
- refresh_btn.click(
497
- get_all_students,
498
- None,
499
- students_table
500
- )
 
501
 
502
- del_btn.click(
503
- delete_student,
504
- del_id_input,
505
- del_status
506
- ).then(
507
- get_all_students,
508
- None,
509
- students_table
510
- )
511
 
512
- # ===== TAB 3: Grading =====
513
- with gr.TabItem("βœ… Record Grades"):
514
  with gr.Row():
515
- with gr.Column():
516
- gr.Markdown("### Enter Grade")
517
- g_student_id = gr.Textbox(label="Student ID*", placeholder="STU001")
518
- g_exam_id = gr.Textbox(label="Exam ID*", placeholder="EXAM-20241204000000")
519
- g_score = gr.Slider(minimum=0, maximum=100, label="Score (%)")
520
- grade_btn = gr.Button("πŸ“ Record Grade", variant="primary")
521
- grade_status = gr.Markdown("")
522
-
523
- with gr.Row():
524
- score_display = gr.Number(label="Score", interactive=False)
525
- grade_display = gr.Textbox(label="Grade", interactive=False)
526
-
527
- with gr.Column():
528
- gr.Markdown("### Gradebook")
529
- grades_table = gr.Dataframe(
530
- headers=["Student", "Exam", "Score", "Grade", "Date"],
531
- interactive=False
532
- )
533
- refresh_grades_btn = gr.Button("πŸ”„ Refresh Grades")
534
 
535
- # Connect buttons
536
- grade_btn.click(
537
- record_grade,
538
- [g_student_id, g_exam_id, g_score],
539
- [grade_status, score_display, grade_display]
540
- ).then(
541
- get_all_grades,
542
- None,
543
- grades_table
544
- )
545
 
546
- refresh_grades_btn.click(
547
- get_all_grades,
548
- None,
549
- grades_table
550
- )
 
551
 
552
- # ===== TAB 4: Analytics =====
553
  with gr.TabItem("πŸ“Š Analytics"):
554
  with gr.Row():
555
- with gr.Column():
556
- gr.Markdown("### Generate Report")
557
- analytics_btn = gr.Button("πŸ“ˆ Generate Analytics", variant="primary")
558
- report_output = gr.Markdown("")
559
-
560
- with gr.Column():
561
- gr.Markdown("### Class Statistics")
562
- stats_table = gr.Dataframe(
563
- headers=["Class", "Average", "Students", "Sample Names"],
564
- interactive=False
565
- )
566
 
567
- analytics_btn.click(
568
- get_analytics,
569
- None,
570
- [report_output, stats_table]
571
- )
572
 
573
- # ===== TAB 5: Settings =====
574
  with gr.TabItem("βš™οΈ Settings"):
575
  with gr.Row():
576
- with gr.Column():
577
- gr.Markdown("### Application Settings")
578
- school_input = gr.Textbox(label="School Name", value="My School")
579
- default_q_input = gr.Slider(minimum=1, maximum=20, value=10, label="Default Questions")
580
- save_settings_btn = gr.Button("πŸ’Ύ Save Settings", variant="primary")
581
- settings_status = gr.Markdown("")
582
-
583
- with gr.Column():
584
- gr.Markdown("### Data Management")
585
- export_btn = gr.Button("πŸ’Ύ Create Backup", variant="secondary")
586
- export_status = gr.Markdown("")
587
- backup_file = gr.File(label="Download Backup", interactive=False)
588
 
589
- # Connect buttons
590
- save_settings_btn.click(
591
- save_settings,
592
- [school_input, default_q_input],
593
- settings_status
594
- )
595
 
596
- export_btn.click(
597
- export_backup,
598
- None,
599
- [export_status, backup_file]
600
- )
601
-
602
- # Footer
603
- gr.HTML("""
604
- <div style="text-align: center; margin-top: 30px; padding: 20px; border-top: 1px solid #e0e0e0;">
605
- <p style="color: #666; font-size: 14px;">
606
- <b>Teacher Assistant</b> β€’ All data stored locally in your browser β€’
607
- No external dependencies β€’ Simple & Effective
608
- </p>
609
- </div>
610
- """)
611
 
612
  return app
613
 
614
- # ============ MAIN APPLICATION ============
615
  if __name__ == "__main__":
616
- print("=" * 50)
617
- print("πŸš€ Launching Teacher Assistant")
618
- print("=" * 50)
619
- print(f"πŸ“ Students: {len(load_json(STUDENTS_FILE))}")
620
- print(f"πŸ“ Exams: {len(load_json(EXAMS_FILE))}")
621
- print(f"βœ… Grades: {len(load_json(GRADES_FILE))}")
622
- print("=" * 50)
623
-
624
- # Create and launch app
625
- app = create_interface()
626
- app.launch(
627
- debug=True,
628
- share=False,
629
- server_name="0.0.0.0",
630
- server_port=7860
631
- )
 
1
  import gradio as gr
2
  import pandas as pd
 
 
 
3
  import json
4
+ import os
5
  from datetime import datetime
 
6
 
7
+ print("πŸš€ Teacher Assistant - Starting...")
8
 
9
  # ============ DATA STORAGE ============
10
  DATA_DIR = "data"
 
15
  GRADES_FILE = os.path.join(DATA_DIR, "grades.json")
16
 
17
  def load_json(filepath):
 
18
  if os.path.exists(filepath):
19
  try:
20
  with open(filepath, 'r') as f:
 
24
  return {}
25
 
26
  def save_json(data, filepath):
 
27
  with open(filepath, 'w') as f:
28
  json.dump(data, f, indent=2)
29
 
30
+ # Initialize files
31
+ for file in [STUDENTS_FILE, EXAMS_FILE, GRADES_FILE]:
32
+ if not os.path.exists(file):
33
+ save_json({}, file)
 
 
 
34
 
35
  # ============ TAB 1: QUESTION GENERATOR ============
36
+ def create_exam(topic, num_q, q_type):
 
37
  if not topic:
38
+ return "Enter a topic", "", ""
39
 
40
  questions = []
41
  answers = []
42
 
43
+ for i in range(num_q):
44
+ if q_type == "Multiple Choice":
45
+ q = f"Q{i+1}: What is important about {topic}?"
46
+ a = f"A) Option A\nB) Option B\nC) Option C\nD) Option D"
47
+ ans = f"Answer: C"
48
+ elif q_type == "True or False":
49
+ q = f"Q{i+1}: {topic} is important. (True/False)"
50
+ a = ""
51
+ ans = f"Answer: True"
52
+ elif q_type == "Identification":
53
+ q = f"Q{i+1}: Define {topic}."
54
+ a = ""
55
+ ans = f"Answer: [Definition]"
56
+ elif q_type == "Essay":
57
+ q = f"Q{i+1}: Discuss {topic}."
58
+ a = "\n[Essay space]"
59
+ ans = f"Answer: [Essay rubric]"
60
+ else: # Matching Type
61
+ q = f"Q{i+1}: Match terms about {topic}."
62
+ a = "\n1. Term1 β†’ A. Def1\n2. Term2 β†’ B. Def2\n3. Term3 β†’ C. Def3"
63
+ ans = f"Answer: 1-A, 2-B, 3-C"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ questions.append(q + a)
66
+ answers.append(ans)
67
 
68
+ exam_id = f"EXAM-{datetime.now().strftime('%H%M%S')}"
 
69
  exam_data = {
70
  "id": exam_id,
71
  "topic": topic,
 
72
  "questions": questions,
73
  "answers": answers,
74
+ "date": datetime.now().isoformat()
 
75
  }
76
 
77
  exams = load_json(EXAMS_FILE)
 
80
 
81
  return "\n\n".join(questions), "\n\n".join(answers), exam_id
82
 
83
+ def download_exam(questions, exam_id):
84
+ if not questions:
 
85
  return None
86
 
87
  filename = f"{exam_id}.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  with open(filename, 'w') as f:
89
+ f.write(f"EXAM: {exam_id}\n\n{questions}")
 
90
  return filename
91
 
92
  # ============ TAB 2: STUDENT MANAGEMENT ============
93
+ def add_student(s_id, f_name, l_name, s_class):
94
+ if not s_id or not f_name:
95
+ return "Fill required fields"
 
96
 
97
  students = load_json(STUDENTS_FILE)
98
 
99
+ if s_id in students:
100
+ return "Student exists"
101
+
102
+ student = {
103
+ "id": s_id,
104
+ "name": f"{f_name} {l_name}",
105
+ "class": s_class,
106
+ "added": datetime.now().isoformat(),
107
+ "exams": 0,
108
+ "avg": 0
 
 
109
  }
110
 
111
+ students[s_id] = student
112
  save_json(students, STUDENTS_FILE)
113
+ return f"Added {f_name} {l_name}"
 
114
 
115
+ def get_students():
 
116
  students = load_json(STUDENTS_FILE)
117
  if not students:
118
+ return pd.DataFrame(columns=["ID", "Name", "Class", "Exams", "Avg"])
119
 
120
  rows = []
121
  for sid, data in students.items():
122
+ rows.append([sid, data["name"], data["class"], data["exams"], f"{data['avg']:.1f}%"])
123
+
124
+ return pd.DataFrame(rows, columns=["ID", "Name", "Class", "Exams", "Avg"])
 
 
 
 
 
 
125
 
126
+ def remove_student(s_id):
 
127
  students = load_json(STUDENTS_FILE)
128
 
129
+ if s_id in students:
130
+ name = students[s_id]["name"]
131
+ del students[s_id]
132
  save_json(students, STUDENTS_FILE)
133
+ return f"Removed {name}"
134
 
135
+ return "Student not found"
136
 
137
+ # ============ TAB 3: GRADING ============
138
+ def add_grade(s_id, e_id, score):
139
+ if not s_id or not e_id:
140
+ return "Fill all fields", 0, "N/A"
 
141
 
142
  students = load_json(STUDENTS_FILE)
143
+ if s_id not in students:
144
+ return "Student not found", 0, "N/A"
145
+
146
+ # Calculate grade
147
+ if score >= 90: grade = "A"
148
+ elif score >= 80: grade = "B"
149
+ elif score >= 70: grade = "C"
150
+ elif score >= 60: grade = "D"
151
+ else: grade = "F"
152
+
153
+ # Update student
154
+ student = students[s_id]
155
+ student["exams"] += 1
156
+ if student["avg"] == 0:
157
+ student["avg"] = score
 
 
 
 
 
 
 
158
  else:
159
+ student["avg"] = (student["avg"] + score) / 2
 
160
  save_json(students, STUDENTS_FILE)
161
 
162
+ # Save grade
163
+ grade_id = f"GRADE-{datetime.now().strftime('%H%M%S')}"
164
  grade_data = {
165
  "id": grade_id,
166
+ "student": student["name"],
167
+ "exam": e_id,
 
168
  "score": score,
169
  "grade": grade,
170
  "date": datetime.now().isoformat()
 
174
  grades[grade_id] = grade_data
175
  save_json(grades, GRADES_FILE)
176
 
177
+ return f"Grade saved for {student['name']}", score, grade
178
 
179
+ def get_grades():
 
180
  grades = load_json(GRADES_FILE)
181
  if not grades:
182
  return pd.DataFrame(columns=["Student", "Exam", "Score", "Grade", "Date"])
183
 
184
  rows = []
185
  for gid, data in grades.items():
186
+ rows.append([data["student"], data["exam"], f"{data['score']}%", data["grade"], data["date"][:10]])
 
 
 
 
 
 
187
 
188
  return pd.DataFrame(rows, columns=["Student", "Exam", "Score", "Grade", "Date"])
189
 
190
  # ============ TAB 4: ANALYTICS ============
191
+ def get_report():
 
192
  students = load_json(STUDENTS_FILE)
193
  grades = load_json(GRADES_FILE)
194
 
195
  if not students:
196
+ return "No data", pd.DataFrame()
197
 
198
  total_students = len(students)
199
  total_grades = len(grades)
200
 
201
+ # Simple report
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  report = f"""
203
+ Students: {total_students}
204
+ Grades: {total_grades}
 
 
 
 
205
  """
206
 
207
+ # Create simple table
208
  rows = []
209
+ for sid, data in students.items():
210
+ rows.append([sid, data["name"], data["class"], data["exams"], f"{data['avg']:.1f}%"])
211
+
212
+ df = pd.DataFrame(rows, columns=["ID", "Name", "Class", "Exams", "Average"])
 
 
 
 
 
 
 
 
213
  return report, df
214
 
215
  # ============ TAB 5: SETTINGS ============
216
+ def save_setting(school, default_q):
217
+ setting = {
218
+ "school": school,
219
+ "questions": default_q,
220
+ "updated": datetime.now().isoformat()
 
221
  }
222
 
223
+ setting_file = os.path.join(DATA_DIR, "settings.json")
224
+ save_json(setting, setting_file)
225
+ return f"Saved settings for {school}"
 
226
 
227
+ def create_backup():
228
+ backup = {
 
229
  "students": load_json(STUDENTS_FILE),
230
  "exams": load_json(EXAMS_FILE),
231
  "grades": load_json(GRADES_FILE),
232
+ "date": datetime.now().isoformat()
233
  }
234
 
235
+ filename = f"backup_{datetime.now().strftime('%H%M%S')}.json"
236
  with open(filename, 'w') as f:
237
+ json.dump(backup, f, indent=2)
238
 
239
+ return f"Backup created", filename
240
 
241
+ # ============ CREATE APP ============
242
+ def create_app():
243
+ """Create the Gradio app - SIMPLE VERSION"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
+ with gr.Blocks() as app:
 
246
 
247
  # Header
248
+ gr.Markdown("# 🍎 Teacher Assistant")
249
+ gr.Markdown("Simple tool for teachers")
 
 
 
 
 
 
250
 
 
251
  with gr.Tabs():
252
 
253
+ # TAB 1: Create Exam
254
  with gr.TabItem("πŸ“ Create Exam"):
255
  with gr.Row():
256
+ col1 = gr.Column()
257
+ col2 = gr.Column()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
+ with col1:
260
+ topic = gr.Textbox(label="Topic")
261
+ num_q = gr.Slider(1, 20, value=5, label="Questions")
262
+ q_type = gr.Dropdown(["Multiple Choice", "True or False", "Identification", "Essay", "Matching Type"], label="Type")
263
+ btn = gr.Button("Create")
 
264
 
265
+ with col2:
266
+ questions = gr.Textbox(label="Questions", lines=10)
267
+ answers = gr.Textbox(label="Answers", lines=5)
268
+ exam_id = gr.Textbox(label="Exam ID")
269
+ download = gr.Button("Download")
270
 
271
+ btn.click(create_exam, [topic, num_q, q_type], [questions, answers, exam_id])
272
+ download.click(download_exam, [questions, exam_id], gr.File(label="File"))
 
 
273
 
274
+ # TAB 2: Students
275
+ with gr.TabItem("πŸ‘₯ Students"):
276
  with gr.Row():
277
+ col1 = gr.Column()
278
+ col2 = gr.Column()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
+ with col1:
281
+ s_id = gr.Textbox(label="Student ID")
282
+ f_name = gr.Textbox(label="First Name")
283
+ l_name = gr.Textbox(label="Last Name")
284
+ s_class = gr.Textbox(label="Class")
285
+ add_btn = gr.Button("Add Student")
286
+ status = gr.Markdown("")
 
 
 
287
 
288
+ with col2:
289
+ table = gr.Dataframe(headers=["ID", "Name", "Class", "Exams", "Avg"])
290
+ refresh = gr.Button("Refresh")
291
+ del_id = gr.Textbox(label="Delete ID")
292
+ del_btn = gr.Button("Delete")
293
+ del_status = gr.Markdown("")
294
 
295
+ add_btn.click(add_student, [s_id, f_name, l_name, s_class], status).then(get_students, None, table)
296
+ refresh.click(get_students, None, table)
297
+ del_btn.click(remove_student, del_id, del_status).then(get_students, None, table)
 
 
 
 
 
 
298
 
299
+ # TAB 3: Grades
300
+ with gr.TabItem("βœ… Grades"):
301
  with gr.Row():
302
+ col1 = gr.Column()
303
+ col2 = gr.Column()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
+ with col1:
306
+ g_sid = gr.Textbox(label="Student ID")
307
+ g_eid = gr.Textbox(label="Exam ID")
308
+ g_score = gr.Slider(0, 100, label="Score")
309
+ g_btn = gr.Button("Add Grade")
310
+ g_status = gr.Markdown("")
311
+ score_disp = gr.Number(label="Score")
312
+ grade_disp = gr.Textbox(label="Grade")
 
 
313
 
314
+ with col2:
315
+ grades_table = gr.Dataframe(headers=["Student", "Exam", "Score", "Grade", "Date"])
316
+ g_refresh = gr.Button("Refresh")
317
+
318
+ g_btn.click(add_grade, [g_sid, g_eid, g_score], [g_status, score_disp, grade_disp]).then(get_grades, None, grades_table)
319
+ g_refresh.click(get_grades, None, grades_table)
320
 
321
+ # TAB 4: Analytics
322
  with gr.TabItem("πŸ“Š Analytics"):
323
  with gr.Row():
324
+ col1 = gr.Column()
325
+ col2 = gr.Column()
326
+
327
+ with col1:
328
+ report_btn = gr.Button("Generate Report")
329
+ report_text = gr.Markdown("")
 
 
 
 
 
330
 
331
+ with col2:
332
+ report_table = gr.Dataframe(headers=["ID", "Name", "Class", "Exams", "Average"])
333
+
334
+ report_btn.click(get_report, None, [report_text, report_table])
 
335
 
336
+ # TAB 5: Settings
337
  with gr.TabItem("βš™οΈ Settings"):
338
  with gr.Row():
339
+ col1 = gr.Column()
340
+ col2 = gr.Column()
 
 
 
 
 
 
 
 
 
 
341
 
342
+ with col1:
343
+ school_name = gr.Textbox(label="School", value="My School")
344
+ default_q = gr.Slider(1, 20, value=10, label="Default Questions")
345
+ save_btn = gr.Button("Save")
346
+ save_status = gr.Markdown("")
 
347
 
348
+ with col2:
349
+ backup_btn = gr.Button("Create Backup")
350
+ backup_status = gr.Markdown("")
351
+ backup_file = gr.File(label="Download")
352
+
353
+ save_btn.click(save_setting, [school_name, default_q], save_status)
354
+ backup_btn.click(create_backup, None, [backup_status, backup_file])
 
 
 
 
 
 
 
 
355
 
356
  return app
357
 
358
+ # ============ MAIN ============
359
  if __name__ == "__main__":
360
+ print("App starting...")
361
+ print(f"Students: {len(load_json(STUDENTS_FILE))}")
362
+ print(f"Exams: {len(load_json(EXAMS_FILE))}")
363
+ print(f"Grades: {len(load_json(GRADES_FILE))}")
364
+
365
+ app = create_app()
366
+ app.launch(server_name="0.0.0.0", server_port=7860)