Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -424,9 +424,16 @@ def download_questions_file(questions_list, topic, grade_level, subject=None):
|
|
| 424 |
if not questions_list:
|
| 425 |
return None
|
| 426 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 428 |
-
|
| 429 |
-
|
|
|
|
|
|
|
|
|
|
| 430 |
|
| 431 |
content = f"""UNEB EXAM PRACTICE QUESTIONS
|
| 432 |
{'='*50}
|
|
@@ -453,7 +460,7 @@ INSTRUCTIONS:
|
|
| 453 |
Good luck!
|
| 454 |
"""
|
| 455 |
|
| 456 |
-
filepath =
|
| 457 |
os.makedirs("downloads", exist_ok=True)
|
| 458 |
with open(filepath, "w", encoding="utf-8") as f:
|
| 459 |
f.write(content)
|
|
@@ -471,10 +478,16 @@ def download_questions_pdf(questions_list, topic, grade_level, subject=None):
|
|
| 471 |
except Exception:
|
| 472 |
return None
|
| 473 |
|
|
|
|
|
|
|
|
|
|
| 474 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
|
|
|
|
|
|
|
|
|
| 478 |
os.makedirs("downloads", exist_ok=True)
|
| 479 |
|
| 480 |
doc = SimpleDocTemplate(filepath, pagesize=A4, rightMargin=20*mm, leftMargin=20*mm, topMargin=20*mm, bottomMargin=20*mm)
|
|
@@ -506,9 +519,15 @@ def download_feedback_file(feedback_text, topic, grade_level, subject=None):
|
|
| 506 |
if not feedback_text:
|
| 507 |
return None
|
| 508 |
|
|
|
|
|
|
|
|
|
|
| 509 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 510 |
-
|
| 511 |
-
|
|
|
|
|
|
|
|
|
|
| 512 |
|
| 513 |
content = f"""AI CORRECTION & FEEDBACK
|
| 514 |
{'='*50}
|
|
@@ -526,7 +545,7 @@ Review this feedback carefully to understand where you went wrong.
|
|
| 526 |
Practice similar questions to strengthen this topic.
|
| 527 |
"""
|
| 528 |
|
| 529 |
-
filepath =
|
| 530 |
os.makedirs("downloads", exist_ok=True)
|
| 531 |
with open(filepath, "w", encoding="utf-8") as f:
|
| 532 |
f.write(content)
|
|
@@ -642,7 +661,7 @@ with gr.Blocks(title="UNEB Exam Prep - Primary 6 & 7", theme=gr.themes.Soft(), c
|
|
| 642 |
num_questions_input = gr.Slider(minimum=1, maximum=100, step=1, value=20, label="Number of Questions")
|
| 643 |
generate_btn = gr.Button(" Generate Questions", variant="primary", size="lg")
|
| 644 |
|
| 645 |
-
questions_output = gr.
|
| 646 |
value="",
|
| 647 |
elem_classes="question-display"
|
| 648 |
)
|
|
@@ -660,24 +679,25 @@ with gr.Blocks(title="UNEB Exam Prep - Primary 6 & 7", theme=gr.themes.Soft(), c
|
|
| 660 |
# Generate questions handler
|
| 661 |
def generate_and_display(grade, subject, topic, num_questions):
|
| 662 |
questions_list, formatted_text = generate_practice_questions(grade, subject, topic, num_questions=num_questions)
|
| 663 |
-
|
| 664 |
if questions_list is None:
|
| 665 |
-
return "",
|
| 666 |
-
|
| 667 |
session.current_questions = questions_list
|
| 668 |
session.current_grade = grade
|
| 669 |
session.current_topic = topic
|
| 670 |
# Also store subject
|
| 671 |
session.current_subject = subject
|
| 672 |
-
|
| 673 |
-
#
|
| 674 |
-
|
| 675 |
-
|
|
|
|
| 676 |
|
| 677 |
generate_btn.click(
|
| 678 |
fn=generate_and_display,
|
| 679 |
inputs=[grade_input, subject_input, topic_input, num_questions_input],
|
| 680 |
-
outputs=[questions_output,
|
| 681 |
)
|
| 682 |
# Download handler - returns file path for gr.DownloadButton
|
| 683 |
def download_qns():
|
|
|
|
| 424 |
if not questions_list:
|
| 425 |
return None
|
| 426 |
|
| 427 |
+
def sanitize_filename(name: str) -> str:
|
| 428 |
+
# Replace unsafe characters with underscore
|
| 429 |
+
return re.sub(r"[^A-Za-z0-9_.()-]", "_", str(name))
|
| 430 |
+
|
| 431 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 432 |
+
safe_grade = sanitize_filename(grade_level)
|
| 433 |
+
safe_topic = sanitize_filename(topic)
|
| 434 |
+
safe_subject = sanitize_filename(subject) if subject else ""
|
| 435 |
+
subject_tag = f"_{safe_subject}" if safe_subject else ""
|
| 436 |
+
filename = f"questions_{safe_grade}{subject_tag}_{safe_topic}_{timestamp}.txt"
|
| 437 |
|
| 438 |
content = f"""UNEB EXAM PRACTICE QUESTIONS
|
| 439 |
{'='*50}
|
|
|
|
| 460 |
Good luck!
|
| 461 |
"""
|
| 462 |
|
| 463 |
+
filepath = os.path.join("downloads", filename)
|
| 464 |
os.makedirs("downloads", exist_ok=True)
|
| 465 |
with open(filepath, "w", encoding="utf-8") as f:
|
| 466 |
f.write(content)
|
|
|
|
| 478 |
except Exception:
|
| 479 |
return None
|
| 480 |
|
| 481 |
+
def sanitize_filename(name: str) -> str:
|
| 482 |
+
return re.sub(r"[^A-Za-z0-9_.()-]", "_", str(name))
|
| 483 |
+
|
| 484 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 485 |
+
safe_grade = sanitize_filename(grade_level)
|
| 486 |
+
safe_topic = sanitize_filename(topic)
|
| 487 |
+
safe_subject = sanitize_filename(subject) if subject else ""
|
| 488 |
+
subject_tag = f"_{safe_subject}" if safe_subject else ""
|
| 489 |
+
filename = f"questions_{safe_grade}{subject_tag}_{safe_topic}_{timestamp}.pdf"
|
| 490 |
+
filepath = os.path.join("downloads", filename)
|
| 491 |
os.makedirs("downloads", exist_ok=True)
|
| 492 |
|
| 493 |
doc = SimpleDocTemplate(filepath, pagesize=A4, rightMargin=20*mm, leftMargin=20*mm, topMargin=20*mm, bottomMargin=20*mm)
|
|
|
|
| 519 |
if not feedback_text:
|
| 520 |
return None
|
| 521 |
|
| 522 |
+
def sanitize_filename(name: str) -> str:
|
| 523 |
+
return re.sub(r"[^A-Za-z0-9_.()-]", "_", str(name))
|
| 524 |
+
|
| 525 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 526 |
+
safe_grade = sanitize_filename(grade_level)
|
| 527 |
+
safe_topic = sanitize_filename(topic)
|
| 528 |
+
safe_subject = sanitize_filename(subject) if subject else ""
|
| 529 |
+
subject_tag = f"_{safe_subject}" if safe_subject else ""
|
| 530 |
+
filename = f"feedback_{safe_grade}{subject_tag}_{safe_topic}_{timestamp}.txt"
|
| 531 |
|
| 532 |
content = f"""AI CORRECTION & FEEDBACK
|
| 533 |
{'='*50}
|
|
|
|
| 545 |
Practice similar questions to strengthen this topic.
|
| 546 |
"""
|
| 547 |
|
| 548 |
+
filepath = os.path.join("downloads", filename)
|
| 549 |
os.makedirs("downloads", exist_ok=True)
|
| 550 |
with open(filepath, "w", encoding="utf-8") as f:
|
| 551 |
f.write(content)
|
|
|
|
| 661 |
num_questions_input = gr.Slider(minimum=1, maximum=100, step=1, value=20, label="Number of Questions")
|
| 662 |
generate_btn = gr.Button(" Generate Questions", variant="primary", size="lg")
|
| 663 |
|
| 664 |
+
questions_output = gr.HTML(
|
| 665 |
value="",
|
| 666 |
elem_classes="question-display"
|
| 667 |
)
|
|
|
|
| 679 |
# Generate questions handler
|
| 680 |
def generate_and_display(grade, subject, topic, num_questions):
|
| 681 |
questions_list, formatted_text = generate_practice_questions(grade, subject, topic, num_questions=num_questions)
|
| 682 |
+
|
| 683 |
if questions_list is None:
|
| 684 |
+
return "", questions_state.value, " Generation failed"
|
| 685 |
+
|
| 686 |
session.current_questions = questions_list
|
| 687 |
session.current_grade = grade
|
| 688 |
session.current_topic = topic
|
| 689 |
# Also store subject
|
| 690 |
session.current_subject = subject
|
| 691 |
+
|
| 692 |
+
# Build accessible HTML list for better rendering on iPad/Safari
|
| 693 |
+
items_html = "".join([f"<li>{q.split('.',1)[1].strip() if '.' in q else q}</li>" for q in questions_list])
|
| 694 |
+
html = f"<div><ol style='margin:0 0 0 1.2rem;padding:0'>{items_html}</ol></div>"
|
| 695 |
+
return html, questions_list, f" Generated {len(questions_list)} {subject} questions on {topic}"
|
| 696 |
|
| 697 |
generate_btn.click(
|
| 698 |
fn=generate_and_display,
|
| 699 |
inputs=[grade_input, subject_input, topic_input, num_questions_input],
|
| 700 |
+
outputs=[questions_output, questions_state, status_output]
|
| 701 |
)
|
| 702 |
# Download handler - returns file path for gr.DownloadButton
|
| 703 |
def download_qns():
|