"""
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"
# โโ LOGIN โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
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("
", unsafe_allow_html=True)
c1, c2, c3 = st.columns([1, 2, 1])
with c2:
st.markdown('
Sign in to your hostel portal
๐ Live Activity Feed
', unsafe_allow_html=True) feed = get_activity_feed(db) if feed: activity_feed(feed) else: st.caption("No recent activity") with c2: st.markdown('๐๏ธ Room Occupancy Grid
', 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" ) # โโ STUDENT โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 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() # โโ ROUTER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 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()