Hidayatmahar commited on
Commit
1ecf220
·
verified ·
1 Parent(s): f6babdb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -242
app.py CHANGED
@@ -1,242 +1,55 @@
1
- """ Iqbal Hall Hostel Allotment (Manual Selection) - Gradio App
2
-
3
- Save this file as app.py and deploy in a Gradio Space on Hugging Face. Dependencies (requirements.txt): gradio>=4.29.0 pillow pandas
4
-
5
- Features added/changed from auto-only version:
6
-
7
- Manual selection of Floor, Room and Bed (with availability validation)
8
-
9
- Option to Auto-Assign if the selected room/bed is full or user prefers automatic allocation
10
-
11
- Occupancy refresh, search, and card generation as before
12
-
13
- All data stored in data/ folder inside the Space (students.csv, photos/, cards/)
14
-
15
-
16
- Usage:
17
-
18
- Create a Gradio Space (Gradio runtime), upload this file, add requirements.txt and README
19
-
20
- The UI allows an admin or user to manually choose floor, room and bed. The app will verify availability. """
21
-
22
-
23
- import gradio as gr import os import pandas as pd from PIL import Image, ImageDraw from datetime import datetime import uuid import io
24
-
25
- === Configuration ===
26
-
27
- HOSTEL_NAME = "Iqbal Hall" UNIVERSITY_NAME = "NFC Institute of Engineering & Technology (NFCIET) Multan" TOTAL_ROOMS = 160 FLOORS = 4 CAPACITY_PER_ROOM = 3 BEDS = ["A", "B", "C"] # 3-person capacity per room
28
-
29
- DATA_DIR = "data" PHOTOS_DIR = os.path.join(DATA_DIR, "photos") CARDS_DIR = os.path.join(DATA_DIR, "cards") CSV_PATH = os.path.join(DATA_DIR, "students.csv")
30
-
31
- os.makedirs(PHOTOS_DIR, exist_ok=True) os.makedirs(CARDS_DIR, exist_ok=True)
32
-
33
- Initialize CSV if not exists
34
-
35
- if not os.path.exists(CSV_PATH): df = pd.DataFrame(columns=[ "id","timestamp","name","father_name","nic_bform","district","province","date_of_birth", "floor","room","bed","photo_path","card_path" ]) df.to_csv(CSV_PATH, index=False)
36
-
37
- Helper functions
38
-
39
- def rooms_per_floor(): return TOTAL_ROOMS // FLOORS
40
-
41
- def floor_room_range(floor): """Return list of room numbers for a floor. Floor is 1..FLOORS We use numbering: 101..140, 201..240, etc. """ rpf = rooms_per_floor() start = floor * 100 + 1 return [start + i for i in range(rpf)]
42
-
43
- def all_rooms_list(): rooms = [] for fl in range(1, FLOORS+1): rooms.extend(floor_room_range(fl)) return rooms
44
-
45
- def read_db(): try: df = pd.read_csv(CSV_PATH) except Exception: df = pd.DataFrame(columns=[ "id","timestamp","name","father_name","nic_bform","district","province","date_of_birth", "floor","room","bed","photo_path","card_path" ]) return df
46
-
47
- def current_allocations(): df = read_db() occ = {} for _, row in df.iterrows(): r = str(row["room"]) b = str(row["bed"]) if r not in occ: occ[r] = set() occ[r].add(b) return occ
48
-
49
- def available_beds_for_room(room_number): occ = current_allocations() used = occ.get(str(room_number), set()) return [b for b in BEDS if b not in used]
50
-
51
- def is_bed_available(room, bed): return bed in available_beds_for_room(room)
52
-
53
- def next_available_room_bed(): occ = current_allocations() for r in all_rooms_list(): r_str = str(r) used = occ.get(r_str, set()) for b in BEDS: if b not in used: # derive floor from room number floor = r // 100 return floor, r, b return None, None, None
54
-
55
- def draw_hostel_card(record, student_img): W, H = 1000, 600 card = Image.new("RGB", (W, H), (245, 248, 250)) draw = ImageDraw.Draw(card)
56
-
57
- header_h = 90
58
- draw.rectangle([(0,0), (W, header_h)], fill=(30, 64, 175))
59
- header_text = f"{HOSTEL_NAME} – {UNIVERSITY_NAME}"
60
- draw.text((24, 20), header_text, fill=(255,255,255))
61
-
62
- photo_box = (40, header_h + 30, 40+220, header_h + 30 + 260)
63
- if student_img.mode != "RGB":
64
- student_img = student_img.convert("RGB")
65
- img = student_img.copy()
66
- img.thumbnail((photo_box[2]-photo_box[0], photo_box[3]-photo_box[1]))
67
- px = photo_box[0] + ((photo_box[2]-photo_box[0]) - img.size[0])//2
68
- py = photo_box[1] + ((photo_box[3]-photo_box[1]) - img.size[1])//2
69
- draw.rectangle(photo_box, outline=(100,100,100), width=2)
70
- card.paste(img, (px, py))
71
-
72
- info_x = 300
73
- info_y = header_h + 30
74
- line_gap = 36
75
-
76
- def t(label, value, y):
77
- draw.text((info_x, y), f"{label}: {value}", fill=(20,20,20))
78
-
79
- t("Name", record["name"], info_y); info_y += line_gap
80
- t("Father's Name", record["father_name"], info_y); info_y += line_gap
81
- t("NIC/B-Form", record["nic_bform"], info_y); info_y += line_gap
82
- t("District", record["district"], info_y); info_y += line_gap
83
- t("Province", record["province"], info_y); info_y += line_gap
84
- t("Date of Birth", record["date_of_birth"], info_y); info_y += line_gap
85
- t("Floor", record.get("floor",""), info_y); info_y += line_gap
86
- t("Room", record.get("room",""), info_y); info_y += line_gap
87
- t("Bed", record.get("bed",""), info_y); info_y += line_gap
88
- t("Allotment ID", record["id"], info_y); info_y += line_gap
89
-
90
- footer_text = f"Issue Date: {datetime.now().strftime('%Y-%m-%d')} Valid for current academic year"
91
- draw.text((24, H-40), footer_text, fill=(60,60,60))
92
-
93
- buf = io.BytesIO()
94
- card.save(buf, format="PNG")
95
- buf.seek(0)
96
- return card, buf
97
-
98
- def validate_inputs(name, father_name, nic_bform, district, province, dob, photo): missing = [] if not name: missing.append("Name") if not father_name: missing.append("Father's Name") if not nic_bform: missing.append("NIC/B-Form") if not district: missing.append("District") if not province: missing.append("Province") if not dob: missing.append("Date of Birth") if photo is None: missing.append("Photo") if missing: return False, f"Please provide: {', '.join(missing)}" return True, ""
99
-
100
- def save_record(record): try: df = pd.read_csv(CSV_PATH) if os.path.exists(CSV_PATH) else pd.DataFrame() except Exception: df = pd.DataFrame() df = pd.concat([df, pd.DataFrame([record])], ignore_index=True) df.to_csv(CSV_PATH, index=False)
101
-
102
- --- Gradio callbacks ---
103
-
104
- Populate floors for dropdown
105
-
106
- FLOOR_OPTIONS = [str(i) for i in range(1, FLOORS+1)] PROVINCES = ["Punjab","Sindh","Khyber Pakhtunkhwa","Balochistan","Gilgit-Baltistan","Azad Kashmir","Islamabad Capital Territory"]
107
-
108
- def rooms_for_floor_str(floor_str): if not floor_str: return [] fl = int(floor_str) return [str(r) for r in floor_room_range(fl)]
109
-
110
- def beds_for_room_str(room_str): if not room_str: return [] room = int(room_str) return available_beds_for_room(room)
111
-
112
- def manual_submit(name, father_name, nic_bform, district, province, dob, photo, floor_sel, room_sel, bed_sel, auto_assign_flag): # Validate fields ok, msg = validate_inputs(name, father_name, nic_bform, district, province, dob, photo) if not ok: return gr.update(value=None), gr.update(visible=False), gr.update(visible=False), gr.update(value=msg)
113
-
114
- # If user elected auto_assign_flag (checkbox True), perform automatic assignment
115
- if auto_assign_flag:
116
- floor, room, bed = next_available_room_bed()
117
- if room is None:
118
- return gr.update(value=None), gr.update(visible=False), gr.update(visible=False), gr.update(value="Hostel is fully occupied. No rooms available.")
119
- else:
120
- # Use manual selection - ensure provided
121
- if not floor_sel or not room_sel or not bed_sel:
122
- return gr.update(value=None), gr.update(visible=False), gr.update(visible=False), gr.update(value="Please select Floor, Room and Bed, or choose Auto-Assign.")
123
- room = int(room_sel)
124
- bed = bed_sel
125
- floor = int(floor_sel)
126
- # Check bed availability
127
- if not is_bed_available(room, bed):
128
- return gr.update(value=None), gr.update(visible=False), gr.update(visible=False), gr.update(value=f"Selected Bed {bed} in Room {room} is already occupied. Choose another.")
129
-
130
- # Create unique ID
131
- sid = str(uuid.uuid4())[:8].upper()
132
-
133
- # Save photo
134
- photo_path = os.path.join(PHOTOS_DIR, f"{sid}.png")
135
- if isinstance(photo, str) and os.path.exists(photo):
136
- im = Image.open(photo)
137
- else:
138
- im = photo
139
- if im.mode != "RGB":
140
- im = im.convert("RGB")
141
- im.save(photo_path)
142
-
143
- record = {
144
- "id": sid,
145
- "timestamp": datetime.now().isoformat(timespec="seconds"),
146
- "name": name.strip(),
147
- "father_name": father_name.strip(),
148
- "nic_bform": nic_bform.strip(),
149
- "district": district.strip(),
150
- "province": province.strip(),
151
- "date_of_birth": dob.strip(),
152
- "floor": floor,
153
- "room": room,
154
- "bed": bed,
155
- "photo_path": photo_path,
156
- "card_path": ""
157
- }
158
-
159
- # Generate card
160
- card_img, buf = draw_hostel_card(record, im)
161
- card_path = os.path.join(CARDS_DIR, f"{sid}_card.png")
162
- card_img.save(card_path)
163
- record["card_path"] = card_path
164
-
165
- # Save record
166
- save_record(record)
167
-
168
- success_msg = f"Allotment successful!\nAssigned Floor: {floor} Room: {room} Bed: {bed}\nAllotment ID: {sid}"
169
- return card_path, gr.update(visible=True), gr.update(visible=True), gr.update(value=success_msg)
170
-
171
- def load_occupancy(): df = read_db() total_beds = TOTAL_ROOMS * CAPACITY_PER_ROOM used_beds = len(df) free_beds = total_beds - used_beds status = f"Total Capacity: {total_beds} | Allocated: {used_beds} | Available: {free_beds}" # convert some columns to string for display safety if not df.empty: df_disp = df.astype(str) else: df_disp = df return df_disp, status
172
-
173
- def search_by_nic(nic): if not nic: return "Enter NIC/B-Form to search.", None, None df = read_db() if df.empty: return "No records yet.", None, None res = df[df["nic_bform"].astype(str).str.strip().str.lower() == nic.strip().lower()] if res.empty: return "No record found.", None, None row = res.iloc[0].to_dict() card_img = row.get("card_path") if isinstance(row.get("card_path"), str) and os.path.exists(row.get("card_path")) else None text = f"Found: {row['name']} | Floor {row.get('floor','')} Room {row['room']} Bed {row['bed']} | ID: {row['id']}" return text, card_img, row.get("card_path")
174
-
175
- Build Gradio UI
176
-
177
- with gr.Blocks(title=f"{HOSTEL_NAME} Allotment – {UNIVERSITY_NAME}") as demo: gr.Markdown(f"## {HOSTEL_NAME} – {UNIVERSITY_NAME} \nManual Room Selection + Auto-Assign fallback")
178
-
179
- with gr.Tabs():
180
- with gr.Tab("New Allotment"):
181
- with gr.Row():
182
- with gr.Column(scale=1):
183
- name = gr.Textbox(label="Student Name", placeholder="Enter full name")
184
- father_name = gr.Textbox(label="Father's Name", placeholder="Enter father's name")
185
- nic_bform = gr.Textbox(label="NIC / B-Form", placeholder="e.g., 35202-1234567-1")
186
- district = gr.Textbox(label="District")
187
- province = gr.Dropdown(choices=PROVINCES, label="Province")
188
- dob = gr.Textbox(label="Date of Birth", placeholder="YYYY-MM-DD")
189
- with gr.Column(scale=1):
190
- photo = gr.Image(type="pil", label="Student Photo (Passport size preferred)")
191
- gr.Markdown("**Manual Room Selection (leave blank for Auto-Assign)**")
192
- floor_dd = gr.Dropdown(choices=FLOOR_OPTIONS, label="Floor (1-4)")
193
- room_dd = gr.Dropdown(choices=[], label="Room Number")
194
- bed_dd = gr.Dropdown(choices=[], label="Bed (A/B/C)")
195
- auto_assign_checkbox = gr.Checkbox(label="Auto-Assign instead of manual selection", value=False)
196
- submit_btn = gr.Button("Allocate Room & Generate Card", variant="primary")
197
- status_box = gr.Textbox(label="Status", interactive=False)
198
-
199
- with gr.Row():
200
- card_out = gr.Image(label="Generated Hostel Card (PNG)", visible=False)
201
- with gr.Row():
202
- download_card = gr.File(label="Download Hostel Card", visible=False)
203
-
204
- # Populate rooms when floor changes
205
- floor_dd.change(lambda f: rooms_for_floor_str(f), inputs=[floor_dd], outputs=[room_dd])
206
- # Populate available beds when room changes
207
- room_dd.change(lambda r: beds_for_room_str(r), inputs=[room_dd], outputs=[bed_dd])
208
-
209
- submit_btn.click(
210
- manual_submit,
211
- inputs=[name, father_name, nic_bform, district, province, dob, photo, floor_dd, room_dd, bed_dd, auto_assign_checkbox],
212
- outputs=[card_out, download_card, card_out, status_box]
213
- )
214
-
215
- with gr.Tab("Occupancy"):
216
- refresh_btn = gr.Button("Refresh Occupancy")
217
- occupancy_status = gr.Markdown("")
218
- table = gr.Dataframe(wrap=True, interactive=False)
219
-
220
- def _refresh():
221
- df, status = load_occupancy()
222
- return status, df
223
-
224
- refresh_btn.click(_refresh, inputs=None, outputs=[occupancy_status, table])
225
- occupancy_status.value, table.value = load_occupancy()
226
-
227
- with gr.Tab("Find Student"):
228
- query_nic = gr.Textbox(label="NIC / B-Form", placeholder="Enter exact NIC/B-Form to search")
229
- search_btn = gr.Button("Search")
230
- result_text = gr.Markdown("")
231
- found_card = gr.Image(label="Hostel Card", visible=False)
232
- found_file = gr.File(label="Download Card", visible=False)
233
-
234
- def _search(nic):
235
- text, img_path, file_path = search_by_nic(nic)
236
- return text, gr.update(visible=bool(img_path), value=img_path), gr.update(visible=bool(file_path), value=file_path)
237
-
238
- search_btn.click(_search, inputs=[query_nic], outputs=[result_text, found_card, found_file])
239
-
240
- gr.Markdown("— Built with ❤️ using Gradio. Data is stored locally in the `data/` folder inside this Space.")
241
-
242
- if name == "main": demo.launch()
 
