saptak21 commited on
Commit
4f184d1
·
verified ·
1 Parent(s): 45a9525

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -0
app.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+
4
+ import pandas as pd
5
+ import math
6
+ import gradio as gr
7
+
8
+ # Step 1: Load Excel Files (Not needed for Gradio, files are loaded in run_allocation)
9
+
10
+ # Step 2: Calculate Total Hours and Average Duty (n)
11
+ def calculate_average_duty(exams_df, teachers_df):
12
+ grouped = exams_df.groupby(['Day', 'Slot', 'Room Number'])['Student Number'].sum().reset_index(name='TotalStudents')
13
+
14
+ def compute_invigilators(x):
15
+ n = math.ceil(x / 20)
16
+ while (20 * n + 10) < x:
17
+ n += 1
18
+ return n
19
+
20
+ grouped['RequiredInvigilators'] = grouped['TotalStudents'].apply(compute_invigilators)
21
+
22
+ exams_df = pd.merge(
23
+ exams_df,
24
+ grouped[['Day', 'Slot', 'Room Number', 'RequiredInvigilators']],
25
+ on=['Day', 'Slot', 'Room Number'],
26
+ how='left'
27
+ )
28
+
29
+ exams_df['Duration'] = exams_df['Duration'].astype(int)
30
+ total_invigilator_hours = sum(exams_df['RequiredInvigilators'] * exams_df['Duration'])
31
+ n = total_invigilator_hours / len(teachers_df)
32
+ return n, total_invigilator_hours, exams_df
33
+
34
+ # Step 3: Assign Initial Duty Limits Based on Designation
35
+ def assign_initial_duties(teachers_df, avg_duty):
36
+ teachers_df['DESIG'] = teachers_df['DESIG'].str.strip().str.upper()
37
+
38
+ def get_duty_limit(desig, avg):
39
+ if desig == "SACT":
40
+ return avg - 2
41
+ elif desig in ["LAB", "HOD", "BURSAR", "AQAC"]:
42
+ return avg - 1
43
+ else:
44
+ return avg # Default for A.P. and others
45
+
46
+ teachers_df['DutyLimit'] = teachers_df['DESIG'].apply(lambda d: get_duty_limit(d, math.ceil(avg_duty)))
47
+ teachers_df['AssignedHours'] = 0
48
+ teachers_df['AssignedDays'] = [[] for _ in range(len(teachers_df))]
49
+ return teachers_df
50
+
51
+ # Step 4: Assign Duties
52
+ def assign_duties(teachers_df, exams_df, buffer=0.5):
53
+ assignments = []
54
+ unassigned = []
55
+
56
+ unique_sessions = exams_df[['Day', 'Slot', 'Room Number', 'Duration', 'RequiredInvigilators']].drop_duplicates()
57
+
58
+ for _, exam in unique_sessions.iterrows():
59
+ date = exam['Day']
60
+ time = exam['Slot']
61
+ duration = int(exam['Duration'])
62
+ room = exam['Room Number']
63
+ required_invigilators = int(exam['RequiredInvigilators'])
64
+
65
+ for _ in range(required_invigilators):
66
+ available_teachers = teachers_df[
67
+ (teachers_df['AssignedHours'] + duration <= teachers_df['DutyLimit'] + buffer) &
68
+ (~teachers_df['AssignedDays'].apply(lambda x: (date, time) in x))
69
+ ]
70
+
71
+ if available_teachers.empty:
72
+ unassigned.append({
73
+ 'Day': date, 'Slot': time, 'Room': room,
74
+ 'Duration': duration, 'Reason': 'No available teacher'
75
+ })
76
+ continue
77
+
78
+ available_teachers = available_teachers.sort_values(by='AssignedHours')
79
+ selected_teacher = available_teachers.head(1)
80
+ idx = selected_teacher.index[0]
81
+
82
+ teachers_df.at[idx, 'AssignedHours'] += duration
83
+ teachers_df.at[idx, 'AssignedDays'].append((date, time))
84
+
85
+ assignments.append({
86
+ 'Day': date,
87
+ 'Slot': time,
88
+ 'Room': room,
89
+ 'Duration': duration,
90
+ 'Teacher': teachers_df.at[idx, 'NAME'],
91
+ 'Designation': teachers_df.at[idx, 'DESIG'],
92
+ 'AssignedHoursAfter': teachers_df.at[idx, 'AssignedHours']
93
+ })
94
+
95
+ return pd.DataFrame(assignments), pd.DataFrame(unassigned)
96
+
97
+ # Function to run the allocation process
98
+ def run_allocation(teachers_file, exams_file, buffer=0.5):
99
+ try:
100
+ teachers_df = pd.read_excel(teachers_file.name)
101
+ exams_df = pd.read_excel(exams_file.name)
102
+
103
+ n, total_hours, exams_df = calculate_average_duty(exams_df, teachers_df)
104
+
105
+ teachers_df = assign_initial_duties(teachers_df, n)
106
+ assignments_df, unassigned_df = assign_duties(teachers_df, exams_df, buffer=buffer)
107
+
108
+ # Save assignments to Excel for download
109
+ assignments_df.to_excel("duty_allocation_summary.xlsx", index=False)
110
+
111
+
112
+ # Return DataFrames, summary, and file path for display and download
113
+ return assignments_df, unassigned_df, teachers_df[['NAME', 'DESIG', 'AssignedHours', 'DutyLimit']], total_hours, n, "duty_allocation_summary.xlsx"
114
+
115
+ except Exception as e:
116
+ return None, None, None, None, str(e), None # Return None for file path on error
117
+
118
+
119
+ # Gradio Interface
120
+ iface = gr.Interface(
121
+ fn=run_allocation,
122
+ inputs=[
123
+ gr.File(label="Teachers Excel File"),
124
+ gr.File(label="Exam Summary Excel File"),
125
+ gr.Slider(minimum=0, maximum=2, step=0.1, label="Duty Buffer", value=0.5),
126
+ ],
127
+ outputs=[
128
+ gr.Dataframe(label="Duty Assignments"),
129
+ gr.Dataframe(label="Unassigned Duties"),
130
+ gr.Dataframe(label="Teacher Summary"),
131
+ gr.Textbox(label="Total Invigilator Hours"),
132
+ gr.Textbox(label="Average Duty per Teacher"),
133
+ gr.File(label="Download Duty Allocation Summary") # Add File component for download
134
+ ],
135
+ title="🧑‍🏫 Duty Allocation System",
136
+ description="Upload your Excel files and click 'Submit' to generate duty assignments."
137
+ )
138
+
139
+ iface.launch(inline = False)
140
+