from transformers import pipeline import pandas as pd import math import gradio as gr # Step 1: Load Excel Files (Not needed for Gradio, files are loaded in run_allocation) # Step 2: Calculate Total Hours and Average Duty (n) 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 # Step 3: Assign Initial Duty Limits Based on Designation 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 # Default for A.P. and others 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 # Step 4: Assign Duties 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) # Function to run the allocation process 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) # Save assignments to Excel for download assignments_df.to_excel("duty_allocation_summary.xlsx", index=False) # Return DataFrames, summary, and file path for display and download 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 # Return None for file path on error # Gradio Interface 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("## 🧑🏫 RKMRC Exam Invigilator Duty Allocation System") gr.Markdown("