Spaces:
Sleeping
Sleeping
Fix NameError in navigation logic
Browse files
app.py
CHANGED
|
@@ -793,23 +793,28 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 793 |
# Display student name
|
| 794 |
student_name_display = gr.Markdown("")
|
| 795 |
|
| 796 |
-
#
|
| 797 |
-
with gr.
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
["Carpal bones arrangement"],
|
| 814 |
["Layers of the scalp"],
|
| 815 |
["Anatomy of the heart chambers"],
|
|
@@ -841,17 +846,17 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 841 |
with gr.Column(scale=1):
|
| 842 |
image_output = gr.Image(label="🖼️ Anatomy Diagram", type="pil")
|
| 843 |
|
| 844 |
-
# VIVA MODE
|
| 845 |
-
|
| 846 |
-
|
| 847 |
|
| 848 |
-
|
| 849 |
-
|
| 850 |
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
|
| 856 |
with gr.Column(scale=2):
|
| 857 |
current_question_display = gr.Markdown("### Question will appear here")
|
|
@@ -870,132 +875,115 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 870 |
|
| 871 |
feedback_display = gr.Markdown("Feedback will appear here after you submit your answer")
|
| 872 |
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
|
| 884 |
-
|
| 885 |
-
|
| 886 |
|
| 887 |
-
|
| 888 |
-
|
| 889 |
|
| 890 |
-
|
| 891 |
-
|
| 892 |
|
| 893 |
-
|
| 894 |
-
|
| 895 |
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
|
| 927 |
|
| 928 |
-
|
| 929 |
-
|
| 930 |
|
| 931 |
-
|
| 932 |
|
| 933 |
-
|
| 934 |
-
|
| 935 |
|
| 936 |
-
|
| 937 |
-
|
| 938 |
-
# Hidden state to store current page topic for VIVA
|
| 939 |
-
current_book_topic = gr.State("")
|
| 940 |
|
| 941 |
-
|
| 942 |
-
|
| 943 |
-
inputs=[page_dropdown, book_images_state, page_captions_state, page_texts_state],
|
| 944 |
-
outputs=[selected_page_image, analysis_output, current_book_topic, start_viva_book_btn]
|
| 945 |
-
)
|
| 946 |
|
| 947 |
-
|
| 948 |
-
|
| 949 |
-
|
| 950 |
-
|
| 951 |
-
outputs=[
|
| 952 |
-
viva_container, viva_status, viva_image,
|
| 953 |
-
current_question_display, hint_display,
|
| 954 |
-
student_answer, feedback_display, submit_answer_btn,
|
| 955 |
-
viva_questions_state,
|
| 956 |
-
question_audio, viva_greeting, student_name_state
|
| 957 |
-
]
|
| 958 |
-
).then(
|
| 959 |
-
fn=lambda: gr.update(selected=1), # Switch to VIVA tab
|
| 960 |
-
outputs=[tabs]
|
| 961 |
-
).then(
|
| 962 |
-
fn=lambda: 0,
|
| 963 |
-
outputs=[current_question_idx]
|
| 964 |
)
|
|
|
|
|
|
|
| 965 |
|
| 966 |
-
|
| 967 |
-
|
| 968 |
-
|
| 969 |
-
|
| 970 |
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
|
| 981 |
-
|
| 982 |
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
|
| 986 |
|
| 987 |
-
|
| 988 |
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
|
| 992 |
|
| 993 |
-
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
|
| 999 |
|
| 1000 |
# Registration Modal Popup (shown on first load)
|
| 1001 |
with gr.Column(visible=True, elem_id="registration_modal") as registration_modal:
|
|
@@ -1035,6 +1023,58 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 1035 |
|
| 1036 |
# Event Handlers
|
| 1037 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1038 |
# Welcome Screen Handler (now for modal)
|
| 1039 |
def handle_modal_submit(name, medical_school, year):
|
| 1040 |
"""Handle registration modal submission."""
|
|
@@ -1099,8 +1139,11 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 1099 |
student_name_state # Return student name (unchanged)
|
| 1100 |
]
|
| 1101 |
).then(
|
| 1102 |
-
fn=lambda: gr.update(
|
| 1103 |
-
outputs=[
|
|
|
|
|
|
|
|
|
|
| 1104 |
).then(
|
| 1105 |
fn=lambda: gr.update(value="🎯 Start VIVA Training", interactive=True), # Reset button
|
| 1106 |
outputs=[start_viva_btn]
|
|
@@ -1180,6 +1223,28 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
|
|
| 1180 |
outputs=[admin_stats, students_table]
|
| 1181 |
)
|
| 1182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1183 |
if __name__ == "__main__":
|
| 1184 |
# Check if API keys are configured
|
| 1185 |
if not SERPAPI_KEY or SERPAPI_KEY == "your_serpapi_key_here":
|
|
|
|
| 793 |
# Display student name
|
| 794 |
student_name_display = gr.Markdown("")
|
| 795 |
|
| 796 |
+
# Custom Navigation Bar
|
| 797 |
+
with gr.Row(elem_id="nav_bar"):
|
| 798 |
+
nav_learning_btn = gr.Button("📚 Learning Mode", variant="primary", scale=1)
|
| 799 |
+
nav_viva_btn = gr.Button("🎯 VIVA Training Mode", variant="secondary", scale=1)
|
| 800 |
+
nav_book_btn = gr.Button("📖 Book Learning Mode", variant="secondary", scale=1)
|
| 801 |
+
nav_admin_btn = gr.Button("🔐 Admin Panel", variant="secondary", scale=1)
|
| 802 |
+
|
| 803 |
+
# LEARNING MODE COLUMN
|
| 804 |
+
with gr.Column(visible=True, elem_id="learning_col") as learning_col:
|
| 805 |
+
# Search and examples at the top
|
| 806 |
+
with gr.Row():
|
| 807 |
+
query_input = gr.Textbox(
|
| 808 |
+
label="Ask an Anatomy Question",
|
| 809 |
+
placeholder="e.g., Show me the Circle of Willis",
|
| 810 |
+
lines=2
|
| 811 |
+
)
|
| 812 |
+
|
| 813 |
+
# Examples
|
| 814 |
+
gr.Examples(
|
| 815 |
+
examples=[
|
| 816 |
+
["Show me the Circle of Willis"],
|
| 817 |
+
["Brachial plexus anatomy"],
|
| 818 |
["Carpal bones arrangement"],
|
| 819 |
["Layers of the scalp"],
|
| 820 |
["Anatomy of the heart chambers"],
|
|
|
|
| 846 |
with gr.Column(scale=1):
|
| 847 |
image_output = gr.Image(label="🖼️ Anatomy Diagram", type="pil")
|
| 848 |
|
| 849 |
+
# VIVA MODE COLUMN
|
| 850 |
+
with gr.Column(visible=False, elem_id="viva_col") as viva_col:
|
| 851 |
+
viva_status = gr.Markdown("Click 'Start VIVA Training' from Learning Mode after studying a topic!")
|
| 852 |
|
| 853 |
+
# Additional greeting component (initially hidden)
|
| 854 |
+
viva_greeting = gr.Markdown("", visible=False)
|
| 855 |
|
| 856 |
+
with gr.Column(visible=False) as viva_container:
|
| 857 |
+
with gr.Row():
|
| 858 |
+
with gr.Column(scale=1):
|
| 859 |
+
viva_image = gr.Image(label="Reference Image", type="pil", interactive=False)
|
| 860 |
|
| 861 |
with gr.Column(scale=2):
|
| 862 |
current_question_display = gr.Markdown("### Question will appear here")
|
|
|
|
| 875 |
|
| 876 |
feedback_display = gr.Markdown("Feedback will appear here after you submit your answer")
|
| 877 |
|
| 878 |
+
# BOOK LEARNING MODE COLUMN
|
| 879 |
+
with gr.Column(visible=False, elem_id="book_col") as book_col:
|
| 880 |
+
# Upload PDF
|
| 881 |
+
pdf_upload = gr.File(label="Upload Anatomy Textbook (PDF)", file_types=[".pdf"], type="binary")
|
| 882 |
+
upload_status = gr.Markdown()
|
| 883 |
|
| 884 |
+
# State to hold extracted images, captions, and text
|
| 885 |
+
book_images_state = gr.State([])
|
| 886 |
+
page_captions_state = gr.State([])
|
| 887 |
+
page_texts_state = gr.State([])
|
| 888 |
|
| 889 |
+
# Dropdown to select a page after processing
|
| 890 |
+
page_dropdown = gr.Dropdown(label="Select Page", choices=[], interactive=False)
|
| 891 |
|
| 892 |
+
# Display selected page image
|
| 893 |
+
selected_page_image = gr.Image(label="Selected Page", type="pil")
|
| 894 |
|
| 895 |
+
# Analysis output
|
| 896 |
+
analysis_output = gr.Markdown(label="Page Analysis")
|
| 897 |
|
| 898 |
+
# Button to start VIVA from this page
|
| 899 |
+
start_viva_book_btn = gr.Button("🎯 Start VIVA Training from this Page", variant="primary", visible=False)
|
| 900 |
|
| 901 |
+
# Process upload
|
| 902 |
+
def handle_book_upload(pdf_bytes):
|
| 903 |
+
extracted_data, status_msg = process_uploaded_book(pdf_bytes)
|
| 904 |
+
if not extracted_data:
|
| 905 |
+
# No data extracted
|
| 906 |
+
return [], status_msg, [], [], gr.update(choices=[], interactive=False), None, ""
|
| 907 |
|
| 908 |
+
# Separate images, captions, and text
|
| 909 |
+
img_list = [item[0] for item in extracted_data]
|
| 910 |
+
caps = [item[1] for item in extracted_data]
|
| 911 |
+
texts = [item[2] for item in extracted_data]
|
| 912 |
|
| 913 |
+
# Update dropdown with captions and enable it
|
| 914 |
+
dropdown_update = gr.update(choices=caps, interactive=True)
|
| 915 |
+
return img_list, status_msg, caps, texts, dropdown_update, None, ""
|
| 916 |
|
| 917 |
+
pdf_upload.upload(
|
| 918 |
+
fn=handle_book_upload,
|
| 919 |
+
inputs=[pdf_upload],
|
| 920 |
+
outputs=[book_images_state, upload_status, page_captions_state, page_texts_state, page_dropdown, selected_page_image, analysis_output]
|
| 921 |
+
)
|
| 922 |
|
| 923 |
+
# When a page is selected, show image and analysis
|
| 924 |
+
def show_page_analysis(selected_caption, images, captions, texts):
|
| 925 |
+
if not selected_caption:
|
| 926 |
+
return None, ""
|
| 927 |
+
# Find index
|
| 928 |
+
try:
|
| 929 |
+
idx = captions.index(selected_caption)
|
| 930 |
+
except ValueError:
|
| 931 |
+
return None, ""
|
| 932 |
|
| 933 |
+
img = images[idx]
|
| 934 |
+
text = texts[idx] if idx < len(texts) else ""
|
| 935 |
|
| 936 |
+
analysis = analyze_book_image(img, selected_caption, text)
|
| 937 |
|
| 938 |
+
# Construct a topic string for VIVA
|
| 939 |
+
viva_topic = f"Anatomy of {selected_caption} (from textbook)"
|
| 940 |
|
| 941 |
+
return img, analysis, viva_topic, gr.update(visible=True)
|
|
|
|
|
|
|
|
|
|
| 942 |
|
| 943 |
+
# Hidden state to store current page topic for VIVA
|
| 944 |
+
current_book_topic = gr.State("")
|
|
|
|
|
|
|
|
|
|
| 945 |
|
| 946 |
+
page_dropdown.change(
|
| 947 |
+
fn=show_page_analysis,
|
| 948 |
+
inputs=[page_dropdown, book_images_state, page_captions_state, page_texts_state],
|
| 949 |
+
outputs=[selected_page_image, analysis_output, current_book_topic, start_viva_book_btn]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 950 |
)
|
| 951 |
+
|
| 952 |
+
# Start VIVA from Book Mode handler moved to end of file to resolve NameError
|
| 953 |
|
| 954 |
+
# ADMIN PANEL COLUMN
|
| 955 |
+
with gr.Column(visible=False, elem_id="admin_col") as admin_col:
|
| 956 |
+
gr.Markdown("## Admin Panel - Student Database")
|
| 957 |
+
gr.Markdown("Enter the admin password to view registered students.")
|
| 958 |
|
| 959 |
+
# Password input
|
| 960 |
+
with gr.Row():
|
| 961 |
+
admin_password_input = gr.Textbox(
|
| 962 |
+
label="Admin Password",
|
| 963 |
+
placeholder="Enter admin password",
|
| 964 |
+
type="password",
|
| 965 |
+
scale=2
|
| 966 |
+
)
|
| 967 |
+
admin_login_btn = gr.Button("🔓 Login", variant="primary", scale=1)
|
| 968 |
|
| 969 |
+
admin_status = gr.Markdown("")
|
| 970 |
|
| 971 |
+
# Admin content (hidden until authenticated)
|
| 972 |
+
with gr.Column(visible=False) as admin_content:
|
| 973 |
+
gr.Markdown("### 📊 Registered Students")
|
| 974 |
|
| 975 |
+
admin_stats = gr.Markdown("")
|
| 976 |
|
| 977 |
+
with gr.Row():
|
| 978 |
+
refresh_btn = gr.Button("🔄 Refresh Data", variant="secondary")
|
| 979 |
+
logout_btn = gr.Button("🚪 Logout", variant="secondary")
|
| 980 |
|
| 981 |
+
students_table = gr.Dataframe(
|
| 982 |
+
headers=["ID", "Name", "Medical School", "Year", "Registration Date"],
|
| 983 |
+
label="Students Database",
|
| 984 |
+
interactive=False,
|
| 985 |
+
wrap=True
|
| 986 |
+
)
|
| 987 |
|
| 988 |
# Registration Modal Popup (shown on first load)
|
| 989 |
with gr.Column(visible=True, elem_id="registration_modal") as registration_modal:
|
|
|
|
| 1023 |
|
| 1024 |
# Event Handlers
|
| 1025 |
|
| 1026 |
+
# Navigation Logic
|
| 1027 |
+
def navigate(nav_target):
|
| 1028 |
+
"""Handle navigation between views."""
|
| 1029 |
+
# Returns: learning_col, viva_col, book_col, admin_col
|
| 1030 |
+
# Also returns button variants: learning_btn, viva_btn, book_btn, admin_btn
|
| 1031 |
+
|
| 1032 |
+
if nav_target == "learning":
|
| 1033 |
+
return (
|
| 1034 |
+
gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
|
| 1035 |
+
gr.update(variant="primary"), gr.update(variant="secondary"), gr.update(variant="secondary"), gr.update(variant="secondary")
|
| 1036 |
+
)
|
| 1037 |
+
elif nav_target == "viva":
|
| 1038 |
+
return (
|
| 1039 |
+
gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False),
|
| 1040 |
+
gr.update(variant="secondary"), gr.update(variant="primary"), gr.update(variant="secondary"), gr.update(variant="secondary")
|
| 1041 |
+
)
|
| 1042 |
+
elif nav_target == "book":
|
| 1043 |
+
return (
|
| 1044 |
+
gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),
|
| 1045 |
+
gr.update(variant="secondary"), gr.update(variant="secondary"), gr.update(variant="primary"), gr.update(variant="secondary")
|
| 1046 |
+
)
|
| 1047 |
+
elif nav_target == "admin":
|
| 1048 |
+
return (
|
| 1049 |
+
gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True),
|
| 1050 |
+
gr.update(variant="secondary"), gr.update(variant="secondary"), gr.update(variant="secondary"), gr.update(variant="primary")
|
| 1051 |
+
)
|
| 1052 |
+
return (
|
| 1053 |
+
gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
|
| 1054 |
+
gr.update(variant="primary"), gr.update(variant="secondary"), gr.update(variant="secondary"), gr.update(variant="secondary")
|
| 1055 |
+
)
|
| 1056 |
+
|
| 1057 |
+
# Bind Navigation Buttons
|
| 1058 |
+
nav_learning_btn.click(
|
| 1059 |
+
fn=lambda: navigate("learning"),
|
| 1060 |
+
outputs=[learning_col, viva_col, book_col, admin_col, nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1061 |
+
)
|
| 1062 |
+
|
| 1063 |
+
nav_viva_btn.click(
|
| 1064 |
+
fn=lambda: navigate("viva"),
|
| 1065 |
+
outputs=[learning_col, viva_col, book_col, admin_col, nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1066 |
+
)
|
| 1067 |
+
|
| 1068 |
+
nav_book_btn.click(
|
| 1069 |
+
fn=lambda: navigate("book"),
|
| 1070 |
+
outputs=[learning_col, viva_col, book_col, admin_col, nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1071 |
+
)
|
| 1072 |
+
|
| 1073 |
+
nav_admin_btn.click(
|
| 1074 |
+
fn=lambda: navigate("admin"),
|
| 1075 |
+
outputs=[learning_col, viva_col, book_col, admin_col, nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1076 |
+
)
|
| 1077 |
+
|
| 1078 |
# Welcome Screen Handler (now for modal)
|
| 1079 |
def handle_modal_submit(name, medical_school, year):
|
| 1080 |
"""Handle registration modal submission."""
|
|
|
|
| 1139 |
student_name_state # Return student name (unchanged)
|
| 1140 |
]
|
| 1141 |
).then(
|
| 1142 |
+
fn=lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)),
|
| 1143 |
+
outputs=[learning_col, viva_col, book_col, admin_col]
|
| 1144 |
+
).then(
|
| 1145 |
+
fn=lambda: (gr.update(variant="secondary"), gr.update(variant="primary"), gr.update(variant="secondary"), gr.update(variant="secondary")),
|
| 1146 |
+
outputs=[nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1147 |
).then(
|
| 1148 |
fn=lambda: gr.update(value="🎯 Start VIVA Training", interactive=True), # Reset button
|
| 1149 |
outputs=[start_viva_btn]
|
|
|
|
| 1223 |
outputs=[admin_stats, students_table]
|
| 1224 |
)
|
| 1225 |
|
| 1226 |
+
# Start VIVA from Book Mode - Use pre-collected name (Moved here to ensure all columns are defined)
|
| 1227 |
+
start_viva_book_btn.click(
|
| 1228 |
+
fn=lambda name, topic, image: start_viva_with_name(name, topic, image),
|
| 1229 |
+
inputs=[student_name_state, current_book_topic, selected_page_image],
|
| 1230 |
+
outputs=[
|
| 1231 |
+
viva_container, viva_status, viva_image,
|
| 1232 |
+
current_question_display, hint_display,
|
| 1233 |
+
student_answer, feedback_display, submit_answer_btn,
|
| 1234 |
+
viva_questions_state,
|
| 1235 |
+
question_audio, viva_greeting, student_name_state
|
| 1236 |
+
]
|
| 1237 |
+
).then(
|
| 1238 |
+
fn=lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)),
|
| 1239 |
+
outputs=[learning_col, viva_col, book_col, admin_col]
|
| 1240 |
+
).then(
|
| 1241 |
+
fn=lambda: (gr.update(variant="secondary"), gr.update(variant="primary"), gr.update(variant="secondary"), gr.update(variant="secondary")),
|
| 1242 |
+
outputs=[nav_learning_btn, nav_viva_btn, nav_book_btn, nav_admin_btn]
|
| 1243 |
+
).then(
|
| 1244 |
+
fn=lambda: 0,
|
| 1245 |
+
outputs=[current_question_idx]
|
| 1246 |
+
)
|
| 1247 |
+
|
| 1248 |
if __name__ == "__main__":
|
| 1249 |
# Check if API keys are configured
|
| 1250 |
if not SERPAPI_KEY or SERPAPI_KEY == "your_serpapi_key_here":
|