| from transformers import pipeline |
|
|
|
|
| import pandas as pd |
| import math |
| import gradio as gr |
|
|
| |
|
|
| |
| def calculate_average_duty(exams_df, teachers_df): |
| grouped = exams_df.groupby(['Day', 'Slot', 'Room Number'])['Student Number'].sum().reset_index(name='TotalStudents') |
|
|
| def compute_invigilators(x): |
| n = math.ceil(x / 20) |
| while (20 * n + 10) < x: |
| n += 1 |
| return n |
|
|
| grouped['RequiredInvigilators'] = grouped['TotalStudents'].apply(compute_invigilators) |
|
|
| exams_df = pd.merge( |
| exams_df, |
| grouped[['Day', 'Slot', 'Room Number', 'RequiredInvigilators']], |
| on=['Day', 'Slot', 'Room Number'], |
| how='left' |
| ) |
|
|
| exams_df['Duration'] = exams_df['Duration'].astype(int) |
| total_invigilator_hours = sum(exams_df['RequiredInvigilators'] * exams_df['Duration']) |
| n = total_invigilator_hours / len(teachers_df) |
| return n, total_invigilator_hours, exams_df |
|
|
| |
| def assign_initial_duties(teachers_df, avg_duty): |
| teachers_df['DESIG'] = teachers_df['DESIG'].str.strip().str.upper() |
|
|
| def get_duty_limit(desig, avg): |
| if desig == "SACT": |
| return avg - 2 |
| elif desig in ["LAB", "HOD", "BURSAR", "AQAC"]: |
| return avg - 1 |
| else: |
| return avg |
|
|
| teachers_df['DutyLimit'] = teachers_df['DESIG'].apply(lambda d: get_duty_limit(d, math.ceil(avg_duty))) |
| teachers_df['AssignedHours'] = 0 |
| teachers_df['AssignedDays'] = [[] for _ in range(len(teachers_df))] |
| return teachers_df |
|
|
| |
| def assign_duties(teachers_df, exams_df, buffer=0.5): |
| assignments = [] |
| unassigned = [] |
|
|
| unique_sessions = exams_df[['Day', 'Slot', 'Room Number', 'Duration', 'RequiredInvigilators']].drop_duplicates() |
|
|
| for _, exam in unique_sessions.iterrows(): |
| date = exam['Day'] |
| time = exam['Slot'] |
| duration = int(exam['Duration']) |
| room = exam['Room Number'] |
| required_invigilators = int(exam['RequiredInvigilators']) |
|
|
| for _ in range(required_invigilators): |
| available_teachers = teachers_df[ |
| (teachers_df['AssignedHours'] + duration <= teachers_df['DutyLimit'] + buffer) & |
| (~teachers_df['AssignedDays'].apply(lambda x: (date, time) in x)) |
| ] |
|
|
| if available_teachers.empty: |
| unassigned.append({ |
| 'Day': date, 'Slot': time, 'Room': room, |
| 'Duration': duration, 'Reason': 'No available teacher' |
| }) |
| continue |
|
|
| available_teachers = available_teachers.sort_values(by='AssignedHours') |
| selected_teacher = available_teachers.head(1) |
| idx = selected_teacher.index[0] |
|
|
| teachers_df.at[idx, 'AssignedHours'] += duration |
| teachers_df.at[idx, 'AssignedDays'].append((date, time)) |
|
|
| assignments.append({ |
| 'Day': date, |
| 'Slot': time, |
| 'Room': room, |
| 'Duration': duration, |
| 'Teacher': teachers_df.at[idx, 'NAME'], |
| 'Designation': teachers_df.at[idx, 'DESIG'], |
| 'AssignedHoursAfter': teachers_df.at[idx, 'AssignedHours'] |
| }) |
|
|
| return pd.DataFrame(assignments), pd.DataFrame(unassigned) |
|
|
| |
| def run_allocation(teachers_file, exams_file, buffer=0.5): |
| try: |
| teachers_df = pd.read_excel(teachers_file.name) |
| exams_df = pd.read_excel(exams_file.name) |
|
|
| n, total_hours, exams_df = calculate_average_duty(exams_df, teachers_df) |
|
|
| teachers_df = assign_initial_duties(teachers_df, n) |
| assignments_df, unassigned_df = assign_duties(teachers_df, exams_df, buffer=buffer) |
|
|
| |
| assignments_df.to_excel("duty_allocation_summary.xlsx", index=False) |
|
|
|
|
| |
| return assignments_df, unassigned_df, teachers_df[['NAME', 'DESIG', 'AssignedHours', 'DutyLimit']], total_hours, n, "duty_allocation_summary.xlsx" |
|
|
| except Exception as e: |
| return None, None, None, None, str(e), None |
|
|
|
|
| |
| with gr.Blocks() as iface: |
| gr.Image( |
| value="https://drive.google.com/uc?id=1nmhNC3JjyU9YsVh-bzgzAmQZgloqNtEQ", |
| height=158, |
| width=158, |
| show_label=False, |
| container=False |
| |
| ) |
| |
| gr.Markdown("<h1 style='text-align: center;'>π§βπ« RKMRC Exam Invigilator Duty Allocation System</h1>") |
| gr.Markdown("π Upload your Excel files and click 'Submit' to generate duty assignments.") |
|
|
| teachers_file = gr.File(label="π Teachers Excel File") |
| exams_file = gr.File(label="π Exam Summary Excel File") |
| buffer_slider = gr.Slider(minimum=0, maximum=2, step=0.1, label="Duty Buffer", value=0.5) |
| submit_btn = gr.Button("Submit") |
|
|
| duty_assignments = gr.Dataframe(label="β
Duty Assignments") |
| unassigned_duties = gr.Dataframe(label="β οΈ Unassigned Duties") |
| teacher_summary = gr.Dataframe(label="π¨βπ« Teacher Summary") |
| total_hours_text = gr.Textbox(label="Total Invigilator Hours") |
| avg_duty_text = gr.Textbox(label="Average Duty per Teacher") |
| download_file = gr.File(label="π Download Duty Allocation Summary") |
|
|
| submit_btn.click( |
| fn=run_allocation, |
| inputs=[teachers_file, exams_file, buffer_slider], |
| outputs=[ |
| duty_assignments, |
| unassigned_duties, |
| teacher_summary, |
| total_hours_text, |
| avg_duty_text, |
| download_file |
| ] |
| ) |
|
|
| iface.launch() |
|
|