Jacksonnavigator7 commited on
Commit
80949f1
·
verified ·
1 Parent(s): e0e5d13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +909 -60
app.py CHANGED
@@ -1,117 +1,966 @@
1
- # Hospital Queue Management System - Gradio App for Hugging Face
2
- # Features: Multiple Doctors, Patient Queue, Phone Number Status Check
3
 
4
  import sqlite3
5
  import gradio as gr
 
 
 
 
 
 
6
 
7
  # ---------------------------
8
  # DATABASE SETUP
9
  # ---------------------------
10
- conn = sqlite3.connect("hospital.db", check_same_thread=False)
 
 
 
 
 
 
 
 
 
 
11
  cursor = conn.cursor()
 
 
12
  cursor.execute('''CREATE TABLE IF NOT EXISTS doctors (
13
  id INTEGER PRIMARY KEY AUTOINCREMENT,
14
- name TEXT NOT NULL
 
 
 
15
  )''')
 
16
  cursor.execute('''CREATE TABLE IF NOT EXISTS patients (
17
  id INTEGER PRIMARY KEY AUTOINCREMENT,
18
- name TEXT,
19
- phone TEXT,
 
20
  symptoms TEXT,
 
21
  doctor_id INTEGER,
22
  queue_number INTEGER,
 
 
 
23
  status TEXT DEFAULT 'Waiting',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  FOREIGN KEY (doctor_id) REFERENCES doctors(id)
25
  )''')
 
 
 
 
 
 
 
 
 
26
  conn.commit()
27
 
28
  # Seed doctors if table is empty
29
  cursor.execute("SELECT COUNT(*) FROM doctors")
30
  if cursor.fetchone()[0] == 0:
31
- doctors = [("Dr. Smith",), ("Dr. Lee",), ("Dr. Patel",)]
32
- cursor.executemany("INSERT INTO doctors (name) VALUES (?)", doctors)
 
 
 
 
 
 
33
  conn.commit()
34
 
35
  # ---------------------------
36
- # CORE FUNCTIONS
37
  # ---------------------------
38
- def register_patient(name, phone, symptoms, doctor_name):
39
- cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
40
- doctor_id = cursor.fetchone()[0]
41
- cursor.execute("SELECT MAX(queue_number) FROM patients WHERE doctor_id=?", (doctor_id,))
42
- last_queue = cursor.fetchone()[0]
43
- next_queue = 1 if last_queue is None else last_queue + 1
44
- cursor.execute("INSERT INTO patients (name, phone, symptoms, doctor_id, queue_number) VALUES (?, ?, ?, ?, ?)",
45
- (name, phone, symptoms, doctor_id, next_queue))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  conn.commit()
47
- return f"Registered! Your queue number is {next_queue} with {doctor_name}."
48
 
49
- def check_status(phone):
50
- cursor.execute("SELECT d.name, p.queue_number, p.status FROM patients p JOIN doctors d ON p.doctor_id = d.id WHERE p.phone=? ORDER BY p.id DESC LIMIT 1", (phone,))
51
- result = cursor.fetchone()
52
- if result:
53
- return f"Doctor: {result[0]}\nQueue #: {result[1]}\nStatus: {result[2]}"
54
- return "Phone number not found."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  def get_doctor_queue(doctor_name):
57
- cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
58
- doctor_id = cursor.fetchone()[0]
59
- cursor.execute("SELECT id, name, queue_number, status FROM patients WHERE doctor_id=? ORDER BY queue_number", (doctor_id,))
60
- rows = cursor.fetchall()
61
- return rows
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  def call_next(doctor_name):
64
- cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
65
- doctor_id = cursor.fetchone()[0]
66
- cursor.execute("SELECT id, name FROM patients WHERE doctor_id=? AND status='Waiting' ORDER BY queue_number ASC LIMIT 1", (doctor_id,))
67
- patient = cursor.fetchone()
68
- if patient:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  cursor.execute("UPDATE patients SET status='In Consultation' WHERE id=?", (patient[0],))
 
 
 
 
 
 
70
  conn.commit()
71
- return f"Calling {patient[1]} for consultation."
72
- return "No patients waiting."
 
 
 
 
 
 
 
 
73
 
74
- def complete_patient(patient_id):
75
- cursor.execute("UPDATE patients SET status='Completed' WHERE id=?", (patient_id,))
76
- conn.commit()
77
- return f"Patient ID {patient_id} marked as completed."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  # ---------------------------
80
  # GRADIO INTERFACE
81
  # ---------------------------
 
 
 
 
 
82
 
83
- doctor_names = [row[0] for row in cursor.execute("SELECT name FROM doctors").fetchall()]
 
 
 
 
84
 
85
- with gr.Blocks() as demo:
86
- gr.Markdown("# 🏥 Hospital Queue Management System")
 
 
 
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  with gr.Tab("➕ Register Patient"):
 
 
 
 
 
 
89
  with gr.Row():
