vrindagopinath commited on
Commit
09edfea
·
verified ·
1 Parent(s): a004b52

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +727 -0
app.py ADDED
@@ -0,0 +1,727 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Complete Malayalam Hospital Booking Chatbot using Llama 3.1-8B-Instruct
2
+ # with HuggingFace Transformers Library in Google Colab
3
+
4
+ import os
5
+ import json
6
+ import gradio as gr
7
+ import torch
8
+ import datetime
9
+ import pytz
10
+ import uuid
11
+ import re
12
+ import time
13
+ import random
14
+ from transformers import AutoModelForCausalLM, AutoTokenizer
15
+ from google.colab import auth
16
+ from googleapiclient.discovery import build
17
+
18
+ # Set up timezone for India
19
+ IST = pytz.timezone('Asia/Kolkata')
20
+
21
+ # ===== CONFIGURATION =====
22
+
23
+ # Path to store the model locally (to avoid re-downloading)
24
+ MODEL_PATH = "/content/llama-3.1-8b-instruct"
25
+
26
+ # Replace with your actual Hugging Face token
27
+ HF_TOKEN = "" # Will be set via Colab input
28
+
29
+ # Google Calendar API scopes
30
+ SCOPES = ['https://www.googleapis.com/auth/calendar']
31
+
32
+ # Available doctors and departments for booking
33
+ available_doctors = {
34
+ "cardiology": ["Dr. Anoop Menon", "Dr. Priya Nair"],
35
+ "orthopedics": ["Dr. Rajesh Kumar", "Dr. Meera Pillai"],
36
+ "neurology": ["Dr. Vinod Thomas", "Dr. Lakshmi Nair"],
37
+ "pediatrics": ["Dr. Suresh Babu", "Dr. Anjali Krishnan"],
38
+ "general": ["Dr. Joseph Mathew", "Dr. Deepa Varma"]
39
+ }
40
+
41
+ # Hospital database simulation
42
+ appointments_db = {}
43
+
44
+ # ===== FUNCTION DEFINITIONS =====
45
+
46
+ function_definitions = [
47
+ {
48
+ "name": "check_doctor_availability",
49
+ "description": "Check which doctors are available in a specific department",
50
+ "parameters": {
51
+ "type": "object",
52
+ "properties": {
53
+ "department": {
54
+ "type": "string",
55
+ "description": "The hospital department (cardiology, orthopedics, neurology, pediatrics, general)"
56
+ }
57
+ },
58
+ "required": ["department"]
59
+ }
60
+ },
61
+ {
62
+ "name": "check_time_slots",
63
+ "description": "Check available time slots for a specific doctor on a specific date",
64
+ "parameters": {
65
+ "type": "object",
66
+ "properties": {
67
+ "doctor_name": {
68
+ "type": "string",
69
+ "description": "The name of the doctor"
70
+ },
71
+ "date": {
72
+ "type": "string",
73
+ "description": "The date in YYYY-MM-DD format"
74
+ }
75
+ },
76
+ "required": ["doctor_name", "date"]
77
+ }
78
+ },
79
+ {
80
+ "name": "book_appointment",
81
+ "description": "Book an appointment with a doctor and add it to Google Calendar",
82
+ "parameters": {
83
+ "type": "object",
84
+ "properties": {
85
+ "patient_name": {
86
+ "type": "string",
87
+ "description": "The name of the patient"
88
+ },
89
+ "patient_phone": {
90
+ "type": "string",
91
+ "description": "The phone number of the patient"
92
+ },
93
+ "doctor_name": {
94
+ "type": "string",
95
+ "description": "The name of the doctor"
96
+ },
97
+ "department": {
98
+ "type": "string",
99
+ "description": "The hospital department"
100
+ },
101
+ "date": {
102
+ "type": "string",
103
+ "description": "The date in YYYY-MM-DD format"
104
+ },
105
+ "time": {
106
+ "type": "string",
107
+ "description": "The time of the appointment (e.g., '10:00 AM')"
108
+ },
109
+ "description": {
110
+ "type": "string",
111
+ "description": "Brief description of the medical issue"
112
+ }
113
+ },
114
+ "required": ["patient_name", "patient_phone", "doctor_name", "department", "date", "time"]
115
+ }
116
+ },
117
+ {
118
+ "name": "cancel_appointment",
119
+ "description": "Cancel an existing appointment",
120
+ "parameters": {
121
+ "type": "object",
122
+ "properties": {
123
+ "appointment_id": {
124
+ "type": "string",
125
+ "description": "The ID of the appointment to cancel"
126
+ },
127
+ "patient_phone": {
128
+ "type": "string",
129
+ "description": "The phone number of the patient for verification"
130
+ }
131
+ },
132
+ "required": ["appointment_id", "patient_phone"]
133
+ }
134
+ }
135
+ ]
136
+
137
+ # ===== FUNCTION IMPLEMENTATIONS =====
138
+
139
+ def check_doctor_availability(department):
140
+ """Check which doctors are available in a specific department"""
141
+ if department.lower() in available_doctors:
142
+ return {
143
+ "available": True,
144
+ "doctors": available_doctors[department.lower()]
145
+ }
146
+ else:
147
+ return {
148
+ "available": False,
149
+ "message": "Department not found",
150
+ "available_departments": list(available_doctors.keys())
151
+ }
152
+
153
+ def check_time_slots(doctor_name, date):
154
+ """Check available time slots for a specific doctor on a specific date"""
155
+ # Available time slots
156
+ all_slots = [
157
+ "09:00 AM", "09:30 AM", "10:00 AM", "10:30 AM",
158
+ "11:00 AM", "11:30 AM", "12:00 PM", "02:00 PM",
159
+ "02:30 PM", "03:00 PM", "03:30 PM", "04:00 PM"
160
+ ]
161
+
162
+ # In a real implementation, this would check a database
163
+ # For this example, we'll simulate some slots being taken
164
+ taken_slots = random.sample(all_slots, 3) # Randomly mark 3 slots as taken
165
+
166
+ available_slots = [slot for slot in all_slots if slot not in taken_slots]
167
+
168
+ return {
169
+ "date": date,
170
+ "doctor": doctor_name,
171
+ "available_slots": available_slots
172
+ }
173
+
174
+ def book_appointment(appointment_details, calendar_service):
175
+ """Book an appointment with a doctor and add it to Google Calendar"""
176
+ try:
177
+ # Validate the appointment details first
178
+ doctor_exists = False
179
+ for dept_doctors in available_doctors.values():
180
+ if appointment_details["doctor_name"] in dept_doctors:
181
+ doctor_exists = True
182
+ break
183
+
184
+ if not doctor_exists:
185
+ return {
186
+ "success": False,
187
+ "message": "Doctor not found"
188
+ }
189
+
190
+ # Parse date and time
191
+ date_parts = appointment_details["date"].split('-')
192
+ year, month, day = int(date_parts[0]), int(date_parts[1]), int(date_parts[2])
193
+
194
+ time_parts = appointment_details["time"].split(' ')
195
+ time = time_parts[0]
196
+ meridian = time_parts[1]
197
+
198
+ hours, minutes = map(int, time.split(':'))
199
+
200
+ if meridian == 'PM' and hours != 12:
201
+ hours += 12
202
+ if meridian == 'AM' and hours == 12:
203
+ hours = 0
204
+
205
+ start_datetime = datetime.datetime(year, month, day, hours, minutes, 0, tzinfo=IST)
206
+ end_datetime = start_datetime + datetime.timedelta(minutes=30) # 30 minutes appointment
207
+
208
+ # Create the calendar event
209
+ event = {
210
+ 'summary': f"Medical appointment with {appointment_details['doctor_name']}",
211
+ 'location': 'City Hospital, Kochi, Kerala',
212
+ 'description': appointment_details.get('description', 'Regular checkup'),
213
+ 'start': {
214
+ 'dateTime': start_datetime.isoformat(),
215
+ 'timeZone': 'Asia/Kolkata',
216
+ },
217
+ 'end': {
218
+ 'dateTime': end_datetime.isoformat(),
219
+ 'timeZone': 'Asia/Kolkata',
220
+ },
221
+ 'attendees': [
222
+ {'email': 'doctor@cityhospital.com'},
223
+ {'email': 'patient@example.com'} # In a real app, use actual email
224
+ ],
225
+ 'reminders': {
226
+ 'useDefault': False,
227
+ 'overrides': [
228
+ {'method': 'email', 'minutes': 24 * 60},
229
+ {'method': 'popup', 'minutes': 60},
230
+ ],
231
+ },
232
+ }
233
+
234
+ # Add to Google Calendar
235
+ if calendar_service:
236
+ try:
237
+ event = calendar_service.events().insert(calendarId='primary', body=event).execute()
238
+ appointment_id = event['id']
239
+ except Exception as e:
240
+ print(f"Calendar service error: {e}")
241
+ # Generate a mock ID if calendar service fails
242
+ appointment_id = str(uuid.uuid4())
243
+ else:
244
+ # If no calendar service, generate a mock ID
245
+ appointment_id = str(uuid.uuid4())
246
+
247
+ # Store in local database
248
+ appointments_db[appointment_id] = {
249
+ "patient_name": appointment_details["patient_name"],
250
+ "patient_phone": appointment_details["patient_phone"],
251
+ "doctor_name": appointment_details["doctor_name"],
252
+ "department": appointment_details["department"],
253
+ "date": appointment_details["date"],
254
+ "time": appointment_details["time"],
255
+ "description": appointment_details.get("description", ""),
256
+ }
257
+
258
+ return {
259
+ "success": True,
260
+ "appointment_id": appointment_id,
261
+ "message": "Appointment successfully booked",
262
+ "details": {
263
+ "doctor": appointment_details["doctor_name"],
264
+ "department": appointment_details["department"],
265
+ "date": appointment_details["date"],
266
+ "time": appointment_details["time"],
267
+ "location": 'City Hospital, Kochi, Kerala'
268
+ }
269
+ }
270
+ except Exception as e:
271
+ print(f"Error in book_appointment: {e}")
272
+ return {
273
+ "success": False,
274
+ "message": f"Failed to book appointment: {str(e)}"
275
+ }
276
+
277
+ def cancel_appointment(appointment_id, patient_phone, calendar_service):
278
+ """Cancel an existing appointment"""
279
+ try:
280
+ # Check if appointment exists in our database
281
+ if appointment_id not in appointments_db:
282
+ return {
283
+ "success": False,
284
+ "message": "Appointment not found"
285
+ }
286
+
287
+ # Verify patient phone
288
+ if appointments_db[appointment_id]["patient_phone"] != patient_phone:
289
+ return {
290
+ "success": False,
291
+ "message": "Patient phone number does not match our records"
292
+ }
293
+
294
+ # Delete from Google Calendar
295
+ if calendar_service:
296
+ try:
297
+ calendar_service.events().delete(calendarId='primary', eventId=appointment_id).execute()
298
+ except Exception as e:
299
+ print(f"Error deleting from calendar: {e}")
300
+ # Continue anyway to delete from local database
301
+
302
+ # Remove from local database
303
+ del appointments_db[appointment_id]
304
+
305
+ return {
306
+ "success": True,
307
+ "message": "Appointment successfully cancelled"
308
+ }
309
+ except Exception as e:
310
+ return {
311
+ "success": False,
312
+ "message": f"Failed to cancel appointment: {str(e)}"
313
+ }
314
+
315
+ # ===== GOOGLE CALENDAR AUTHENTICATION =====
316
+
317
+ def get_calendar_service():
318
+ """Authenticate and return the Google Calendar service"""
319
+ creds = None
320
+
321
+ try:
322
+ # Authenticate using Colab's auth helper
323
+ auth.authenticate_user()
324
+
325
+ # Get credentials from the authenticated Colab user
326
+ from google.auth import default
327
+ creds, _ = default()
328
+
329
+ # Build and return the service
330
+ service = build('calendar', 'v3', credentials=creds)
331
+ return service
332
+ except Exception as e:
333
+ print(f"Error authenticating with Google Calendar: {e}")
334
+ print("Continuing without Google Calendar integration.")
335
+ return None
336
+
337
+ # ===== LLAMA 3.1 MODEL SETUP =====
338
+
339
+ def load_llama_model():
340
+ """Load the Llama 3.1 model and tokenizer"""
341
+ model_name = "meta-llama/Meta-Llama-3.1-8B-Instruct"
342
+
343
+ print("Loading Llama 3.1 model and tokenizer...")
344
+
345
+ try:
346
+ # Check if model is already downloaded
347
+ if os.path.exists(MODEL_PATH):
348
+ print(f"Loading model from local path: {MODEL_PATH}")
349
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
350
+ model = AutoModelForCausalLM.from_pretrained(
351
+ MODEL_PATH,
352
+ torch_dtype=torch.bfloat16,
353
+ device_map="auto",
354
+ low_cpu_mem_usage=True
355
+ )
356
+ else:
357
+ print(f"Downloading model from Hugging Face Hub")
358
+ tokenizer = AutoTokenizer.from_pretrained(model_name, token=HF_TOKEN)
359
+ model = AutoModelForCausalLM.from_pretrained(
360
+ model_name,
361
+ torch_dtype=torch.bfloat16,
362
+ device_map="auto",
363
+ low_cpu_mem_usage=True,
364
+ token=HF_TOKEN
365
+ )
366
+
367
+ # Save model locally to avoid re-downloading
368
+ print(f"Saving model to: {MODEL_PATH}")
369
+ tokenizer.save_pretrained(MODEL_PATH)
370
+ model.save_pretrained(MODEL_PATH)
371
+
372
+ print("Model loaded successfully!")
373
+ return model, tokenizer
374
+
375
+ except Exception as e:
376
+ print(f"Error loading model: {e}")
377
+ return None, None
378
+
379
+ # ===== CHAT PROCESSING =====
380
+
381
+ def format_prompt_with_functions(messages, system_prompt):
382
+ """Format the prompt for Llama 3.1 with function definitions"""
383
+ # Add function definitions to system prompt
384
+ full_system_prompt = system_prompt + "\n\n"
385
+ full_system_prompt += "You have access to the following functions:\n"
386
+
387
+ for func in function_definitions:
388
+ full_system_prompt += f"- {func['name']}: {func['description']}\n"
389
+ full_system_prompt += " Parameters:\n"
390
+ for param_name, param_info in func['parameters']['properties'].items():
391
+ required = "required" if param_name in func['parameters'].get('required', []) else "optional"
392
+ full_system_prompt += f" - {param_name} ({required}): {param_info.get('description', '')}\n"
393
+
394
+ full_system_prompt += "\nIf the user's request can be addressed by calling one of these functions, respond in the following JSON format:\n"
395
+ full_system_prompt += '```json\n{"function_call": {"name": "function_name", "arguments": {"arg1": "value1", "arg2": "value2"}}}\n```\n'
396
+ full_system_prompt += "Otherwise, respond conversationally."
397
+
398
+ # Format conversation history
399
+ formatted_messages = [
400
+ {"role": "system", "content": full_system_prompt}
401
+ ]
402
+
403
+ # Add conversation history
404
+ for message in messages:
405
+ if message["role"] == "function":
406
+ # Convert function results to assistant format for Llama 3.1
407
+ formatted_messages.append({
408
+ "role": "assistant",
409
+ "content": f"I'll process the function result: {message['content']}"
410
+ })
411
+ else:
412
+ formatted_messages.append(message)
413
+
414
+ return formatted_messages
415
+
416
+ def extract_function_call(response_text):
417
+ """Extract function call from model response"""
418
+ # Look for JSON block in the response
419
+ json_pattern = r'```json\s*(.*?)\s*```'
420
+ json_matches = re.findall(json_pattern, response_text, re.DOTALL)
421
+
422
+ if not json_matches:
423
+ # Try alternative pattern without markdown
424
+ json_pattern = r'({.*"function_call".*})'
425
+ json_matches = re.findall(json_pattern, response_text, re.DOTALL)
426
+
427
+ if json_matches:
428
+ try:
429
+ for json_str in json_matches:
430
+ parsed_json = json.loads(json_str.strip())
431
+ if "function_call" in parsed_json:
432
+ function_call = parsed_json["function_call"]
433
+ return {
434
+ "id": str(uuid.uuid4()),
435
+ "name": function_call["name"],
436
+ "arguments": function_call["arguments"]
437
+ }
438
+ except json.JSONDecodeError:
439
+ print(f"Failed to parse JSON: {json_matches[0]}")
440
+
441
+ return None
442
+
443
+ def process_chat(message, chat_history, language, model_tokenizer_calendar):
444
+ """Process a chat message, calling functions when necessary"""
445
+ model, tokenizer, calendar_service = model_tokenizer_calendar
446
+
447
+ try:
448
+ # Create system prompt based on language preference
449
+ system_prompt = f"""You are a hospital booking assistant for City Hospital in Kerala. You can understand and respond fluently in Malayalam and English.
450
+
451
+ For Malayalam speakers, introduce yourself as: "ഹലോ, ഞാൻ സിറ്റി ഹോസ്പിറ്റലിന്റെ ഓൺലൈൻ അസിസ്റ്റന്റ് ആണ്. എങ്ങനെ സഹായിക്കാൻ കഴിയും?"
452
+
453
+ Be polite and helpful. You can assist with checking doctor availability, booking appointments, and answering general questions about the hospital services.
454
+
455
+ For medical questions that require diagnosis, always advise patients to consult a doctor directly.
456
+
457
+ When booking appointments, collect all necessary information: patient name, phone number, department, doctor, date, and time.
458
+
459
+ Current language preference: {language}"""
460
+
461
+ # Build message history from chat history
462
+ messages = []
463
+ for user_msg, bot_msg in chat_history:
464
+ messages.append({"role": "user", "content": user_msg})
465
+ messages.append({"role": "assistant", "content": bot_msg})
466
+
467
+ # Add current message
468
+ messages.append({"role": "user", "content": message})
469
+
470
+ # Format messages with function calling info
471
+ formatted_messages = format_prompt_with_functions(messages, system_prompt)
472
+
473
+ # Generate model response
474
+ inputs = tokenizer.apply_chat_template(
475
+ formatted_messages,
476
+ tokenize=True,
477
+ add_generation_prompt=True,
478
+ return_tensors="pt"
479
+ ).to(model.device)
480
+
481
+ outputs = model.generate(
482
+ inputs,
483
+ max_new_tokens=1024,
484
+ temperature=0.7,
485
+ top_p=0.9,
486
+ do_sample=True
487
+ )
488
+
489
+ response_text = tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True)
490
+
491
+ # Check if response contains a function call
492
+ function_call = extract_function_call(response_text)
493
+
494
+ if function_call:
495
+ # Extract non-JSON response part for context (if any)
496
+ response_context = response_text.split("```")[0].strip() if "```" in response_text else ""
497
+
498
+ # Execute the appropriate function
499
+ function_name = function_call["name"]
500
+ function_args = function_call["arguments"]
501
+
502
+ function_result = None
503
+ if function_name == "check_doctor_availability" and "department" in function_args:
504
+ function_result = check_doctor_availability(function_args["department"])
505
+ elif function_name == "check_time_slots" and "doctor_name" in function_args and "date" in function_args:
506
+ function_result = check_time_slots(function_args["doctor_name"], function_args["date"])
507
+ elif function_name == "book_appointment":
508
+ function_result = book_appointment(function_args, calendar_service)
509
+ elif function_name == "cancel_appointment" and "appointment_id" in function_args and "patient_phone" in function_args:
510
+ function_result = cancel_appointment(function_args["appointment_id"], function_args["patient_phone"], calendar_service)
511
+ else:
512
+ function_result = {"error": "Invalid function call or missing parameters"}
513
+
514
+ # Add the function result to messages
515
+ messages.append({
516
+ "role": "assistant",
517
+ "content": response_context,
518
+ })
519
+
520
+ messages.append({
521
+ "role": "function",
522
+ "name": function_name,
523
+ "content": json.dumps(function_result)
524
+ })
525
+
526
+ # Format messages for second call
527
+ formatted_messages = format_prompt_with_functions(messages, system_prompt)
528
+
529
+ # Generate second response
530
+ inputs = tokenizer.apply_chat_template(
531
+ formatted_messages,
532
+ tokenize=True,
533
+ add_generation_prompt=True,
534
+ return_tensors="pt"
535
+ ).to(model.device)
536
+
537
+ outputs = model.generate(
538
+ inputs,
539
+ max_new_tokens=1024,
540
+ temperature=0.7,
541
+ top_p=0.9,
542
+ do_sample=True
543
+ )
544
+
545
+ second_response = tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True)
546
+
547
+ # Update chat history
548
+ new_chat_history = chat_history + [(message, second_response)]
549
+
550
+ return second_response, new_chat_history
551
+ else:
552
+ # No function call, just return the response
553
+ # Update chat history
554
+ new_chat_history = chat_history + [(message, response_text)]
555
+
556
+ return response_text, new_chat_history
557
+
558
+ except Exception as e:
559
+ print(f"Error in process_chat: {e}")
560
+ error_msg = f"Sorry, I encountered an error. Please try again. (Error: {str(e)})"
561
+ return error_msg, chat_history + [(message, error_msg)]
562
+
563
+ # ===== GRADIO INTERFACE =====
564
+
565
+ def create_gradio_interface(model, tokenizer, calendar_service):
566
+ """Create the Gradio interface for the chatbot"""
567
+
568
+ with gr.Blocks(css="""
569
+ .gradio-container {max-width: 800px !important}
570
+ .chat-window {height: 600px !important; overflow-y: auto}
571
+ .language-selector {text-align: right; margin-bottom: 10px}
572
+ """) as demo:
573
+ gr.Markdown("# City Hospital - Hospital Booking Assistant")
574
+ gr.Markdown("### മലയാളത്തിലും ഇംഗ്ലീഷിലും സംസാരിക്കുന്ന ആശുപത്രി ബുക്കിംഗ് സഹായി")
575
+
576
+ with gr.Row():
577
+ with gr.Column():
578
+ language = gr.Radio(
579
+ ["English", "Malayalam"],
580
+ label="Select Language",
581
+ value="English",
582
+ interactive=True
583
+ )
584
+
585
+ chatbot = gr.Chatbot(
586
+ [],
587
+ elem_id="chatbot",
588
+ label="Chat with Hospital Assistant",
589
+ height=500
590
+ )
591
+
592
+ with gr.Row():
593
+ msg = gr.Textbox(
594
+ show_label=False,
595
+ placeholder="Type your message here...",
596
+ container=False
597
+ )
598
+ submit = gr.Button("Send")
599
+
600
+ with gr.Row():
601
+ clear = gr.Button("Clear Conversation")
602
+
603
+ # Provide instructions
604
+ with gr.Accordion("Instructions", open=False):
605
+ gr.Markdown("""
606
+ ## How to use this hospital booking assistant:
607
+
608
+ 1. You can chat in English or Malayalam - select your preferred language above.
609
+ 2. Ask about doctor availability in different departments.
610
+ 3. Check available time slots for appointments.
611
+ 4. Book appointments by providing patient details.
612
+ 5. Cancel existing appointments if needed.
613
+
614
+ ### Example questions in English:
615
+ - Which doctors are available in the cardiology department?
616
+ - I need an appointment with Dr. Priya Nair tomorrow.
617
+ - What are your hospital visiting hours?
618
+
619
+ ### Example questions in Malayalam:
620
+ - കാർഡിയോളജി വിഭാഗത്തിൽ ഏതൊക്കെ ഡോക്ടർമാർ ലഭ്യമാണ്?
621
+ - എനിക്ക് നാളെ ഡോ. പ്രിയ നായരുമായി ഒരു അപ്പോയിന്റ്മെന്റ് വേണം.
622
+ - നിങ്ങളുടെ ആശുപത്രി സന്ദർശന സമയങ്ങൾ എന്തൊക്കെയാണ്?
623
+ """)
624
+
625
+ chat_history = gr.State([])
626
+
627
+ # Set up event handlers
628
+ submit.click(
629
+ process_chat,
630
+ inputs=[msg, chat_history, language, gr.State((model, tokenizer, calendar_service))],
631
+ outputs=[chatbot, chat_history]
632
+ ).then(
633
+ lambda: "",
634
+ None,
635
+ msg
636
+ )
637
+
638
+ msg.submit(
639
+ process_chat,
640
+ inputs=[msg, chat_history, language, gr.State((model, tokenizer, calendar_service))],
641
+ outputs=[chatbot, chat_history]
642
+ ).then(
643
+ lambda: "",
644
+ None,
645
+ msg
646
+ )
647
+
648
+ clear.click(
649
+ lambda: ([], []),
650
+ inputs=None,
651
+ outputs=[chatbot, chat_history]
652
+ )
653
+
654
+ # When language changes, add a system message
655
+ def on_language_change(lang, history):
656
+ if lang == "Malayalam":
657
+ welcome = "ഹലോ, ഞാൻ സിറ്റി ഹോസ്പിറ്റലിന്റെ ഓൺലൈൻ അസിസ്റ്റന്റ് ആണ്. എങ്ങനെ സഹായിക്കാൻ കഴിയും?"
658
+ else:
659
+ welcome = "Hello! I'm the online assistant for City Hospital. How can I help you today?"
660
+
661
+ if not history or history[-1][1] != welcome:
662
+ return history + [("", welcome)]
663
+ return history
664
+
665
+ language.change(
666
+ on_language_change,
667
+ inputs=[language, chat_history],
668
+ outputs=[chat_history]
669
+ ).then(
670
+ lambda history: (history, history),
671
+ inputs=[chat_history],
672
+ outputs=[chatbot, chat_history]
673
+ )
674
+
675
+ # Initial welcome message
676
+ demo.load(
677
+ lambda: ([("", "Hello! I'm the online assistant for City Hospital. How can I help you today?")],
678
+ [("", "Hello! I'm the online assistant for City Hospital. How can I help you today?")]),
679
+ inputs=None,
680
+ outputs=[chatbot, chat_history]
681
+ )
682
+
683
+ return demo
684
+
685
+ # ===== MAIN EXECUTION =====
686
+
687
+ def main():
688
+ global HF_TOKEN
689
+
690
+ print("===== Malayalam Hospital Booking Chatbot =====")
691
+ print("Using Llama 3.1-8B-Instruct with Google Calendar integration")
692
+
693
+ # Install required packages in Colab
694
+ try:
695
+ import IPython
696
+ print("Installing required packages...")
697
+ IPython.get_ipython().system('pip install transformers>=4.37.0')
698
+ IPython.get_ipython().system('pip install accelerate>=0.25.0')
699
+ IPython.get_ipython().system('pip install bitsandbytes>=0.41.0')
700
+ IPython.get_ipython().system('pip install sentencepiece>=0.1.99')
701
+ IPython.get_ipython().system('pip install gradio==3.50.2')
702
+ IPython.get_ipython().system('pip install google-auth google-auth-oauthlib google-auth-httplib2')
703
+ IPython.get_ipython().system('pip install google-api-python-client')
704
+ IPython.get_ipython().system('pip install pytz')
705
+ print("All packages installed successfully!")
706
+ except:
707
+ print("Not running in IPython environment or packages already installed.")
708
+
709
+ # Get HF token from user input
710
+ HF_TOKEN = input("Enter your Hugging Face token with access to meta-llama models: ")
711
+
712
+ # Load the Llama model and tokenizer
713
+ model, tokenizer = load_llama_model()
714
+
715
+ if model is None or tokenizer is None:
716
+ print("Failed to load the model. Please check your Hugging Face token and try again.")
717
+ return
718
+
719
+ # Get calendar service
720
+ calendar_service = get_calendar_service()
721
+
722
+ # Create and launch the Gradio interface
723
+ demo = create_gradio_interface(model, tokenizer, calendar_service)
724
+ demo.launch(share=True, debug=True)
725
+
726
+ if __name__ == "__main__":
727
+ main()