| """ |
| Hostel Management System β Streamlit Web App |
| PDC Lab Project | UCP BSAI |
| Ch Hamza Younas (L1F23BAI0089) & Muhammad Abdullah (L1F23BSAI0063) |
| """ |
|
|
| import json |
| import time |
| from datetime import date |
|
|
| import pandas as pd |
| import plotly.express as px |
| import plotly.graph_objects as go |
| import streamlit as st |
|
|
| from hostel_data import ( |
| STATUS_MAP, |
| add_announcement, |
| add_gate_log, |
| add_student, |
| assign_room, |
| bulk_mark_attendance, |
| export_summary, |
| find_room, |
| find_student, |
| fresh_state, |
| get_activity_feed, |
| get_analytics, |
| get_student_attendance_history, |
| get_student_gate_logs, |
| mark_attendance, |
| match_student, |
| pay_label, |
| record_payment, |
| room_status, |
| ) |
| from pdc_benchmark import CHART_CATEGORIES, run_all_benchmarks |
| from theme import ( |
| activity_feed, |
| feature_grid, |
| hero, |
| inject_theme, |
| metrics_row, |
| page_footer, |
| room_grid, |
| sidebar_brand, |
| ) |
|
|
| st.set_page_config( |
| page_title="Hostel MS | PDC Lab", |
| page_icon="π ", |
| layout="wide", |
| initial_sidebar_state="expanded", |
| ) |
| inject_theme() |
|
|
|
|
| def init_session(): |
| defaults = { |
| "db": fresh_state(), |
| "user": None, |
| "role": None, |
| "student_idx": -1, |
| } |
| for key, val in defaults.items(): |
| if key not in st.session_state: |
| st.session_state[key] = val |
|
|
|
|
| def logout(): |
| st.session_state.user = None |
| st.session_state.role = None |
| st.session_state.student_idx = -1 |
|
|
|
|
| def active_students(db): |
| return [s for s in db["students"] if s["active"]] |
|
|
|
|
| def active_rooms(db): |
| return [r for r in db["rooms"] if r["active"]] |
|
|
|
|
| def student_name(db, idx): |
| return db["students"][idx]["name"] |
|
|
|
|
| def room_number(db, room_id): |
| for r in db["rooms"]: |
| if r["id"] == room_id: |
| return r["number"] |
| return "None" |
|
|
|
|
| |
|
|
| def page_login(): |
| hero("π Hostel Management System", "Smart hostel operations Β· PDC parallel computing demo") |
| feature_grid([ |
| ("π", "Live Dashboard", "Occupancy, fees, complaints & analytics at a glance"), |
| ("π", "Role Portals", "Separate admin & student workspaces with secure login"), |
| ("β‘", "PDC Benchmarks", "Real OpenMP & POSIX Threads speedup tests in C"), |
| ("π½οΈ", "Full Operations", "Rooms, mess, gate logs, attendance & announcements"), |
| ]) |
| st.markdown("<br>", unsafe_allow_html=True) |
|
|
| c1, c2, c3 = st.columns([1, 2, 1]) |
| with c2: |
| st.markdown('<div class="login-shell">', unsafe_allow_html=True) |
| st.markdown( |
| """ |
| <div class="login-header"> |
| <div class="icon">π </div> |
| <h2>Welcome Back</h2> |
| <p>Sign in to your hostel portal</p> |
| </div> |
| """, |
| unsafe_allow_html=True, |
| ) |
| tab_a, tab_s = st.tabs(["π Admin / Warden", "π Student"]) |
|
|
| with tab_a: |
| user = st.text_input("Username", value="admin", key="adm_user") |
| pwd = st.text_input("Password", type="password", value="admin123", key="adm_pwd") |
| if st.button("Login as Admin", type="primary", use_container_width=True): |
| if user == "admin" and pwd == "admin123": |
| st.session_state.user = "Warden" |
| st.session_state.role = "admin" |
| st.success("Welcome, Warden!") |
| time.sleep(0.3) |
| st.rerun() |
| else: |
| st.error("Invalid admin credentials") |
|
|
| with tab_s: |
| roll = st.text_input("Roll No", value="UCP-BSAI-1001", key="stu_roll") |
| pwd2 = st.text_input("Password", type="password", value="student123", key="stu_pwd") |
| if st.button("Login as Student", type="primary", use_container_width=True): |
| idx = find_student(st.session_state.db["students"], roll) |
| if idx >= 0 and st.session_state.db["students"][idx]["password"] == pwd2: |
| st.session_state.user = st.session_state.db["students"][idx]["name"] |
| st.session_state.role = "student" |
| st.session_state.student_idx = idx |
| st.success(f"Welcome, {st.session_state.user}!") |
| time.sleep(0.3) |
| st.rerun() |
| else: |
| st.error("Invalid roll number or password") |
|
|
| st.caption("Demo Β· admin/admin123 Β· UCP-BSAI-1001/student123") |
| st.markdown("</div>", unsafe_allow_html=True) |
|
|
| page_footer() |
|
|
|
|
| |
|
|
| def admin_dashboard(): |
| db = st.session_state.db |
| stats = get_analytics(db) |
| hero("Admin Control Center", f"Welcome back, {st.session_state.user}", badge="Live") |
|
|
| metrics_row([ |
| (stats["students_total"], "Active Students", f"{stats['present_today']} present today"), |
| (f"{stats['occupancy_pct']}%", "Occupancy", f"{stats['vacant']} vacant rooms"), |
| (stats["defaulters"], "Fee Defaulters", f"PKR {stats['total_dues']:,.0f} pending"), |
| (len(db["complaints"]), "Open Tickets", "Track in Mess & Complaints"), |
| ]) |
|
|
| c1, c2, c3 = st.columns(3) |
| with c1: |
| fig = px.pie( |
| names=["Vacant", "Partial", "Full"], |
| values=[stats["vacant"], stats["partial"], stats["full"]], |
| title="Room Availability", |
| color_discrete_sequence=["#10B981", "#F59E0B", "#6366F1"], |
| hole=0.45, |
| ) |
| fig.update_layout(template="plotly_dark", height=320, margin=dict(t=40, b=20)) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with c2: |
| fig = go.Figure(go.Bar( |
| x=["Rent Clear", "Mess Clear", "Defaulters"], |
| y=[stats["rent_clear"], stats["mess_clear"], stats["defaulters"]], |
| marker_color=["#6366F1", "#A855F7", "#EF4444"], |
| )) |
| fig.update_layout(template="plotly_dark", title="Fee Status", height=320, margin=dict(t=40, b=20)) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with c3: |
| cc = stats["complaint_counts"] |
| fig = px.bar( |
| x=list(cc.keys()), y=list(cc.values()), |
| title="Complaint Pipeline", color=list(cc.values()), |
| color_continuous_scale="Viridis", |
| ) |
| fig.update_layout(template="plotly_dark", height=320, showlegend=False, margin=dict(t=40, b=20)) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| st.markdown("#### π’ Latest Announcements") |
| for a in db["announcements"][:3]: |
| pri = a["priority"].upper() |
| st.info(f"**{a['title']}** ({pri}) β {a['body']}") |
|
|
| c1, c2 = st.columns([1, 1]) |
| with c1: |
| st.markdown('<p class="panel-title">π Live Activity Feed</p>', unsafe_allow_html=True) |
| feed = get_activity_feed(db) |
| if feed: |
| activity_feed(feed) |
| else: |
| st.caption("No recent activity") |
|
|
| with c2: |
| st.markdown('<p class="panel-title">ποΈ Room Occupancy Grid</p>', unsafe_allow_html=True) |
| tiles = [{ |
| "number": r["number"], "occupied": r["occupied"], |
| "capacity": r["capacity"], "status": room_status(r), |
| } for r in active_rooms(db)[:10]] |
| room_grid(tiles) |
|
|
| page_footer() |
|
|
|
|
| def admin_rooms(): |
| hero("Room Management", "Inventory, capacity & rent configuration") |
| db = st.session_state.db |
| tab1, tab2, tab3 = st.tabs(["π All Rooms", "β Add Room", "ποΈ Delete"]) |
|
|
| with tab1: |
| rows = [{ |
| "Room": r["number"], "Floor": r["floor"], "Type": r["type"], |
| "AC": "Yes" if r["ac"] else "No", "Occ/Cap": f"{r['occupied']}/{r['capacity']}", |
| "Status": room_status(r), "Rent (PKR)": r["rent"], |
| } for r in active_rooms(db)] |
| st.dataframe(pd.DataFrame(rows), use_container_width=True, hide_index=True) |
| st.download_button("β¬οΈ Export CSV", pd.DataFrame(rows).to_csv(index=False), |
| "rooms.csv", "text/csv", use_container_width=True) |
|
|
| with tab2: |
| with st.form("add_room"): |
| num = st.text_input("Room Number", placeholder="R-116") |
| floor = st.number_input("Floor", 1, 10, 1) |
| rtype = st.selectbox("Type", ["2-seater", "4-seater"]) |
| ac = st.checkbox("AC Room") |
| cap = st.number_input("Capacity", 1, 8, 2) |
| rent = st.number_input("Monthly Rent (PKR)", 5000, 50000, 12000) |
| if st.form_submit_button("Add Room", type="primary"): |
| if find_room(db["rooms"], num) >= 0: |
| st.error(f"Room {num} already exists") |
| else: |
| db["rooms"].append({ |
| "id": len(db["rooms"]) + 1, "number": num, "floor": floor, |
| "type": rtype, "ac": ac, "capacity": cap, "occupied": 0, |
| "rent": rent, "active": True, |
| }) |
| st.success(f"Room {num} added") |
| st.rerun() |
|
|
| with tab3: |
| num = st.text_input("Room to delete") |
| if st.button("Delete Room", type="primary"): |
| ri = find_room(db["rooms"], num) |
| if ri < 0: |
| st.error("Room not found") |
| elif any(s["active"] and s["room_id"] == db["rooms"][ri]["id"] for s in db["students"]): |
| st.error("Cannot delete β students assigned") |
| else: |
| db["rooms"][ri]["active"] = False |
| st.success(f"Room {num} removed") |
| st.rerun() |
|
|
|
|
| def admin_students(): |
| hero("Student Management", "Enrollment, search, room assignment") |
| db = st.session_state.db |
| tab1, tab2, tab3, tab4 = st.tabs(["π Roster", "β Enroll", "π Search", "π Assign Room"]) |
|
|
| with tab1: |
| rows = [] |
| for s in active_students(db): |
| status = "CLEAR" if s["rent_paid"] and s["mess_paid"] else "DUE" |
| rows.append({ |
| "Name": s["name"], "Roll": s["roll"], "Room": room_number(db, s["room_id"]), |
| "Phone": s["phone"], "Rent": pay_label(s["rent_paid"]), |
| "Mess": pay_label(s["mess_paid"]), "Status": status, |
| }) |
| st.dataframe(pd.DataFrame(rows), use_container_width=True, hide_index=True) |
| st.download_button("β¬οΈ Export CSV", pd.DataFrame(rows).to_csv(index=False), |
| "students.csv", "text/csv") |
|
|
| with tab2: |
| with st.form("enroll"): |
| name = st.text_input("Full Name") |
| roll = st.text_input("Roll Number", placeholder="UCP-BSAI-1011") |
| phone = st.text_input("Phone", placeholder="0300-1234567") |
| room = st.text_input("Room Number", placeholder="R-116") |
| if st.form_submit_button("Enroll Student", type="primary"): |
| ok, msg = add_student(db, name, roll, phone, room) |
| st.success(msg) if ok else st.error(msg) |
| if ok: |
| st.rerun() |
|
|
| with tab3: |
| key = st.text_input("Search by name or roll") |
| if key: |
| t0 = time.perf_counter() |
| results = [s for s in db["students"] if match_student(s, key)] |
| elapsed = time.perf_counter() - t0 |
| st.dataframe(pd.DataFrame([{ |
| "Name": s["name"], "Roll": s["roll"], "Room": room_number(db, s["room_id"]), |
| "Rent": pay_label(s["rent_paid"]), "Mess": pay_label(s["mess_paid"]), |
| } for s in results]), use_container_width=True, hide_index=True) |
| st.caption(f"Found {len(results)} in {elapsed:.6f}s") |
|
|
| with tab4: |
| roll = st.text_input("Student Roll", key="assign_roll") |
| room = st.text_input("Target Room", key="assign_room") |
| if st.button("Assign Room", type="primary"): |
| ok, msg = assign_room(db, roll, room) |
| st.success(msg) if ok else st.error(msg) |
| if ok: |
| st.rerun() |
|
|
|
|
| def admin_fees(): |
| hero("Fee & Finance", "Challans, payments & defaulter tracking") |
| db = st.session_state.db |
| tab1, tab2, tab3, tab4 = st.tabs(["π Challans", "π³ Record Payment", "β οΈ Defaulters", "π History"]) |
|
|
| with tab1: |
| rows, total = [], 0 |
| for s in active_students(db): |
| t = s["rent_due"] + s["mess_due"] + s["utility_due"] |
| total += t |
| rows.append({"Name": s["name"], "Rent": s["rent_due"], "Mess": s["mess_due"], |
| "Utility": s["utility_due"], "Total": t}) |
| st.dataframe(pd.DataFrame(rows), use_container_width=True, hide_index=True) |
| st.metric("Grand Total Monthly Dues", f"PKR {total:,.0f}") |
|
|
| with tab2: |
| roll = st.text_input("Student Roll No") |
| idx = find_student(db["students"], roll) if roll else -1 |
| if idx >= 0: |
| s = db["students"][idx] |
| st.info(f"**{s['name']}** Β· Rent: {pay_label(s['rent_paid'])} Β· Mess: {pay_label(s['mess_paid'])}") |
| if s["rent_paid"] and s["mess_paid"]: |
| st.success("All payments clear") |
| else: |
| opts = [] |
| if not s["rent_paid"]: |
| opts.append("Rent") |
| if not s["mess_paid"]: |
| opts.append("Mess") |
| choice = st.multiselect("Record payment for", opts) |
| if st.button("Save Payment", type="primary"): |
| record_payment(db, idx, "Rent" in choice, "Mess" in choice) |
| st.success("Payment recorded") |
| st.rerun() |
|
|
| with tab3: |
| rows = [{"Name": s["name"], "Roll": s["roll"], |
| "Rent": pay_label(s["rent_paid"]), "Mess": pay_label(s["mess_paid"])} |
| for s in active_students(db) if not s["rent_paid"] or not s["mess_paid"]] |
| st.dataframe(pd.DataFrame(rows) if rows else pd.DataFrame([{"Status": "No defaulters"}]), |
| use_container_width=True, hide_index=True) |
|
|
| with tab4: |
| hist = [] |
| for p in db["payment_history"]: |
| hist.append({ |
| "Student": student_name(db, p["student_idx"]), |
| "Type": p["type"], "Amount": p["amount"], "Date": p["date"], |
| }) |
| st.dataframe(pd.DataFrame(hist), use_container_width=True, hide_index=True) |
|
|
|
|
| def admin_mess_complaints(): |
| hero("Mess & Complaints", "Weekly menu & maintenance tickets") |
| db = st.session_state.db |
| tab1, tab2, tab3 = st.tabs(["π½οΈ Mess Menu", "π Complaints", "π’ Announcements"]) |
|
|
| with tab1: |
| cols = st.columns(2) |
| for i, m in enumerate(db["mess"]): |
| with cols[i % 2]: |
| with st.expander(f"π
{m['day']}", expanded=i < 2): |
| st.markdown(f"π
**Breakfast:** {m['breakfast']}") |
| st.markdown(f"βοΈ **Lunch:** {m['lunch']}") |
| st.markdown(f"π **Dinner:** {m['dinner']}") |
|
|
| with tab2: |
| filter_st = st.selectbox("Filter by status", ["All"] + list(STATUS_MAP.values())) |
| for c in db["complaints"]: |
| if filter_st != "All" and STATUS_MAP[c["status"]] != filter_st: |
| continue |
| name = student_name(db, c["student_idx"]) |
| st.markdown(f"**#{c['id']}** Β· {name} Β· `{STATUS_MAP[c['status']]}` Β· _{c.get('created', '')}_") |
| st.write(c["text"]) |
| new_st = st.selectbox("Status", [0, 1, 2], format_func=lambda x: STATUS_MAP[x], |
| key=f"st_{c['id']}") |
| if st.button("Update", key=f"btn_{c['id']}"): |
| c["status"] = new_st |
| st.success("Updated") |
| st.rerun() |
|
|
| with tab3: |
| with st.form("ann"): |
| title = st.text_input("Title") |
| body = st.text_area("Message") |
| pri = st.selectbox("Priority", ["low", "medium", "high"]) |
| if st.form_submit_button("Publish", type="primary") and title and body: |
| add_announcement(db, title, body, pri) |
| st.success("Announcement published") |
| st.rerun() |
| for a in db["announcements"]: |
| st.info(f"**{a['title']}** ({a['priority']}) β {a['date']}\n\n{a['body']}") |
|
|
|
|
| def admin_gate_attendance(): |
| hero("Gate & Attendance", "Entry/exit logs & daily roll call") |
| db = st.session_state.db |
| tab1, tab2 = st.tabs(["πͺ Gate Logs", "β
Attendance"]) |
|
|
| with tab1: |
| c1, c2 = st.columns(2) |
| with c1: |
| rolls = {s["roll"]: i for s in active_students(db)} |
| roll = st.selectbox("Student", list(rolls.keys())) |
| log_type = st.selectbox("Action", ["IN", "OUT"]) |
| if st.button("Log Entry", type="primary"): |
| add_gate_log(db, rolls[roll], log_type) |
| st.success(f"{log_type} logged for {student_name(db, rolls[roll])}") |
| st.rerun() |
| with c2: |
| logs = [{ |
| "Student": student_name(db, g["student_idx"]), |
| "Type": g["type"], "Time": g["time"], |
| } for g in reversed(db["gate_logs"][-15:])] |
| st.dataframe(pd.DataFrame(logs), use_container_width=True, hide_index=True) |
|
|
| with tab2: |
| today = str(date.today()) |
| bc1, bc2, bc3 = st.columns(3) |
| if bc1.button("β
Mark All Present", use_container_width=True): |
| bulk_mark_attendance(db, True) |
| st.success("All students marked present") |
| st.rerun() |
| if bc2.button("β Mark All Absent", use_container_width=True): |
| bulk_mark_attendance(db, False) |
| st.warning("All students marked absent") |
| st.rerun() |
| if bc3.button("π Attendance Summary", use_container_width=True): |
| present = sum(1 for a in db["attendance"] |
| if a["date"] == today and a["present"]) |
| st.info(f"Present today: **{present}** / {len(active_students(db))}") |
|
|
| st.divider() |
| for i, s in enumerate(active_students(db)): |
| rec = next((a for a in db["attendance"] |
| if a["student_idx"] == i and a["date"] == today), None) |
| present = rec["present"] if rec else False |
| c1, c2, c3 = st.columns([3, 1, 1]) |
| c1.write(f"**{s['name']}** ({s['roll']})") |
| if c2.button("Present", key=f"p_{i}"): |
| mark_attendance(db, i, True) |
| st.rerun() |
| if c3.button("Absent", key=f"a_{i}"): |
| mark_attendance(db, i, False) |
| st.rerun() |
| st.caption("Present" if present else "Absent") |
|
|
|
|
| def admin_analytics(): |
| hero("Analytics Hub", "Deep insights across hostel operations") |
| db = st.session_state.db |
| stats = get_analytics(db) |
|
|
| c1, c2 = st.columns(2) |
| with c1: |
| students = active_students(db) |
| df = pd.DataFrame({ |
| "Category": ["Paid", "Due"], |
| "Count": [ |
| sum(1 for s in students if s["rent_paid"]), |
| sum(1 for s in students if not s["rent_paid"]), |
| ], |
| }) |
| fig = px.pie(df, names="Category", values="Count", title="Rent Collection", |
| color="Category", color_discrete_map={"Paid": "#6366F1", "Due": "#EF4444"}, hole=0.4) |
| fig.update_layout(template="plotly_dark", height=350) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with c2: |
| floors = {} |
| for r in active_rooms(db): |
| floors[r["floor"]] = floors.get(r["floor"], 0) + r["occupied"] |
| fig = px.bar(x=list(floors.keys()), y=list(floors.values()), title="Occupancy by Floor", |
| labels={"x": "Floor", "y": "Students"}, color_discrete_sequence=["#A855F7"]) |
| fig.update_layout(template="plotly_dark", height=350) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| st.markdown("#### Summary") |
| st.json({ |
| "occupancy_rate": f"{stats['occupancy_pct']}%", |
| "defaulters": stats["defaulters"], |
| "pending_dues_pkr": stats["total_dues"], |
| "complaints": stats["complaint_counts"], |
| "gate_logs_today": len(db["gate_logs"]), |
| }) |
| page_footer() |
|
|
|
|
| def admin_reports(): |
| hero("Reports & Export", "Download operational snapshots", badge="Export") |
| db = st.session_state.db |
| summary = export_summary(db) |
|
|
| c1, c2 = st.columns(2) |
| with c1: |
| st.markdown("#### π¦ Summary Report") |
| st.json(summary) |
| st.download_button( |
| "β¬οΈ Download JSON Report", |
| json.dumps(summary, indent=2), |
| "hostel_report.json", |
| "application/json", |
| use_container_width=True, |
| ) |
| with c2: |
| students = active_students(db) |
| df = pd.DataFrame([{ |
| "Name": s["name"], "Roll": s["roll"], |
| "Room": room_number(db, s["room_id"]), |
| "Rent": pay_label(s["rent_paid"]), "Mess": pay_label(s["mess_paid"]), |
| } for s in students]) |
| st.download_button( |
| "β¬οΈ Download Student Roster CSV", |
| df.to_csv(index=False), |
| "roster.csv", |
| "text/csv", |
| use_container_width=True, |
| ) |
| rooms_df = pd.DataFrame([{ |
| "Room": r["number"], "Floor": r["floor"], "Status": room_status(r), |
| "Occupied": r["occupied"], "Capacity": r["capacity"], |
| } for r in active_rooms(db)]) |
| st.download_button( |
| "β¬οΈ Download Room Inventory CSV", |
| rooms_df.to_csv(index=False), |
| "rooms.csv", |
| "text/csv", |
| use_container_width=True, |
| ) |
|
|
| if st.button("π Reset Demo Data", type="secondary"): |
| st.session_state.db = fresh_state() |
| st.success("Demo data restored") |
| st.rerun() |
| page_footer() |
|
|
|
|
| def page_help(): |
| hero("Help & About", "Project documentation & credentials") |
| st.markdown(""" |
| ### About |
| **Hostel Management System** β PDC Lab Project for UCP BSAI. |
| Built by **Ch Hamza Younas** & **Muhammad Abdullah** under **Ma'am Khadija**. |
| |
| ### Demo Logins |
| | Role | Username / Roll | Password | |
| |------|-----------------|----------| |
| | Admin | `admin` | `admin123` | |
| | Student | `UCP-BSAI-1001` | `student123` | |
| |
| ### PDC Benchmark |
| Runs compiled **search_bench** with **Sequential**, **OpenMP**, and **POSIX Threads** in C. |
| |
| ### Links |
| - [Hugging Face Space](https://huggingface.co/spaces/Hamzavelous/Hostel-Management_System) |
| - [GitHub Repository](https://github.com/Hamzavelous/Hostel-Management_System) |
| """) |
| page_footer() |
|
|
|
|
| def page_pdc(): |
| hero("β‘ PDC Performance Test", "Sequential Β· OpenMP Β· POSIX Threads", badge="C Backend") |
| st.markdown( |
| "Runs the compiled **search_bench** binary with real OpenMP and pthread parallelism β " |
| "same engine as the console C application." |
| ) |
| keyword = st.text_input("Search keyword", value="Ali") |
|
|
| if st.button("Run Benchmark", type="primary", use_container_width=True): |
| try: |
| with st.spinner("Executing C parallel benchmarks..."): |
| rows, kw = run_all_benchmarks(None, keyword) |
| except FileNotFoundError as exc: |
| st.error(str(exc)) |
| return |
| except RuntimeError as exc: |
| st.error(f"Benchmark failed: {exc}") |
| return |
|
|
| df = pd.DataFrame(rows) |
| df["Time (ms)"] = (df["Time (s)"] * 1000).round(2) |
| st.dataframe( |
| df[["Method", "Workers", "Fee (s)", "Search (s)", "Time (s)", "Time (ms)", "Found", "Speedup"]], |
| use_container_width=True, hide_index=True, |
| ) |
|
|
| chart_df = df.set_index("Label").reindex(CHART_CATEGORIES).reset_index() |
| fig = px.bar(chart_df, x="Label", y="Speedup", color="Method", text="Speedup", |
| title="Speedup vs Sequential Baseline", |
| color_discrete_map={ |
| "Sequential": "#6366F1", "OpenMP": "#A855F7", "POSIX Threads": "#10B981", |
| }) |
| fig.update_traces(texttemplate="%{text:.2f}x", textposition="outside") |
| fig.update_layout(template="plotly_dark", height=420, xaxis_title="") |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| c1, c2 = st.columns(2) |
| with c1: |
| fig2 = px.line(chart_df, x="Label", y="Time (ms)", markers=True, title="Execution Time (ms)") |
| fig2.update_layout(template="plotly_dark", height=300) |
| st.plotly_chart(fig2, use_container_width=True) |
| with c2: |
| st.info( |
| f"**Workload:** Fee calculation + student search\n\n" |
| f"**Keyword:** \"{kw}\" matched **{rows[0]['Found']}** student(s)\n\n" |
| f"**Best speedup:** {max(r['Speedup'] for r in rows):.2f}x" |
| ) |
|
|
|
|
| |
|
|
| def student_profile(): |
| s = st.session_state.db["students"][st.session_state.student_idx] |
| db = st.session_state.db |
| hero("My Profile", s["name"]) |
| c1, c2 = st.columns(2) |
| with c1: |
| st.markdown("#### Personal") |
| st.write(f"**Roll:** {s['roll']}") |
| st.write(f"**Phone:** {s['phone']}") |
| st.write(f"**Emergency:** {s['emergency']}") |
| st.write(f"**Last Payment:** {s['last_pay_date']}") |
| with c2: |
| st.markdown("#### Room") |
| if s["room_id"] > 0: |
| r = next(x for x in db["rooms"] if x["id"] == s["room_id"]) |
| st.write(f"**Room:** {r['number']} Β· Floor {r['floor']}") |
| st.write(f"**Type:** {r['type']} Β· AC: {'Yes' if r['ac'] else 'No'}") |
| st.write(f"**Monthly Rent:** PKR {r['rent']:,.0f}") |
| else: |
| st.warning("No room assigned") |
|
|
|
|
| def student_fees_page(): |
| s = st.session_state.db["students"][st.session_state.student_idx] |
| total = s["rent_due"] + s["mess_due"] + s["utility_due"] |
| hero("My Fees", "Payment status") |
| metrics_row([ |
| (f"PKR {s['rent_due']:,.0f}", "Rent", pay_label(s["rent_paid"])), |
| (f"PKR {s['mess_due']:,.0f}", "Mess", pay_label(s["mess_paid"])), |
| (f"PKR {s['utility_due']:,.0f}", "Utility", "Fixed"), |
| (f"PKR {total:,.0f}", "Total Due", "Monthly"), |
| ]) |
| if s["rent_paid"] and s["mess_paid"]: |
| st.success("β
All payments clear β thank you!") |
| else: |
| st.warning("β οΈ Pending dues β please visit the warden office") |
|
|
|
|
| def student_complaint_page(): |
| idx = st.session_state.student_idx |
| db = st.session_state.db |
| hero("Complaint Box", "Report maintenance issues") |
| text = st.text_area("Describe your issue", placeholder="Wi-Fi, plumbing, electricity...") |
| if st.button("Submit Ticket", type="primary") and text.strip(): |
| cid = len(db["complaints"]) + 1 |
| db["complaints"].append({ |
| "id": cid, "student_idx": idx, "text": text.strip(), |
| "status": 0, "created": str(date.today()), |
| }) |
| st.success(f"Ticket #{cid} submitted") |
| st.rerun() |
| st.markdown("#### My Tickets") |
| for c in db["complaints"]: |
| if c["student_idx"] == idx: |
| st.info(f"#{c['id']}: {c['text']} β **{STATUS_MAP[c['status']]}**") |
|
|
|
|
| def student_mess_page(): |
| hero("Mess Menu", "Weekly dining schedule") |
| for m in st.session_state.db["mess"]: |
| with st.expander(f"π
{m['day']}"): |
| st.write(f"π
**Breakfast:** {m['breakfast']}") |
| st.write(f"βοΈ **Lunch:** {m['lunch']}") |
| st.write(f"π **Dinner:** {m['dinner']}") |
|
|
|
|
| def student_announcements(): |
| hero("Announcements", "Notices from hostel administration") |
| for a in st.session_state.db["announcements"]: |
| icon = "π΄" if a["priority"] == "high" else "π‘" if a["priority"] == "medium" else "π’" |
| st.markdown(f"{icon} **{a['title']}** Β· _{a['date']}_") |
| st.write(a["body"]) |
| st.divider() |
| page_footer() |
|
|
|
|
| def student_activity(): |
| idx = st.session_state.student_idx |
| db = st.session_state.db |
| hero("My Activity", "Gate logs & attendance history") |
| tab1, tab2 = st.tabs(["πͺ Gate Logs", "β
Attendance"]) |
|
|
| with tab1: |
| logs = get_student_gate_logs(db, idx) |
| if logs: |
| st.dataframe(pd.DataFrame([{ |
| "Action": g["type"], "Time": g["time"], |
| } for g in reversed(logs)]), use_container_width=True, hide_index=True) |
| else: |
| st.info("No gate logs yet") |
|
|
| with tab2: |
| hist = get_student_attendance_history(db, idx) |
| if hist: |
| st.dataframe(pd.DataFrame([{ |
| "Date": a["date"], |
| "Status": "Present" if a["present"] else "Absent", |
| } for a in reversed(hist)]), use_container_width=True, hide_index=True) |
| else: |
| st.info("No attendance records yet") |
| page_footer() |
|
|
|
|
| |
|
|
| ADMIN_PAGES = { |
| "π Dashboard": admin_dashboard, |
| "ποΈ Rooms": admin_rooms, |
| "π Students": admin_students, |
| "π° Fees": admin_fees, |
| "π½οΈ Mess & Complaints": admin_mess_complaints, |
| "πͺ Gate & Attendance": admin_gate_attendance, |
| "π Analytics": admin_analytics, |
| "π Reports": admin_reports, |
| "β‘ PDC Performance": page_pdc, |
| "β Help": page_help, |
| } |
|
|
| STUDENT_PAGES = { |
| "π€ My Profile": student_profile, |
| "π° My Fees": student_fees_page, |
| "π Complaints": student_complaint_page, |
| "π½οΈ Mess Menu": student_mess_page, |
| "π’ Announcements": student_announcements, |
| "π My Activity": student_activity, |
| "β‘ PDC Performance": page_pdc, |
| "β Help": page_help, |
| } |
|
|
|
|
| def main(): |
| init_session() |
| if st.session_state.role is None: |
| page_login() |
| return |
|
|
| with st.sidebar: |
| sidebar_brand() |
| st.markdown(f"### π€ {st.session_state.user}") |
| st.caption(f"Role Β· **{st.session_state.role.title()}**") |
| if st.session_state.role == "student": |
| pending = sum( |
| 1 for a in st.session_state.db["announcements"] if a["priority"] == "high" |
| ) |
| st.caption(f"π’ {pending} high-priority notices") |
| elif st.session_state.role == "admin": |
| stats = get_analytics(st.session_state.db) |
| st.caption(f"β οΈ {stats['defaulters']} fee defaulters Β· {stats['vacant']} vacant rooms") |
| st.divider() |
|
|
| pages = ADMIN_PAGES if st.session_state.role == "admin" else STUDENT_PAGES |
| choice = st.radio("Navigate", list(pages.keys()), label_visibility="collapsed") |
|
|
| st.divider() |
| if st.button("πͺ Logout", use_container_width=True, type="secondary"): |
| logout() |
| st.rerun() |
|
|
| st.divider() |
| st.caption("PDC Lab Β· UCP BSAI") |
| st.caption("Hamza Younas & Abdullah") |
| st.caption("[HF Space](https://huggingface.co/spaces/Hamzavelous/Hostel-Management_System)") |
|
|
| pages[choice]() |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|