import streamlit as st import pandas as pd import os from io import BytesIO from datetime import datetime import plotly.express as px st.set_page_config(page_title="Specialization Allocation System", layout="wide") st.markdown(""" """, unsafe_allow_html=True) BASE_DIR = os.path.dirname(__file__) excel_path = os.path.join(BASE_DIR, "For Specialisation.xlsx") csv_file = os.path.join(BASE_DIR, "submissions.csv") logo_path = os.path.join(BASE_DIR, "logo.png") if not os.path.exists(excel_path): st.error("Excel file not found. Please upload For Specialisation.xlsx") st.stop() df_students = pd.read_excel(excel_path) all_choices = [ "Civil Engineering (Baccalaureate level)", "Architectural Engineering (Baccalaureate level)", "Quantity Surveying & Cost Estimation (Baccalaureate level)", "Mechanical Engineering (Baccalaureate level)", "Chemical Engineering (Baccalaureate level)", "Heating Ventilation & Air Conditioning (Diploma level)", "Oil and Gas (Diploma level)", "Electrical Power Engineering (Baccalaureate level)", "Electronics and Telecommunication Engineering (Baccalaureate level)", "Computer Engineering (Baccalaureate level)" ] female_choices = [c for c in all_choices if "Heating Ventilation" not in c] eligibility_df = pd.DataFrame({ "S.No": range(1, 11), "Specialization": all_choices, "Male": ["Yes"] * 10, "Female": ["Yes", "Yes", "Yes", "Yes", "Yes", "Not Applicable", "Yes", "Yes", "Yes", "Yes"] }) def reset_student_form(): for key in list(st.session_state.keys()): if key.startswith("choice_") or key in ["student_id_input", "phone_input", "gender_input"]: del st.session_state[key] def convert_df_to_excel(df): output = BytesIO() with pd.ExcelWriter(output, engine="openpyxl") as writer: df.to_excel(writer, index=False, sheet_name="Student Choices") output.seek(0) return output def create_ack_html(student_id, name, advisor, gender, phone, choices): rows = "".join([ f"Choice {i+1}{c}" for i, c in enumerate(choices) ]) return f""" Specialization Choice Acknowledgement

Specialization Choice Acknowledgement

Engineering Specialization Selection Portal

Submission Date/Time: {datetime.now().strftime("%d-%m-%Y %H:%M:%S")}

Student ID: {student_id}

Student Name: {name}

Advisor Name: {advisor}

Gender: {gender}

Phone Number: {phone}

{rows}
Priority Selected Specialization
This acknowledgement confirms that your specialization preferences have been submitted successfully. If the same student submits again, only the latest submission will be considered. Final allocation is subject to Specialization Committee approval.
""".encode("utf-8") def show_header(): top1, top2 = st.columns([1, 5]) with top1: if os.path.exists(logo_path): st.image(logo_path, width=150) with top2: st.markdown("""
Specialization Priority Selection System
Engineering Specialization Selection Portal
""", unsafe_allow_html=True) def student_portal(): show_header() st.markdown("""

Student Steps and Rules

  1. Enter your Student ID.
  2. If your ID is found, your name and advisor name will appear.
  3. Select your gender and enter your phone number.
  4. After entering phone number, specialization choices will appear.
  5. Male students must prioritize all 10 specializations.
  6. Female students must prioritize 9 specializations only, as HVAC is not applicable.
  7. After submission, download your acknowledgement report.
  8. If you submit more than once using the same Student ID, only your latest submission will be stored and considered.
  9. Final allocation is subject to Specialization Committee approval.
""", unsafe_allow_html=True) st.header("Available Specializations") st.table(eligibility_df) st.header("Step 1: Student Login") student_id = st.text_input("Enter your Student ID", key="student_id_input") if student_id: matched = df_students[df_students["Student No"].astype(str) == student_id] if matched.empty: st.error( "Student ID not found in the system. Please contact Mazoon Mohamed Mubarak Al Araimi " "(mazoon.alaraimi@utas.edu.om) or Dr. Deevyankar Agarwal " "(deevyankar.agarwal@utas.edu.om) through Microsoft Teams." ) else: row = matched.iloc[0] st.success("Student ID found successfully.") st.info( f"**Student Name:** {row['Student Name']} \n" f"**Advisor Name:** {row['Advisor Name']}" ) st.header("Step 2: Basic Information") gender = st.radio( "Select Gender", ["Male", "Female"], horizontal=True, key="gender_input" ) phone = st.text_input("Enter Phone Number", key="phone_input") if phone.strip(): choices_available = all_choices if gender == "Male" else female_choices required_choices = 10 if gender == "Male" else 9 st.header(f"Step 3: Prioritize Your {required_choices} Choices") selected_choices = [] for i in range(required_choices): remaining = [c for c in choices_available if c not in selected_choices] choice = st.selectbox(f"Choice {i+1}", remaining, key=f"choice_{i}") selected_choices.append(choice) if st.button("Submit Choices"): submission = { "Student ID": student_id, "Student Name": row["Student Name"], "Advisor Name": row["Advisor Name"], "Gender": gender, "Phone Number": phone } for i, c in enumerate(selected_choices): submission[f"Choice {i+1}"] = c submit_df = pd.DataFrame([submission]) if os.path.exists(csv_file): old_df = pd.read_csv(csv_file) old_df = old_df[old_df["Student ID"].astype(str) != student_id] final_df = pd.concat([old_df, submit_df], ignore_index=True) else: final_df = submit_df final_df.to_csv(csv_file, index=False) st.success("Your choices have been submitted successfully.") st.markdown("""
Your acknowledgement report is ready. Please click the orange button below to download it. After downloading, the form will reset for the next student.
""", unsafe_allow_html=True) ack_html = create_ack_html( student_id, row["Student Name"], row["Advisor Name"], gender, phone, selected_choices ) st.download_button( "📥 Download Acknowledgement Report", data=ack_html, file_name=f"acknowledgement_{student_id}.html", mime="text/html", on_click=reset_student_form ) else: st.warning("Please enter your phone number to continue.") def admin_dashboard(): show_header() st.markdown("""

Admin Dashboard

This section is only for Specialization Committee Members. Please enter the authorized password to view reports and analytics.
""", unsafe_allow_html=True) admin_password = st.text_input("Enter Admin Password", type="password") if admin_password != "admin123": st.info("Please enter the correct admin password to open the dashboard.") return st.success("Admin access granted.") if not os.path.exists(csv_file): st.warning("No student submissions are available yet.") return report_df = pd.read_csv(csv_file) if report_df.empty: st.warning("No student submissions are available yet.") return st.subheader("Summary") m1, m2, m3 = st.columns(3) with m1: st.metric("Total Submissions", len(report_df)) with m2: st.metric("Male Students", len(report_df[report_df["Gender"] == "Male"])) with m3: st.metric("Female Students", len(report_df[report_df["Gender"] == "Female"])) excel_data = convert_df_to_excel(report_df) st.markdown("""
The full Excel report is ready. Please click the orange button below to download the student choice report.
""", unsafe_allow_html=True) st.download_button( "📥 Download Excel Report", data=excel_data, file_name="specialization_report.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) st.divider() st.header("Analytics Dashboard") first_choice_counts = report_df["Choice 1"].value_counts().reset_index() first_choice_counts.columns = ["Specialization", "Required Seats"] st.subheader("Seats Required to Fulfil Student First Choice") st.dataframe(first_choice_counts, use_container_width=True) st.info( "This table shows how many seats are required in each specialization " "to fulfil students' first-choice preferences." ) color_sequence = [ "#003b7a", "#f58220", "#00a6a6", "#7a4cc2", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#17becf" ] st.subheader("First Choice Demand by Specialization") fig_first = px.bar( first_choice_counts, x="Specialization", y="Required Seats", color="Specialization", text="Required Seats", title="Number of Students Interested in Each Specialization as First Choice", template="plotly_white", color_discrete_sequence=color_sequence ) fig_first.update_traces(textposition="outside") fig_first.update_layout( xaxis_tickangle=-35, plot_bgcolor="white", paper_bgcolor="white", font=dict(color="black"), height=550, showlegend=False ) st.plotly_chart(fig_first, use_container_width=True) st.subheader("First Choice Preference by Gender") gender_choice = ( report_df.groupby(["Choice 1", "Gender"]) .size() .reset_index(name="Students") ) fig_gender = px.bar( gender_choice, x="Choice 1", y="Students", color="Gender", barmode="group", text="Students", title="Male and Female Student First Choice Preferences", template="plotly_white", color_discrete_map={ "Male": "#003b7a", "Female": "#f58220" } ) fig_gender.update_traces(textposition="outside") fig_gender.update_layout( xaxis_tickangle=-35, plot_bgcolor="white", paper_bgcolor="white", font=dict(color="black"), height=600 ) st.plotly_chart(fig_gender, use_container_width=True) st.subheader("Submitted Student Choices") st.dataframe(report_df, use_container_width=True) st.sidebar.title("Navigation") page = st.sidebar.radio( "Select Page", ["Student Portal", "Admin Dashboard"] ) if page == "Student Portal": student_portal() else: admin_dashboard()