1
+ import gradio as gr
2
+ import os
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ import uuid
6
+
7
+ # File to store allotment data
8
+ CSV_FILE = "hostel_allotments.csv"
9
+
10
+ # Create CSV if not exists
11
+ if not os.path.exists(CSV_FILE):
12
+ df = pd.DataFrame(columns=["Allotment_ID", "Name", "Roll_No", "Department", "Hostel", "Room_Type", "Bed_No", "Date_Time"])
13
+ df.to_csv(CSV_FILE, index=False)
14
+
15
+ # Function for hostel allotment
16
+ def allot_hostel(name, roll_no, department, hostel, room_type, bed_no):
17
+ allotment_id = str(uuid.uuid4())[:8] # unique short ID
18
+ date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
19
+
20
+ # Save to CSV
21
+ df = pd.read_csv(CSV_FILE)
22
+ new_entry = {
23
+ "Allotment_ID": allotment_id,
24
+ "Name": name,
25
+ "Roll_No": roll_no,
26
+ "Department": department,
27
+ "Hostel": hostel,
28
+ "Room_Type": room_type,
29
+ "Bed_No": bed_no,
30
+ "Date_Time": date_time
31
+ }
32
+ df = pd.concat([df, pd.DataFrame([new_entry])], ignore_index=True)
33
+ df.to_csv(CSV_FILE, index=False)
34
+
35
+ return f"✅ Hostel Allotted Successfully!\n\nAllotment ID: {allotment_id}\nName: {name}\nRoll No: {roll_no}\nDepartment: {department}\nHostel: {hostel}\nRoom Type: {room_type}\nBed No: {bed_no}\nDate & Time: {date_time}"
36
+
37
+ # UI
38
+ with gr.Blocks() as demo:
39
+ gr.Markdown("## 🏨 Hostel Allotment System")
40
+
41
+ with gr.Row():
42
+ name = gr.Textbox(label="Student Name")
43
+ roll_no = gr.Textbox(label="Roll Number")
44
+ department = gr.Textbox(label="Department")
45
+
46
+ hostel = gr.Dropdown(["Hostel A", "Hostel B", "Hostel C"], label="Select Hostel")
47
+ room_type = gr.Dropdown(["Single", "Double", "Triple"], label="Select Room Type")
48
+ bed_no = gr.Dropdown([f"Bed {i}" for i in range(1, 11)], label="Select Bed No")
49
+
50
+ submit_btn = gr.Button("Allot Hostel")
51
+ output = gr.Textbox(label="Allotment Details", lines=10)
52
+
53
+ submit_btn.click(fn=allot_hostel, inputs=[name, roll_no, department, hostel, room_type, bed_no], outputs=output)
54
+
55
+ demo.launch()