90
- name = gr.Textbox(label="Patient Name")
91
- phone = gr.Textbox(label="Phone Number")
92
- symptoms = gr.Textbox(label="Symptoms")
93
- doctor = gr.Dropdown(choices=doctor_names, label="Select Doctor")
94
- register_btn = gr.Button("Register")
95
- register_output = gr.Textbox(label="Response")
96
- register_btn.click(fn=register_patient, inputs=[name, phone, symptoms, doctor], outputs=register_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
 
98
  with gr.Tab("🔍 Check My Status"):
99
- phone_lookup = gr.Textbox(label="Enter Your Phone Number")
100
- check_btn = gr.Button("Check Status")
101
- status_output = gr.Textbox(label="Queue Info")
 
 
 
 
 
 
 
 
102
  check_btn.click(fn=check_status, inputs=phone_lookup, outputs=status_output)
103
 
 
104
  with gr.Tab("🩺 Doctor Panel"):
105
- doc_select = gr.Dropdown(choices=doctor_names, label="Select Doctor")
106
- call_btn = gr.Button("Call Next Patient")
107
- call_output = gr.Textbox(label="Now Calling")
108
- queue_table = gr.Dataframe(headers=["ID", "Name", "Queue #", "Status"], interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  refresh_btn = gr.Button("Refresh Queue")
110
 
 
111
  call_btn.click(fn=call_next, inputs=doc_select, outputs=call_output)
112
- refresh_btn.click(fn=lambda d: get_doctor_queue(d), inputs=doc_select, outputs=queue_table)
113
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  # ---------------------------
115
  # LAUNCH APP
116
  # ---------------------------
117
- demo.launch()
 
1
+ # Enhanced Hospital Queue Management System - Gradio App for Hugging Face
2
+ # Features: Multiple Doctors, Patient Queue, Phone Number Status Check, Appointment Scheduling, Estimated Wait Times
3
 
4
  import sqlite3
5
  import gradio as gr
6
+ import pandas as pd
7
+ import time
8
+ from datetime import datetime, timedelta
9
+ import random
10
+ import string
11
+ import os
12
 
13
  # ---------------------------
14
  # DATABASE SETUP
15
  # ---------------------------
16
+ def get_db_connection():
17
+ """Create a database connection with proper error handling"""
18
+ try:
19
+ conn = sqlite3.connect("hospital.db", check_same_thread=False)
20
+ conn.row_factory = sqlite3.Row # Return rows as dictionaries
21
+ return conn
22
+ except sqlite3.Error as e:
23
+ print(f"Database connection error: {e}")
24
+ return None
25
+
26
+ conn = get_db_connection()
27
  cursor = conn.cursor()
28
+
29
+ # Create tables with improved schema
30
  cursor.execute('''CREATE TABLE IF NOT EXISTS doctors (
31
  id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ name TEXT NOT NULL,
33
+ specialty TEXT,
34
+ avg_consultation_time INTEGER DEFAULT 15, # in minutes
35
+ available BOOLEAN DEFAULT 1
36
  )''')
37
+
38
  cursor.execute('''CREATE TABLE IF NOT EXISTS patients (
39
  id INTEGER PRIMARY KEY AUTOINCREMENT,
40
+ name TEXT NOT NULL,
41
+ phone TEXT NOT NULL,
42
+ email TEXT,
43
  symptoms TEXT,
44
+ priority INTEGER DEFAULT 3, # 1=emergency, 2=urgent, 3=normal
45
  doctor_id INTEGER,
46
  queue_number INTEGER,
47
+ token TEXT UNIQUE,
48
+ registration_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
49
+ estimated_start_time TIMESTAMP,
50
  status TEXT DEFAULT 'Waiting',
51
+ completed_time TIMESTAMP,
52
+ notes TEXT,
53
+ FOREIGN KEY (doctor_id) REFERENCES doctors(id)
54
+ )''')
55
+
56
+ cursor.execute('''CREATE TABLE IF NOT EXISTS appointments (
57
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58
+ patient_name TEXT NOT NULL,
59
+ phone TEXT NOT NULL,
60
+ email TEXT,
61
+ doctor_id INTEGER,
62
+ appointment_date TEXT,
63
+ appointment_time TEXT,
64
+ reason TEXT,
65
+ status TEXT DEFAULT 'Scheduled',
66
  FOREIGN KEY (doctor_id) REFERENCES doctors(id)
67
  )''')
68
+
69
+ cursor.execute('''CREATE TABLE IF NOT EXISTS notifications (
70
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
71
+ patient_id INTEGER,
72
+ message TEXT,
73
+ sent_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
74
+ FOREIGN KEY (patient_id) REFERENCES patients(id)
75
+ )''')
76
+
77
  conn.commit()
78
 
79
  # Seed doctors if table is empty
80
  cursor.execute("SELECT COUNT(*) FROM doctors")
81
  if cursor.fetchone()[0] == 0:
82
+ doctors = [
83
+ ("Dr. Smith", "General Medicine", 15, 1),
84
+ ("Dr. Lee", "Pediatrics", 20, 1),
85
+ ("Dr. Patel", "Cardiology", 25, 1),
86
+ ("Dr. Johnson", "Orthopedics", 20, 1),
87
+ ("Dr. Garcia", "Dermatology", 15, 1)
88
+ ]
89
+ cursor.executemany("INSERT INTO doctors (name, specialty, avg_consultation_time, available) VALUES (?, ?, ?, ?)", doctors)
90
  conn.commit()
91
 
92
  # ---------------------------
93
+ # HELPER FUNCTIONS
94
  # ---------------------------
95
+ def generate_token():
96
+ """Generate a unique alphanumeric token for patients"""
97
+ token = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
98
+ return token
99
+
100
+ def calculate_wait_time(doctor_id, queue_position):
101
+ """Calculate estimated wait time based on doctor's avg consultation time and queue position"""
102
+ cursor.execute("SELECT avg_consultation_time FROM doctors WHERE id=?", (doctor_id,))
103
+ avg_time = cursor.fetchone()[0]
104
+
105
+ # Count how many patients are currently in consultation (usually just 1)
106
+ cursor.execute("SELECT COUNT(*) FROM patients WHERE doctor_id=? AND status='In Consultation'", (doctor_id,))
107
+ in_consultation = cursor.fetchone()[0]
108
+
109
+ # Calculate wait time: (patients ahead + in consultation) * avg time
110
+ wait_minutes = (queue_position - 1 + in_consultation) * avg_time
111
+
112
+ # Add some randomness to make it realistic (±20%)
113
+ variation = random.uniform(0.8, 1.2)
114
+ wait_minutes = int(wait_minutes * variation)
115
+
116
+ return wait_minutes
117
+
118
+ def format_wait_time(minutes):
119
+ """Format wait time into hours and minutes"""
120
+ if minutes < 60:
121
+ return f"{minutes} minutes"
122
+ hours = minutes // 60
123
+ mins = minutes % 60
124
+ return f"{hours} hour{'s' if hours > 1 else ''} {mins} minutes"
125
+
126
+ def update_all_wait_times():
127
+ """Update estimated wait times for all waiting patients"""
128
+ # Get all waiting patients
129
+ cursor.execute("""
130
+ SELECT p.id, p.doctor_id, p.queue_number
131
+ FROM patients p
132
+ WHERE p.status='Waiting'
133
+ ORDER BY p.doctor_id, p.queue_number
134
+ """)
135
+ waiting_patients = cursor.fetchall()
136
+
137
+ # Group by doctor
138
+ for doctor_id in set([p[1] for p in waiting_patients]):
139
+ # Get all patients for this doctor
140
+ doctor_patients = [p for p in waiting_patients if p[1] == doctor_id]
141
+
142
+ # Update wait time for each patient
143
+ for patient in doctor_patients:
144
+ wait_minutes = calculate_wait_time(doctor_id, patient[2])
145
+ estimated_time = datetime.now() + timedelta(minutes=wait_minutes)
146
+ cursor.execute(
147
+ "UPDATE patients SET estimated_start_time=? WHERE id=?",
148
+ (estimated_time.strftime('%Y-%m-%d %H:%M:%S'), patient[0])
149
+ )
150
+
151
  conn.commit()
 
152
 
153
+ # ---------------------------
154
+ # CORE FUNCTIONS
155
+ # ---------------------------
156
+ def register_patient(name, phone, email, symptoms, priority, doctor_name):
157
+ """Register a new patient with improved data validation and wait time estimation"""
158
+ # Input validation
159
+ if not name or not phone or not doctor_name:
160
+ return "Error: Name, phone number, and doctor selection are required."
161
+
162
+ try:
163
+ # Get doctor details
164
+ cursor.execute("SELECT id, available FROM doctors WHERE name=?", (doctor_name,))
165
+ doctor_result = cursor.fetchone()
166
+
167
+ if not doctor_result:
168
+ return f"Error: Doctor {doctor_name} not found."
169
+
170
+ doctor_id, is_available = doctor_result
171
+
172
+ if not is_available:
173
+ return f"Sorry, {doctor_name} is currently not available. Please select another doctor."
174
+
175
+ # Check if patient with same phone is already in queue
176
+ cursor.execute("SELECT id FROM patients WHERE phone=? AND status IN ('Waiting', 'In Consultation')", (phone,))
177
+ if cursor.fetchone():
178
+ return "This phone number is already registered in the active queue."
179
+
180
+ # Get next queue number
181
+ cursor.execute("SELECT MAX(queue_number) FROM patients WHERE doctor_id=?", (doctor_id,))
182
+ last_queue = cursor.fetchone()[0]
183
+ next_queue = 1 if last_queue is None else last_queue + 1
184
+
185
+ # Generate unique token
186
+ token = generate_token()
187
+ while True:
188
+ # Check if token already exists
189
+ cursor.execute("SELECT id FROM patients WHERE token=?", (token,))
190
+ if not cursor.fetchone():
191
+ break
192
+ token = generate_token() # Generate new token if exists
193
+
194
+ # Calculate estimated wait time
195
+ wait_minutes = calculate_wait_time(doctor_id, next_queue)
196
+ estimated_time = datetime.now() + timedelta(minutes=wait_minutes)
197
+
198
+ # Insert patient
199
+ cursor.execute("""
200
+ INSERT INTO patients
201
+ (name, phone, email, symptoms, priority, doctor_id, queue_number, token, estimated_start_time, status)
202
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
203
+ """, (name, phone, email, symptoms, priority, doctor_id, next_queue, token,
204
+ estimated_time.strftime('%Y-%m-%d %H:%M:%S'), 'Waiting'))
205
+ conn.commit()
206
+
207
+ # Get patient ID for notification
208
+ patient_id = cursor.lastrowid
209
+
210
+ # Add welcome notification
211
+ notification_msg = f"Welcome {name}! You are registered with {doctor_name}. Your token is {token} and queue number is {next_queue}."
212
+ cursor.execute("INSERT INTO notifications (patient_id, message) VALUES (?, ?)",
213
+ (patient_id, notification_msg))
214
+ conn.commit()
215
+
216
+ # Update wait times for all patients
217
+ update_all_wait_times()
218
+
219
+ # Format response
220
+ wait_time_str = format_wait_time(wait_minutes)
221
+ return f"Registered successfully!\n\nYour token: {token}\nQueue number: {next_queue}\nDoctor: {doctor_name}\nEstimated wait time: {wait_time_str}"
222
+
223
+ except Exception as e:
224
+ conn.rollback()
225
+ return f"An error occurred: {str(e)}"
226
+
227
+ def check_status(phone_or_token):
228
+ """Check patient status by phone or token"""
229
+ if not phone_or_token:
230
+ return "Please enter a phone number or token."
231
+
232
+ try:
233
+ # Try to find by token first (more specific)
234
+ cursor.execute("""
235
+ SELECT
236
+ p.id, p.name, p.token, p.queue_number, p.status, p.estimated_start_time,
237
+ d.name as doctor_name, d.specialty
238
+ FROM patients p
239
+ JOIN doctors d ON p.doctor_id = d.id
240
+ WHERE p.token=? AND p.status IN ('Waiting', 'In Consultation')
241
+ LIMIT 1
242
+ """, (phone_or_token,))
243
+
244
+ result = cursor.fetchone()
245
+
246
+ # If not found by token, try phone
247
+ if not result:
248
+ cursor.execute("""
249
+ SELECT
250
+ p.id, p.name, p.token, p.queue_number, p.status, p.estimated_start_time,
251
+ d.name as doctor_name, d.specialty
252
+ FROM patients p
253
+ JOIN doctors d ON p.doctor_id = d.id
254
+ WHERE p.phone=? AND p.status IN ('Waiting', 'In Consultation')
255
+ ORDER BY p.id DESC LIMIT 1
256
+ """, (phone_or_token,))
257
+ result = cursor.fetchone()
258
+
259
+ if not result:
260
+ return "No active registration found. If you've already completed your visit or haven't registered yet, please check with reception."
261
+
262
+ # Format estimated time
263
+ estimated_time = datetime.strptime(result[5], '%Y-%m-%d %H:%M:%S') if result[5] else None
264
+ now = datetime.now()
265
+
266
+ if estimated_time and estimated_time > now:
267
+ time_diff = estimated_time - now
268
+ wait_minutes = int(time_diff.total_seconds() / 60)
269
+ wait_str = format_wait_time(wait_minutes)
270
+ else:
271
+ wait_str = "You should be called soon"
272
+
273
+ status_info = f"""
274
+ Patient: {result[1]}
275
+ Token: {result[2]}
276
+ Queue #: {result[3]}
277
+ Status: {result[4]}
278
+ Doctor: {result[6]} ({result[7]})
279
+ """
280
+
281
+ if result[4] == 'Waiting':
282
+ status_info += f"Estimated wait: {wait_str}"
283
+
284
+ # Get any notifications
285
+ cursor.execute("""
286
+ SELECT message FROM notifications
287
+ WHERE patient_id=?
288
+ ORDER BY sent_time DESC LIMIT 1
289
+ """, (result[0],))
290
+
291
+ notification = cursor.fetchone()
292
+ if notification:
293
+ status_info += f"\n\nNotification: {notification[0]}"
294
+
295
+ return status_info
296
+
297
+ except Exception as e:
298
+ return f"Error checking status: {str(e)}"
299
 
300
  def get_doctor_queue(doctor_name):
301
+ """Get current queue for a specific doctor"""
302
+ try:
303
+ cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
304
+ doctor_id = cursor.fetchone()[0]
305
+
306
+ cursor.execute("""
307
+ SELECT
308
+ id, name, queue_number, priority,
309
+ strftime('%H:%M', registration_time) as reg_time,
310
+ status, phone, token
311
+ FROM patients
312
+ WHERE doctor_id=? AND status IN ('Waiting', 'In Consultation')
313
+ ORDER BY
314
+ CASE status
315
+ WHEN 'In Consultation' THEN 0
316
+ ELSE 1
317
+ END,
318
+ priority, queue_number
319
+ """, (doctor_id,))
320
+
321
+ rows = cursor.fetchall()
322
+
323
+ # Convert to list of lists for gradio dataframe
324
+ result = []
325
+ for row in rows:
326
+ # Format priority as text
327
+ priority_text = {1: "Emergency", 2: "Urgent", 3: "Normal"}.get(row[3], "Normal")
328
+
329
+ result.append([row[0], row[1], row[2], priority_text, row[4], row[5], row[6], row[7]])
330
+
331
+ return result
332
+
333
+ except Exception as e:
334
+ print(f"Error getting doctor queue: {e}")
335
+ return []
336
+
337
+ def get_doctor_availability():
338
+ """Get the list of available doctors with their specialties"""
339
+ cursor.execute("""
340
+ SELECT id, name, specialty, available
341
+ FROM doctors
342
+ ORDER BY name
343
+ """)
344
+ doctors = cursor.fetchall()
345
+
346
+ # Format for display
347
+ result = []
348
+ for doc in doctors:
349
+ status = "Available" if doc[3] else "Unavailable"
350
+ result.append([doc[0], doc[1], doc[2], status])
351
+
352
+ return result
353
+
354
+ def toggle_doctor_availability(doctor_id):
355
+ """Toggle a doctor's availability status"""
356
+ try:
357
+ if not doctor_id:
358
+ return "Please select a doctor."
359
+
360
+ cursor.execute("SELECT available FROM doctors WHERE id=?", (doctor_id,))
361
+ current_status = cursor.fetchone()[0]
362
+
363
+ # Toggle status
364
+ new_status = 0 if current_status else 1
365
+ cursor.execute("UPDATE doctors SET available=? WHERE id=?", (new_status, doctor_id))
366
+ conn.commit()
367
+
368
+ status_text = "available" if new_status else "unavailable"
369
+ return f"Doctor status updated to {status_text}"
370
+
371
+ except Exception as e:
372
+ conn.rollback()
373
+ return f"Error updating status: {str(e)}"
374
 
375
  def call_next(doctor_name):
376
+ """Call the next patient in queue with notifications"""
377
+ try:
378
+ cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
379
+ doctor_id = cursor.fetchone()[0]
380
+
381
+ # First check if any patient is currently in consultation
382
+ cursor.execute("""
383
+ SELECT id, name
384
+ FROM patients
385
+ WHERE doctor_id=? AND status='In Consultation'
386
+ LIMIT 1
387
+ """, (doctor_id,))
388
+ current_patient = cursor.fetchone()
389
+
390
+ if current_patient:
391
+ return f"{current_patient[1]} is currently in consultation. Please complete their visit before calling the next patient."
392
+
393
+ # Find next patient based on priority and queue number
394
+ cursor.execute("""
395
+ SELECT id, name, token, queue_number, phone
396
+ FROM patients
397
+ WHERE doctor_id=? AND status='Waiting'
398
+ ORDER BY priority, queue_number ASC
399
+ LIMIT 1
400
+ """, (doctor_id,))
401
+
402
+ patient = cursor.fetchone()
403
+
404
+ if not patient:
405
+ return "No patients waiting."
406
+
407
+ # Update patient status
408
  cursor.execute("UPDATE patients SET status='In Consultation' WHERE id=?", (patient[0],))
409
+
410
+ # Create notification
411
+ notification_msg = f"It's your turn! Please proceed to {doctor_name}'s room immediately."
412
+ cursor.execute("INSERT INTO notifications (patient_id, message) VALUES (?, ?)",
413
+ (patient[0], notification_msg))
414
+
415
  conn.commit()
416
+
417
+ # Update wait times for all remaining patients
418
+ update_all_wait_times()
419
+
420
+ # Return formatted message
421
+ return f"Now calling: {patient[1]} (Token: {patient[2]}, Queue #: {patient[3]})"
422
+
423
+ except Exception as e:
424
+ conn.rollback()
425
+ return f"Error calling next patient: {str(e)}"
426
 
427
+ def complete_patient(patient_id, notes=""):
428
+ """Mark patient consultation as completed with optional notes"""
429
+ try:
430
+ if not patient_id:
431
+ return "Please select a patient to mark as completed."
432
+
433
+ # Update patient status and add completion time
434
+ cursor.execute(
435
+ "UPDATE patients SET status='Completed', completed_time=?, notes=? WHERE id=?",
436
+ (datetime.now().strftime('%Y-%m-%d %H:%M:%S'), notes, patient_id)
437
+ )
438
+
439
+ # Get patient info for confirmation
440
+ cursor.execute("SELECT name, token FROM patients WHERE id=?", (patient_id,))
441
+ patient = cursor.fetchone()
442
+
443
+ conn.commit()
444
+
445
+ # Update wait times for all remaining patients
446
+ update_all_wait_times()
447
+
448
+ return f"Patient {patient[0]} (Token: {patient[1]}) marked as completed."
449
+
450
+ except Exception as e:
451
+ conn.rollback()
452
+ return f"Error completing patient visit: {str(e)}"
453
+
454
+ def schedule_appointment(name, phone, email, doctor_name, date, time, reason):
455
+ """Schedule a future appointment"""
456
+ try:
457
+ # Validate inputs
458
+ if not name or not phone or not doctor_name or not date or not time:
459
+ return "Error: Name, phone, doctor, date and time are required fields."
460
+
461
+ # Get doctor ID
462
+ cursor.execute("SELECT id FROM doctors WHERE name=?", (doctor_name,))
463
+ doctor_result = cursor.fetchone()
464
+
465
+ if not doctor_result:
466
+ return f"Error: Doctor {doctor_name} not found."
467
+
468
+ doctor_id = doctor_result[0]
469
+
470
+ # Check if time slot is available
471
+ cursor.execute("""
472
+ SELECT COUNT(*) FROM appointments
473
+ WHERE doctor_id=? AND appointment_date=? AND appointment_time=? AND status='Scheduled'
474
+ """, (doctor_id, date, time))
475
+
476
+ if cursor.fetchone()[0] > 0:
477
+ return f"Sorry, {doctor_name} is already booked at {time} on {date}. Please select another time."
478
+
479
+ # Insert appointment
480
+ cursor.execute("""
481
+ INSERT INTO appointments
482
+ (patient_name, phone, email, doctor_id, appointment_date, appointment_time, reason, status)
483
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'Scheduled')
484
+ """, (name, phone, email, doctor_id, date, time, reason))
485
+
486
+ conn.commit()
487
+
488
+ return f"Appointment scheduled successfully for {name} with {doctor_name} on {date} at {time}."
489
+
490
+ except Exception as e:
491
+ conn.rollback()
492
+ return f"Error scheduling appointment: {str(e)}"
493
+
494
+ def get_appointments(date=None, doctor_name=None):
495
+ """Get list of appointments by date and/or doctor"""
496
+ try:
497
+ query = """
498
+ SELECT
499
+ a.id, a.patient_name, a.phone, a.appointment_time,
500
+ d.name as doctor_name, a.reason, a.status
501
+ FROM appointments a
502
+ JOIN doctors d ON a.doctor_id = d.id
503
+ WHERE 1=1
504
+ """
505
+ params = []
506
+
507
+ if date:
508
+ query += " AND a.appointment_date = ?"
509
+ params.append(date)
510
+
511
+ if doctor_name and doctor_name != "All Doctors":
512
+ query += " AND d.name = ?"
513
+ params.append(doctor_name)
514
+
515
+ query += " ORDER BY a.appointment_time"
516
+
517
+ cursor.execute(query, params)
518
+ appointments = cursor.fetchall()
519
+
520
+ # Format for display
521
+ result = []
522
+ for appt in appointments:
523
+ result.append([appt[0], appt[1], appt[2], appt[3], appt[4], appt[5], appt[6]])
524
+
525
+ return result
526
+
527
+ except Exception as e:
528
+ print(f"Error getting appointments: {e}")
529
+ return []
530
+
531
+ def get_daily_stats():
532
+ """Get daily statistics for the dashboard"""
533
+ try:
534
+ today = datetime.now().strftime('%Y-%m-%d')
535
+
536
+ # Total patients today
537
+ cursor.execute("""
538
+ SELECT COUNT(*) FROM patients
539
+ WHERE date(registration_time) = ?
540
+ """, (today,))
541
+ total_patients = cursor.fetchone()[0]
542
+
543
+ # Waiting patients
544
+ cursor.execute("SELECT COUNT(*) FROM patients WHERE status='Waiting'")
545
+ waiting_patients = cursor.fetchone()[0]
546
+
547
+ # In consultation
548
+ cursor.execute("SELECT COUNT(*) FROM patients WHERE status='In Consultation'")
549
+ in_consultation = cursor.fetchone()[0]
550
+
551
+ # Completed today
552
+ cursor.execute("""
553
+ SELECT COUNT(*) FROM patients
554
+ WHERE status='Completed' AND date(completed_time) = ?
555
+ """, (today,))
556
+ completed_today = cursor.fetchone()[0]
557
+
558
+ # Average wait time today
559
+ cursor.execute("""
560
+ SELECT AVG(
561
+ (julianday(completed_time) - julianday(registration_time)) * 24 * 60
562
+ ) FROM patients
563
+ WHERE status='Completed' AND date(completed_time) = ?
564
+ """, (today,))
565
+ avg_wait_time = cursor.fetchone()[0]
566
+ avg_wait_formatted = f"{int(avg_wait_time)} minutes" if avg_wait_time else "N/A"
567
+
568
+ return {
569
+ "total_patients": total_patients,
570
+ "waiting": waiting_patients,
571
+ "in_consultation": in_consultation,
572
+ "completed": completed_today,
573
+ "avg_wait_time": avg_wait_formatted
574
+ }
575
+
576
+ except Exception as e:
577
+ print(f"Error getting stats: {e}")
578
+ return {
579
+ "total_patients": 0,
580
+ "waiting": 0,
581
+ "in_consultation": 0,
582
+ "completed": 0,
583
+ "avg_wait_time": "N/A"
584
+ }
585
 
586
  # ---------------------------
587
  # GRADIO INTERFACE
588
  # ---------------------------
589
+ def get_doctor_names():
590
+ """Get list of available doctor names"""
591
+ cursor.execute("SELECT name FROM doctors WHERE available=1 ORDER BY name")
592
+ doctors = [row[0] for row in cursor.fetchall()]
593
+ return doctors
594
 
595
+ def get_all_doctor_names():
596
+ """Get list of all doctor names regardless of availability"""
597
+ cursor.execute("SELECT name FROM doctors ORDER BY name")
598
+ doctors = [row[0] for row in cursor.fetchall()]
599
+ return doctors
600
 
601
+ # Create the Gradio interface with theme and improved UI
602
+ theme = gr.themes.Soft(
603
+ primary_hue="blue",
604
+ secondary_hue="indigo",
605
+ )
606
 
607
+ with gr.Blocks(theme=theme, title="Hospital Queue Management System") as demo:
608
+ gr.Markdown("# 🏥 Hospital Queue Management System")
609
+
610
+ # Dashboard Tab
611
+ with gr.Tab("📊 Dashboard"):
612
+ gr.Markdown("### Today's Statistics")
613
+
614
+ with gr.Row():
615
+ total_count = gr.Textbox(label="Total Patients Today")
616
+ waiting_count = gr.Textbox(label="Currently Waiting")
617
+ consulting_count = gr.Textbox(label="In Consultation")
618
+ completed_count = gr.Textbox(label="Completed Today")
619
+ avg_wait = gr.Textbox(label="Average Wait Time")
620
+
621
+ refresh_stats_btn = gr.Button("Refresh Statistics")
622
+
623
+ def update_dashboard():
624
+ stats = get_daily_stats()
625
+ return [
626
+ stats["total_patients"],
627
+ stats["waiting"],
628
+ stats["in_consultation"],
629
+ stats["completed"],
630
+ stats["avg_wait_time"]
631
+ ]
632
+
633
+ refresh_stats_btn.click(
634
+ fn=update_dashboard,
635
+ inputs=[],
636
+ outputs=[total_count, waiting_count, consulting_count, completed_count, avg_wait]
637
+ )
638
+
639
+ # Initialize dashboard
640
+ demo.load(
641
+ fn=update_dashboard,
642
+ inputs=[],
643
+ outputs=[total_count, waiting_count, consulting_count, completed_count, avg_wait]
644
+ )
645
+
646
+ # Patient Registration Tab
647
  with gr.Tab("➕ Register Patient"):
648
+ gr.Markdown("### New Patient Registration")
649
+
650
+ with gr.Row():
651
+ name = gr.Textbox(label="Patient Name*", placeholder="Enter full name")
652
+ phone = gr.Textbox(label="Phone Number*", placeholder="Enter phone number")
653
+
654
  with gr.Row():
655
+ email = gr.Textbox(label="Email (Optional)", placeholder="Enter email address")
656
+ priority = gr.Dropdown(
657
+ choices=[
658
+ {"label": "Normal", "value": 3},
659
+ {"label": "Urgent", "value": 2},
660
+ {"label": "Emergency", "value": 1}
661
+ ],
662
+ label="Priority",
663
+ value=3
664
+ )
665
+
666
+ symptoms = gr.Textbox(
667
+ label="Symptoms/Reason for Visit",
668
+ placeholder="Briefly describe the symptoms or reason for visit",
669
+ lines=3
670
+ )
671
+
672
+ doctor = gr.Dropdown(
673
+ choices=get_doctor_names,
674
+ label="Select Doctor*",
675
+ info="Only shows available doctors"
676
+ )
677
+
678
+ register_btn = gr.Button("Register Patient", variant="primary")
679
+ register_output = gr.Textbox(label="Registration Details", lines=6)
680
+
681
+ register_btn.click(
682
+ fn=register_patient,
683
+ inputs=[name, phone, email, symptoms, priority, doctor],
684
+ outputs=register_output
685
+ )
686
 
687
+ # Status Check Tab
688
  with gr.Tab("🔍 Check My Status"):
689
+ gr.Markdown("### Patient Status Lookup")
690
+
691
+ phone_lookup = gr.Textbox(
692
+ label="Enter Your Phone Number or Token",
693
+ placeholder="Enter phone number or 6-digit token",
694
+ info="You can use either your phone number or token to check your status"
695
+ )
696
+
697
+ check_btn = gr.Button("Check Status", variant="primary")
698
+ status_output = gr.Textbox(label="Your Status", lines=8)
699
+
700
  check_btn.click(fn=check_status, inputs=phone_lookup, outputs=status_output)
701
 
702
+ # Doctor Panel Tab
703
  with gr.Tab("🩺 Doctor Panel"):
704
+ gr.Markdown("### Manage Patient Queue")
705
+
706
+ with gr.Row():
707
+ doc_select = gr.Dropdown(
708
+ choices=get_all_doctor_names,
709
+ label="Select Doctor",
710
+ info="Select doctor to view their queue"
711
+ )
712
+
713
+ with gr.Column():
714
+ call_btn = gr.Button("Call Next Patient", variant="primary")
715
+ call_output = gr.Textbox(label="Now Calling", lines=2)
716
+
717
+ queue_table = gr.Dataframe(
718
+ headers=["ID", "Name", "Queue #", "Priority", "Reg. Time", "Status", "Phone", "Token"],
719
+ datatype=["number", "str", "number", "str", "str", "str", "str", "str"],
720
+ interactive=False,
721
+ label="Current Queue"
722
+ )
723
+
724
+ with gr.Row():
725
+ selected_patient_id = gr.Number(label="Patient ID", precision=0)
726
+ patient_notes = gr.Textbox(label="Consultation Notes", lines=2)
727
+ complete_btn = gr.Button("Complete Visit")
728
+ complete_output = gr.Textbox(label="Result")
729
+
730
  refresh_btn = gr.Button("Refresh Queue")
731
 
732
+ # Set up event handlers
733
  call_btn.click(fn=call_next, inputs=doc_select, outputs=call_output)
734
+
735
+ complete_btn.click(
736
+ fn=complete_patient,
737
+ inputs=[selected_patient_id, patient_notes],
738
+ outputs=complete_output
739
+ )
740
+
741
+ refresh_btn.click(
742
+ fn=lambda d: get_doctor_queue(d),
743
+ inputs=doc_select,
744
+ outputs=queue_table
745
+ )
746
+
747
+ # Update queue when doctor selection changes
748
+ doc_select.change(
749
+ fn=lambda d: get_doctor_queue(d),
750
+ inputs=doc_select,
751
+ outputs=queue_table
752
+ )
753
+
754
+ # Appointment Scheduling Tab
755
+ with gr.Tab("📅 Schedule Appointment"):
756
+ gr.Markdown("### Schedule a Future Appointment")
757
+
758
+ with gr.Row():
759
+ appt_name = gr.Textbox(label="Patient Name*", placeholder="Enter full name")
760
+ appt_phone = gr.Textbox(label="Phone Number*", placeholder="Enter phone number")
761
+
762
+ with gr.Row():
763
+ appt_email = gr.Textbox(label="Email (Optional)", placeholder="Enter email address")
764
+ appt_doctor = gr.Dropdown(
765
+ choices=get_all_doctor_names,
766
+ label="Select Doctor*"
767
+ )
768
+
769
+ with gr.Row():
770
+ appt_date = gr.Textbox(
771
+ label="Appointment Date*",
772
+ placeholder="YYYY-MM-DD",
773
+ info="Enter date in YYYY-MM-DD format"
774
+ )
775
+ appt_time = gr.Dropdown(
776
+ choices=[
777
+ "09:00 AM", "09:30 AM", "10:00 AM", "10:30 AM", "11:00 AM", "11:30 AM",
778
+ "01:00 PM", "01:30 PM", "02:00 PM", "02:30 PM", "03:00 PM", "03:30 PM",
779
+ "04:00 PM", "04:30 PM"
780
+ ],
781
+ label="Appointment Time*"
782
+ )
783
+
784
+ appt_reason = gr.Textbox(
785
+ label="Reason for Appointment",
786
+ placeholder="Briefly describe the reason for appointment",
787
+ lines=3
788
+ )
789
+
790
+ schedule_btn = gr.Button("Schedule Appointment", variant="primary")
791
+ schedule_output = gr.Textbox(label="Appointment Details")
792
+
793
+ schedule_btn.click(
794
+ fn=schedule_appointment,
795
+ inputs=[appt_name, appt_phone, appt_email, appt_doctor, appt_date, appt_time, appt_reason],
796
+ outputs=schedule_output
797
+ )
798
+
799
+ # Appointment List
800
+ gr.Markdown("### View Appointments")
801
+
802
+ with gr.Row():
803
+ view_date = gr.Textbox(
804
+ label="Date (YYYY-MM-DD)",
805
+ placeholder="Leave empty for all dates",
806
+ value=datetime.now().strftime('%Y-%m-%d')
807
+ )
808
+ view_doctor = gr.Dropdown(
809
+ choices=["All Doctors"] + get_all_doctor_names(),
810
+ label="Doctor",
811
+ value="All Doctors"
812
+ )
813
+ view_btn = gr.Button("View Appointments")
814
+
815
+ appointments_table = gr.Dataframe(
816
+ headers=["ID", "Patient Name", "Phone", "Time", "Doctor", "Reason", "Status"],
817
+ interactive=False,
818
+ label="Appointments"
819
+ )
820
+
821
+ view_btn.click(
822
+ fn=get_appointments,
823
+ inputs=[view_date, view_doctor],
824
+ outputs=appointments_table
825
+ )
826
+
827
+ # Admin Panel Tab
828
+ with gr.Tab("⚙️ Admin Panel"):
829
+ gr.Markdown("### Manage Doctors")
830
+
831
+ # Doctor availability management
832
+ doctors_table = gr.Dataframe(
833
+ headers=["ID", "Name", "Specialty", "Status"],
834
+ interactive=False,
835
+ label="Doctors List"
836
+ )
837
+
838
+ with gr.Row():
839
+ toggle_doctor_id = gr.Number(label="Doctor ID", precision=0)
840
+ toggle_btn = gr.Button("Toggle Availability")
841
+ toggle_output = gr.Textbox(label="Result")
842
+
843
+ refresh_doctors_btn = gr.Button("Refresh Doctors List")
844
+
845
+ # Set up event handlers
846
+ toggle_btn.click(
847
+ fn=toggle_doctor_availability,
848
+ inputs=toggle_doctor_id,
849
+ outputs=toggle_output
850
+ )
851
+
852
+ refresh_doctors_btn.click(
853
+ fn=get_doctor_availability,
854
+ inputs=[],
855
+ outputs=doctors_table
856
+ )
857
+
858
+ # Initialize doctors table
859
+ demo.load(fn=get_doctor_availability, inputs=[], outputs=doctors_table)
860
+
861
+ # System monitoring section
862
+ gr.Markdown("### System Monitoring")
863
+
864
+ with gr.Row():
865
+ db_size = gr.Textbox(label="Database Size")
866
+ system_status = gr.Textbox(label="System Status")
867
+
868
+ def check_system_status():
869
+ """Check system status and database size"""
870
+ try:
871
+ # Get database file size
872
+ if os.path.exists("hospital.db"):
873
+ size_bytes = os.path.getsize("hospital.db")
874
+ size_kb = size_bytes / 1024
875
+ if size_kb < 1024:
876
+ size_str = f"{size_kb:.2f} KB"
877
+ else:
878
+ size_mb = size_kb / 1024
879
+ size_str = f"{size_mb:.2f} MB"
880
+ else:
881
+ size_str = "Database file not found"
882
+
883
+ # Check database connection
884
+ if conn:
885
+ try:
886
+ cursor.execute("SELECT COUNT(*) FROM doctors")
887
+ cursor.fetchone()
888
+ status = "System operational - Database connection OK"
889
+ except:
890
+ status = "Database connection error"
891
+ else:
892
+ status = "Database connection not established"
893
+
894
+ return size_str, status
895
+
896
+ except Exception as e:
897
+ return "Error getting size", f"Error: {str(e)}"
898
+
899
+ check_system_btn = gr.Button("Check System Status")
900
+ check_system_btn.click(
901
+ fn=check_system_status,
902
+ inputs=[],
903
+ outputs=[db_size, system_status]
904
+ )
905
+
906
+ # Backup & Maintenance
907
+ gr.Markdown("### Backup & Maintenance")
908
+
909
+ def backup_database():
910
+ """Create a backup of the database"""
911
+ try:
912
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
913
+ backup_file = f"hospital_backup_{timestamp}.db"
914
+
915
+ # Create connection to source and destination databases
916
+ source_conn = sqlite3.connect("hospital.db")
917
+ backup_conn = sqlite3.connect(backup_file)
918
+
919
+ # Backup
920
+ source_conn.backup(backup_conn)
921
+
922
+ # Close connections
923
+ source_conn.close()
924
+ backup_conn.close()
925
+
926
+ return f"Backup created successfully: {backup_file}"
927
+
928
+ except Exception as e:
929
+ return f"Backup failed: {str(e)}"
930
+
931
+ backup_btn = gr.Button("Create Database Backup")
932
+ backup_output = gr.Textbox(label="Backup Result")
933
+
934
+ backup_btn.click(fn=backup_database, inputs=[], outputs=backup_output)
935
+
936
+ # Emergency queue reset
937
+ def reset_queue():
938
+ """Reset the entire patient queue for emergency situations"""
939
+ try:
940
+ cursor.execute("UPDATE patients SET status='Completed' WHERE status IN ('Waiting', 'In Consultation')")
941
+ conn.commit()
942
+ affected = cursor.rowcount
943
+ return f"Queue reset successfully. {affected} patients marked as completed."
944
+ except Exception as e:
945
+ conn.rollback()
946
+ return f"Queue reset failed: {str(e)}"
947
+
948
+ with gr.Row():
949
+ gr.Markdown("### ⚠️ Emergency Queue Reset ⚠️")
950
+ with gr.Row():
951
+ reset_confirm = gr.Checkbox(label="I confirm I want to reset all queues")
952
+ reset_btn = gr.Button("Reset All Queues", variant="stop")
953
+ reset_output = gr.Textbox(label="Reset Result")
954
+
955
+ def safe_reset_queue(confirmed):
956
+ if confirmed:
957
+ return reset_queue()
958
+ else:
959
+ return "Please check the confirmation box to reset queues"
960
+
961
+ reset_btn.click(fn=safe_reset_queue, inputs=reset_confirm, outputs=reset_output)
962
+
963
  # ---------------------------
964
  # LAUNCH APP
965
  # ---------------------------
966
+ demo.launch()