import gradio as gr import sqlite3 from utils import get_device_id, authenticate_user, get_user_role from database import ( init_db, add_student, get_sessions, toggle_session, get_open_session, has_marked_attendance, mark_attendance, get_attendance_summary ) # Initialize the database init_db() # Global user state current_user = {"email": None, "role": None, "device_id": None, "class_id": None} # Custom theme for the app theme = gr.themes.Soft( primary_hue="indigo", secondary_hue="blue", neutral_hue="slate", radius_size=gr.themes.sizes.radius_md, ).set( button_primary_background_fill="*primary_500", button_primary_background_fill_hover="*primary_600", button_primary_text_color="white", button_secondary_background_fill="*neutral_100", button_secondary_background_fill_hover="*neutral_200", button_secondary_text_color="*neutral_800", block_label_background_fill="*neutral_50", block_title_text_weight="600", ) # --- Login Logic --- def login(email, password): if not email or not password: return "Please fill in all fields.", gr.update(visible=False), gr.update(visible=True) device_id = get_device_id() success, message = authenticate_user(email, password, device_id) if success: current_user["email"] = email current_user["role"] = get_user_role(email) current_user["device_id"] = device_id # Get class_id and name conn = sqlite3.connect("attendance.db") cursor = conn.cursor() cursor.execute("SELECT class_id, name FROM users WHERE email=?", (email,)) row = cursor.fetchone() current_user["class_id"] = row[0] if row else None user_name = row[1] if row else email conn.close() # Set visibility based on user role if current_user["role"] == "teacher": return ( f"👋 Welcome, {user_name}!", gr.update(visible=False), gr.update(visible=True), gr.update(selected="teacher_tab" if current_user["role"] == "teacher" else "student_tab") ) else: return ( f"👋 Welcome, {user_name}!", gr.update(visible=False), gr.update(visible=True), gr.update(selected="student_tab") ) else: return message, gr.update(visible=True), gr.update(visible=False), gr.update() def logout(): # Reset user data current_user["email"] = None current_user["role"] = None current_user["class_id"] = None current_user["device_id"] = None # Show login form, hide dashboard return gr.update(visible=True), gr.update(visible=False) # --- Teacher Dashboard Functions --- def teacher_dashboard_view(): if current_user["role"] != "teacher": return "Access denied. You are not a teacher." sessions = get_sessions(current_user["class_id"]) # Format sessions as a list of dictionaries for the DataFrame session_data = [ {"ID": s[0], "Date & Time": s[1], "Status": "đŸŸĸ Open" if bool(s[2]) else "🔴 Closed"} for s in sessions ] if not session_data: session_data = [{"ID": "-", "Date & Time": "-", "Status": "-"}] return session_data def handle_open_session(): if current_user["role"] != "teacher": return "Access denied.", teacher_dashboard_view() result = toggle_session(current_user["class_id"], True) return f"✅ {result}", teacher_dashboard_view() def handle_close_session(): if current_user["role"] != "teacher": return "Access denied.", teacher_dashboard_view() result = toggle_session(current_user["class_id"], False) return f"❌ {result}", teacher_dashboard_view() def handle_add_student(name, email, password): if not name or not email or not password: return "Please fill in all fields." if current_user["role"] != "teacher": return "Access denied. You are not authorized to add students." result = add_student(name, email, password, current_user["class_id"]) # Clear the form on success if "successfully" in result: return f"✅ {result}", "", "", "" else: return f"❌ {result}", gr.update(), gr.update(), gr.update() # --- Student Dashboard Functions --- def handle_mark_attendance(): if current_user["role"] != "student": return "Access denied. You are not a student." session_id = get_open_session(current_user["class_id"]) if not session_id: return "❌ No open attendance session right now.", get_student_attendance_data() if has_marked_attendance(current_user["email"], session_id): return "â„šī¸ You have already marked attendance for this session.", get_student_attendance_data() result = mark_attendance(current_user["email"], session_id) return f"✅ {result}", get_student_attendance_data() def get_student_attendance_data(): if current_user["role"] != "student": return [{"Date": "-", "Class": "-"}] conn = sqlite3.connect("attendance.db") cursor = conn.cursor() cursor.execute(""" SELECT s.date, s.class_id FROM attendance_logs a JOIN sessions s ON a.session_id = s.id WHERE a.student_email=? ORDER BY s.date DESC LIMIT 10 """, (current_user["email"],)) records = cursor.fetchall() conn.close() if not records: return [{"Date": "-", "Class": "-"}] return [{"Date": row[0], "Class": row[1]} for row in records] def get_student_stats(): if current_user["role"] != "student" or not current_user["email"]: return "0", "0%" conn = sqlite3.connect("attendance.db") cursor = conn.cursor() # Get total sessions for the student's class cursor.execute("SELECT COUNT(*) FROM sessions WHERE class_id=?", (current_user["class_id"],)) total_sessions = cursor.fetchone()[0] # Get student's attendance count cursor.execute(""" SELECT COUNT(*) FROM attendance_logs a JOIN sessions s ON a.session_id = s.id WHERE a.student_email=? AND s.class_id=? """, (current_user["email"], current_user["class_id"])) attended_sessions = cursor.fetchone()[0] conn.close() attendance_percentage = "0%" if total_sessions > 0: attendance_percentage = f"{(attended_sessions / total_sessions) * 100:.1f}%" return str(attended_sessions), attendance_percentage # --- UI Layout --- with gr.Blocks(theme=theme, title="Smart Attendance System") as demo: gr.Markdown( """ # 📱 Smart Attendance System ### Modern attendance tracking for educational institutions """ ) # Login Section login_container = gr.Column(visible=True) with login_container: with gr.Group(): gr.Markdown("### Log in to your account") with gr.Row(): with gr.Column(scale=2): email = gr.Textbox( label="Email Address", placeholder="Enter your email", scale=2 ) password = gr.Textbox( label="Password", placeholder="Enter your password", type="password", scale=2 ) login_msg = gr.Textbox( label="", interactive=False, visible=True ) with gr.Column(scale=1): gr.Markdown("### Welcome!") gr.Markdown("Sign in to access the attendance system. Teachers can manage sessions and students, while students can mark their attendance.") with gr.Row(): login_btn = gr.Button( "🔐 Login", variant="primary", scale=1 ) # Dashboard Section dashboard_container = gr.Column(visible=False) with dashboard_container: with gr.Row(): user_greeting = gr.Textbox( value="Welcome!", label="", interactive=False ) logout_btn = gr.Button( "đŸšĒ Logout", variant="secondary", scale=0 ) # Tabs for different interfaces with gr.Tabs(selected=0) as dashboard_tabs: # Teacher Dashboard Tab with gr.TabItem("👨‍đŸĢ Teacher Dashboard", id="teacher_tab"): with gr.Row(): with gr.Column(scale=2): gr.Markdown("### Class Sessions") with gr.Row(): open_btn = gr.Button("✅ Open Session", variant="primary") close_btn = gr.Button("❌ Close Session", variant="secondary") session_status = gr.Textbox(label="", interactive=False) gr.Markdown("### Session History") refresh_btn = gr.Button("🔄 Refresh Sessions", variant="secondary") session_output = gr.DataFrame( headers=["ID", "Date & Time", "Status"], datatype=["number", "str", "str"], label="All Sessions" ) with gr.Column(scale=1): gr.Markdown("### Add New Student") with gr.Group(): student_name = gr.Textbox( label="Student Name", placeholder="Full name" ) student_email = gr.Textbox( label="Student Email", placeholder="student@example.com" ) student_pass = gr.Textbox( label="Password", placeholder="Create password", type="password" ) add_btn = gr.Button("➕ Add Student", variant="primary") add_status = gr.Textbox(label="", interactive=False) # Student Dashboard Tab with gr.TabItem("👨‍🎓 Student Dashboard", id="student_tab"): with gr.Row(): with gr.Column(scale=1): gr.Markdown("### Quick Actions") mark_btn = gr.Button("📍 Mark Attendance", size="lg", variant="primary") mark_status = gr.Textbox(label="Status", interactive=False) gr.Markdown("### Your Statistics") with gr.Row(): with gr.Column(): total_attended = gr.Textbox(label="Sessions Attended", interactive=False) with gr.Column(): attendance_rate = gr.Textbox(label="Attendance Rate", interactive=False) with gr.Column(scale=2): gr.Markdown("### Attendance History") attendance_table = gr.DataFrame( headers=["Date", "Class"], datatype=["str", "str"], label="Your Recent Attendance", interactive=False ) # Event Bindings login_btn.click( fn=login, inputs=[email, password], outputs=[user_greeting, login_container, dashboard_container, dashboard_tabs] ) logout_btn.click( fn=logout, outputs=[login_container, dashboard_container] ) # Teacher functions refresh_btn.click( fn=teacher_dashboard_view, outputs=session_output ) open_btn.click( fn=handle_open_session, outputs=[session_status, session_output] ) close_btn.click( fn=handle_close_session, outputs=[session_status, session_output] ) add_btn.click( fn=handle_add_student, inputs=[student_name, student_email, student_pass], outputs=[add_status, student_name, student_email, student_pass] ) # Student functions mark_btn.click( fn=handle_mark_attendance, outputs=[mark_status, attendance_table] ) # Dynamic loading handlers dashboard_tabs.select( fn=lambda tab: teacher_dashboard_view() if tab == "teacher_tab" else get_student_attendance_data(), inputs=dashboard_tabs, outputs=session_output if dashboard_tabs.selected == "teacher_tab" else attendance_table ) dashboard_tabs.select( fn=lambda tab: get_student_stats() if tab == "student_tab" else (None, None), inputs=dashboard_tabs, outputs=[total_attended, attendance_rate] ) # Footer gr.Markdown( """ --- ### Smart Attendance - A modern attendance tracking solution Version 2.0 | Š 2025 """ ) # Launch the app if __name__ == "__main__": demo.launch(share=True)