simran0608 commited on
Commit
f3a65ad
·
verified ·
1 Parent(s): 81eeebe

Delete functions.py

Browse files
Files changed (1) hide show
  1. functions.py +0 -489
functions.py DELETED
@@ -1,489 +0,0 @@
1
- from datetime import timedelta
2
- from datetime import datetime
3
- import os.path
4
- from google.auth.transport.requests import Request
5
- from google.oauth2.credentials import Credentials
6
- from google_auth_oauthlib.flow import InstalledAppFlow
7
- from googleapiclient.discovery import build
8
- from googleapiclient.errors import HttpError
9
- import smtplib
10
- from email.mime.multipart import MIMEMultipart
11
- from email.mime.text import MIMEText
12
- import pandas as pd
13
- from langchain.prompts import PromptTemplate
14
- from langchain.chains import LLMChain
15
- from langchain_groq import ChatGroq
16
- from langchain.agents import tool
17
- from schemas import symptoms,bookSlot,deleteSlot,reschedule_event,listevent,checkevent
18
-
19
- API_KEY="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"
20
-
21
- llm = ChatGroq(
22
- model="llama3-8b-8192",
23
- temperature=0,
24
- max_tokens=None,
25
- timeout=None,
26
- max_retries=2,
27
- api_key=API_KEY
28
- )
29
- SCOPES = ["https://www.googleapis.com/auth/calendar"]
30
- doctor_df = pd.read_csv('doctor_specialization_dummy_data.csv')
31
-
32
- EMAIL_SENDER = "[email protected]"
33
- EMAIL_PASSWORD = "wlxf poqr wgsh qvqs"
34
-
35
- def get_service():
36
- """Create and return the Google Calendar API service."""
37
- print('this function is called.')
38
- creds = None
39
- if os.path.exists("token.json"):
40
- creds = Credentials.from_authorized_user_file("token.json", SCOPES)
41
- if not creds or not creds.valid:
42
- if creds and creds.expired and creds.refresh_token:
43
- creds.refresh(Request())
44
- else:
45
- flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES)
46
- creds = flow.run_local_server(port=0)
47
- with open("token.json", "w") as token:
48
- token.write(creds.to_json())
49
-
50
- return build("calendar", "v3", credentials=creds)
51
-
52
- def send_email(to_email, subject, body):
53
- """Send an email notification to the participants."""
54
- try:
55
- msg = MIMEMultipart()
56
- msg['From'] = EMAIL_SENDER
57
- msg['To'] = to_email
58
- msg['Subject'] = subject
59
- msg.attach(MIMEText(body, 'plain'))
60
-
61
- server = smtplib.SMTP('smtp.gmail.com', 587)
62
- server.starttls()
63
- server.login(EMAIL_SENDER, EMAIL_PASSWORD)
64
- text = msg.as_string()
65
- server.sendmail(EMAIL_SENDER, to_email, text)
66
- server.quit()
67
-
68
- print(f"Email sent to {to_email}")
69
- except Exception as e:
70
- print(f"Failed to send email: {e}")
71
-
72
-
73
- def is_valid_booking_time(start_time):
74
- # Convert string to datetime object
75
- start_time_dt = datetime.strptime(start_time, "%Y-%m-%dT%H:%M:%S%z")
76
-
77
- # Ensure the booking is within the next 7 days
78
- today = datetime.now(start_time_dt.tzinfo)
79
- if start_time_dt < today or start_time_dt > (today + timedelta(days=7)):
80
- return False, "You can only book appointments within the next 7 days."
81
-
82
- # Ensure the booking is on a weekday and within 10 AM to 7 PM
83
- if start_time_dt.weekday() >= 5: # 0 = Monday, 6 = Sunday
84
- return False, "Appointments can only be booked Monday to Friday."
85
-
86
- if not (10 <= start_time_dt.hour < 19): # Ensure the time is between 10 AM to 7 PM
87
- return False, "Appointments can only be scheduled between 10 AM and 7 PM."
88
-
89
- return True, None
90
- import pytz
91
- @tool("check-event", args_schema=checkevent, return_direct=True)
92
- def check_slots(date):
93
- """
94
- This function is to check available slot for a given date, excluding times when events are booked.
95
- It only returns valid slots that fall on weekdays (Mon-Fri) between 10 AM to 7 PM.
96
-
97
- Args:
98
- date (str): The date for which to check availability (e.g., '2024-09-17').
99
-
100
- Returns:
101
- str: Formatted string of available 1-hour slots or a message if no slots are available.
102
- """
103
- # Define the start and end time for the day
104
- start_time = f"{date}T10:00:00+05:30" # Start at 10 AM
105
- end_time = f"{date}T19:00:00+05:30" # End at 7 PM
106
- service = get_service()
107
-
108
- # Check if the date is valid (weekday, and within 10 AM to 7 PM)
109
- valid, message = is_valid_booking_time(start_time)
110
- if not valid:
111
- return message
112
-
113
- # Query for events between start and end time
114
- events_result = service.events().list(
115
- calendarId='primary',
116
- timeMin=start_time,
117
- timeMax=end_time,
118
- singleEvents=True,
119
- orderBy='startTime'
120
- ).execute()
121
-
122
- events = events_result.get('items', [])
123
-
124
- # Define the working hours (10 AM to 7 PM)
125
- work_start = datetime.fromisoformat(f"{date}T10:00:00+05:30")
126
- work_end = datetime.fromisoformat(f"{date}T19:00:00+05:30")
127
- available_slots = []
128
-
129
- # Add all the slots starting from work_start until work_end
130
- current_time = work_start
131
-
132
- for event in events:
133
- event_start = datetime.fromisoformat(event['start']['dateTime'])
134
- event_end = datetime.fromisoformat(event['end']['dateTime'])
135
-
136
- # Find all available 1-hour slots between current_time and the event start
137
- while current_time + timedelta(hours=1) <= event_start:
138
- slot_start = current_time
139
- slot_end = current_time + timedelta(hours=1)
140
-
141
- # Ensure the slot is a valid booking time
142
- valid, message = is_valid_booking_time(slot_start.isoformat())
143
- if valid:
144
- available_slots.append((slot_start, slot_end))
145
- current_time += timedelta(hours=1)
146
-
147
- # Move current_time to the end of the event
148
- current_time = max(current_time, event_end)
149
-
150
- # Add slots from the last event to the end of the working day
151
- while current_time + timedelta(hours=1) <= work_end:
152
- slot_start = current_time
153
- slot_end = current_time + timedelta(hours=1)
154
-
155
- # Ensure the slot is a valid booking time
156
- valid, message = is_valid_booking_time(slot_start.isoformat())
157
- if valid:
158
- available_slots.append((slot_start, slot_end))
159
- current_time += timedelta(hours=1)
160
-
161
- # Return available slots in a properly formatted string
162
- if available_slots:
163
- formatted_output = f"📅 **Available Slots for {date}:\n**\n\n"
164
- for slot in available_slots:
165
- start_time = slot[0].strftime('%I:%M %p')
166
- end_time = slot[1].strftime('%I:%M %p')
167
- formatted_output += f"\n🕒 {start_time} - {end_time}\n"
168
-
169
- formatted_output += "\n✨ Each slot is for a 1-hour appointment."
170
- formatted_output += "\n\n💡 To book an appointment, please specify your preferred time slot."
171
-
172
- return formatted_output
173
- else:
174
- return "😔 I'm sorry, but there are no available slots for the requested date. Would you like to check another date?"
175
-
176
-
177
- def check_slot_availability(start_time, end_time):
178
- # Define the Asia/Kolkata timezone
179
- kolkata_tz = pytz.timezone('Asia/Kolkata')
180
-
181
- # Parse and localize the start_time and end_time into Asia/Kolkata timezone
182
- start_time_dt = datetime.strptime(start_time, "%Y-%m-%dT%H:%M:%S%z")
183
- end_time_dt = datetime.strptime(end_time, "%Y-%m-%dT%H:%M:%S%z")
184
-
185
- # Ensure the times are correctly converted to ISO format without adding "Z"
186
- time_min = start_time_dt.isoformat() # Already includes the timezone info
187
- time_max = end_time_dt.isoformat() # Already includes the timezone info
188
- service=get_service()
189
- # Fetch events within the given time range in Asia/Kolkata timezone
190
- events_result = service.events().list(
191
- calendarId="primary",
192
- timeMin=time_min,
193
- timeMax=time_max,
194
- singleEvents=True,
195
- orderBy="startTime"
196
- ).execute()
197
-
198
- events = events_result.get("items", [])
199
- return len(events) == 0 # Returns True if the slot is free
200
-
201
- def find_event_by_time(start_time):
202
- """
203
- Finds an event by its start time in the user's Google Calendar.
204
-
205
- Args:
206
- start_time (str): The start time of the event in ISO format (e.g., '2024-09-17T14:30:00+05:30').
207
-
208
- Returns:
209
- dict or None: The event details if found, otherwise None.
210
- """
211
- try:
212
- print(f"Searching for event starting at {start_time}")
213
- service=get_service()
214
- # Calculate the end time (assuming 1-hour event window)
215
- start_time_dt = datetime.fromisoformat(start_time)
216
- end_time_dt = start_time_dt + timedelta(hours=1)
217
- end_time = end_time_dt.isoformat()
218
-
219
- # Query Google Calendar API for events in this time window
220
- events_result = service.events().list(
221
- calendarId="primary",
222
- timeMin=start_time,
223
- timeMax=end_time,
224
- singleEvents=True,
225
- orderBy="startTime",
226
- ).execute()
227
-
228
- events = events_result.get("items", [])
229
- print(f"Events found: {events}")
230
-
231
- # Return the first event that matches the time exactly
232
- for event in events:
233
- event_start = event['start'].get('dateTime')
234
- if event_start == start_time:
235
- print(f"Matching event found: {event['summary']} at {event_start}")
236
- return event
237
-
238
- print(f"No event found starting at {start_time}")
239
- return None
240
-
241
- except HttpError as error:
242
- print(f"An error occurred: {error}")
243
- return None
244
- except Exception as e:
245
- print(f"Unexpected error: {e}")
246
- return None
247
-
248
-
249
-
250
-
251
- @tool("list_event", args_schema=listevent, return_direct=True)
252
- def list_upcoming_events(target_date):
253
- """
254
- Lists the upcoming events on the user's calendar for a specific date.
255
-
256
- Args:
257
- target_date (str): The date to filter events on, in 'YYYY-MM-DD' format.
258
-
259
- Returns:
260
- string: Summary of the events
261
- """
262
- service=get_service()
263
- # Parse the target date to create timeMin and timeMax bounds
264
- # Convert the target date string to a datetime object
265
- target_date_obj = datetime.strptime(target_date, "%Y-%m-%d")
266
-
267
- # Set timeMin to the beginning of the day and timeMax to the end of the day
268
- time_min = target_date_obj.isoformat() + "Z" # Beginning of the day in UTC
269
- time_max = (target_date_obj + timedelta(days=1)).isoformat() + "Z" # End of the day in UTC
270
-
271
- print(f"Getting events for {target_date}")
272
-
273
- try:
274
- events_result = (
275
- service.events()
276
- .list(
277
- calendarId="primary",
278
- timeMin=time_min,
279
- timeMax=time_max,
280
- singleEvents=True,
281
- orderBy="startTime",
282
- )
283
- .execute()
284
- )
285
- events = events_result.get("items", [])
286
-
287
- if not events:
288
- print(f"No events found for {target_date}.")
289
- else:
290
- for event in events:
291
- start = event["start"].get("dateTime", event["start"].get("date"))
292
- result=start, event["summary"]
293
- return result
294
- except HttpError as error:
295
- print(f"An error occurred: {error}")
296
-
297
- @tool("book-slot-tool", args_schema=bookSlot, return_direct=True)
298
- def book_slot(start_time, end_time, summary):
299
- """
300
- This functions is to boos a appointment/slot for user by creating an event on the calendar.
301
-
302
- Args:
303
- start_time (str): The start time of the slot (e.g., '2024-09-16T14:00:00+05:30').
304
- end_time (str): The end time of the slot (e.g., '2024-09-16T15:00:00+05:30').
305
- summary (str): Summary or title of the event.
306
-
307
- Returns:
308
- str: Confirmation message if the event is created or an error message if booking fails.
309
- """
310
- service = get_service()
311
- is_valid, error_message = is_valid_booking_time(start_time)
312
-
313
- if not is_valid:
314
- # Return the error message with proper formatting
315
- formatted_output = "❌ **Invalid Booking Time**\n\n"
316
- formatted_output += f"{error_message}\n"
317
- formatted_output += "\nAppointments can only be scheduled:\n"
318
- formatted_output += "📅 Monday to Friday\n"
319
- formatted_output += "🕒 Between 10 AM and 7 PM\n"
320
- formatted_output += "📆 Within the next 7 days\n"
321
- return formatted_output
322
- if not check_slot_availability(start_time, end_time):
323
- formatted_output = "❌ **Slot Unavailable**\n\n"
324
- formatted_output += "\nThe requested slot is not available.\n"
325
- formatted_output += "\nPlease choose another time."
326
- return formatted_output
327
-
328
- # Create the event object
329
- event = {
330
- 'summary': summary,
331
- 'start': {
332
- 'dateTime': start_time, # ISO 8601 format
333
- 'timeZone': 'Asia/Kolkata', # Use appropriate timezone
334
- },
335
- 'end': {
336
- 'dateTime': end_time,
337
- 'timeZone': 'Asia/Kolkata',
338
- },
339
- }
340
-
341
- try:
342
- # Insert the event into the primary calendar
343
- event_result = service.events().insert(calendarId='primary', body=event).execute()
344
- formatted_output = "✅ **Event Created Successfully!**\n\n"
345
- formatted_output += f"\n📌 **Summary:** {summary}\n"
346
- formatted_output += f"\n🕒 **Start Time:** {start_time}\n"
347
- formatted_output += f"\n🕒 **End Time:** {end_time}\n\n"
348
- formatted_output += "\n📅 The event has been added to your primary calendar."
349
- return formatted_output
350
- except HttpError as error:
351
- return f"❌ **An error occurred:** {error}\n\nPlease try again or contact support if the issue persists."
352
-
353
- @tool("delete-slot-tool", args_schema=deleteSlot, return_direct=True)
354
- def delete_event(start_time):
355
- """
356
- Deletes an event by start time on the user's calendar.
357
-
358
- Args:
359
- start_time (str): The start time of the event (e.g., '2024-09-20T15:30:00+05:30').
360
-
361
- Returns:
362
- str: Confirmation message if the event is deleted.
363
- """
364
- service = get_service()
365
- event = find_event_by_time(start_time)
366
-
367
- if event:
368
- try:
369
- service.events().delete(calendarId='primary', eventId=event['id']).execute()
370
- formatted_output = "\n🗑️ **Event Deleted Successfully!**\n\n"
371
- formatted_output += f"\n📌 **Summary:** {event['summary']}\n"
372
- formatted_output += f"\n🕒 **Start Time:** {event['start']['dateTime']}\n\n"
373
- formatted_output += "\nThe event has been removed from your primary calendar."
374
- return formatted_output
375
- except HttpError as error:
376
- return f"❌ **An error occurred:** {error}\n\nPlease try again or contact support if the issue persists."
377
- else:
378
- formatted_output = "❓ **No Event Found**\n\n"
379
- formatted_output += f"🕒 **\nRequested Start Time:** {start_time}\n\n"
380
- formatted_output += "\nNo event was found for the specified time. Please check the time and try again."
381
- return formatted_output
382
-
383
-
384
- @tool("reschedule-event-tool", args_schema=reschedule_event, return_direct=True)
385
- def reschedule_event(start_time, new_start_time, new_end_time):
386
- """
387
- Reschedules an existing event by providing new start and end times.
388
-
389
- Args:
390
- start_time (str): The start time of the existing event (e.g., '2024-09-18T14:00:00+05:30').
391
- new_start_time (str): The new start time of the event (e.g., '2024-09-18T12:00:00+05:30').
392
- new_end_time (str): The new end time of the event (e.g., '2024-09-18T14:00:00+05:30').
393
-
394
- Returns:
395
- str: Confirmation message if the event is rescheduled or an error message if rescheduling fails.
396
- """
397
- service = get_service()
398
- if not is_valid_booking_time(start_time):
399
- formatted_output = "❌ **Invalid Booking Time**\n\n"
400
- formatted_output += "\nAppointments can only be scheduled:\n"
401
- formatted_output += "\n📅 Monday to Friday\n"
402
- formatted_output += "\n🕒 Between 10 AM and 7 PM\n"
403
- formatted_output += "\n📆 Within the next 7 days\n"
404
- return formatted_output
405
-
406
- if not check_slot_availability(new_start_time, new_end_time):
407
- formatted_output = "❌ **Slot Unavailable**\n\n"
408
- formatted_output += "\nThe requested slot is not available.\n"
409
- formatted_output += "\nPlease choose another time."
410
- return formatted_output
411
-
412
- try:
413
- event = find_event_by_time(start_time)
414
-
415
- if not event:
416
- formatted_output = "❓ **No Event Found**\n\n"
417
- formatted_output += f"\n🕒 **Requested Start Time:** {start_time}\n\n"
418
- formatted_output += "\nNo event was found for the specified time. Please check the time and try again."
419
- return formatted_output
420
-
421
- event['start']['dateTime'] = new_start_time
422
- event['end']['dateTime'] = new_end_time
423
-
424
- updated_event = service.events().update(calendarId='primary', eventId=event['id'], body=event).execute()
425
-
426
- formatted_output = "✅ **Event Rescheduled Successfully!**\n\n"
427
- formatted_output += f"\n🔄 **Original Start Time:** {start_time}\n"
428
- formatted_output += f"\n🆕 **New Start Time:** {new_start_time}\n"
429
- formatted_output += f"\n🆕 **New End Time:** {new_end_time}\n\n"
430
- formatted_output += "\nYour appointment has been updated in the calendar."
431
- return formatted_output
432
-
433
- except HttpError as error:
434
- return f"❌ **An error occurred:** {error}\n\nPlease try again or contact support if the issue persists."
435
-
436
-
437
- @tool("suggest-doctors-tool", return_direct=True)
438
- def suggest_specialization(symptoms):
439
- """This function understands user's symptoms and suggests specialization and doctor details.
440
- Args:
441
- symptoms (string): symptoms of patients/user
442
- Returns:
443
- string: Formatted string with specialization and doctor details
444
- """
445
- prompt_template = """
446
- You are a highly knowledgeable Healthcare AI specialized in directing patients to the appropriate medical professionals.
447
- Greet the user politely. Based on the symptoms provided below, suggest the most suitable doctor's specialization for the patient to visit.
448
- Respond with only the name of the specialization in one word, without any additional explanations.
449
-
450
- Here are a few examples for reference:
451
- - Symptoms: skin rash, itching, dryness → Answer: "Dermatologist"
452
- - Symptoms: chest pain, shortness of breath → Answer: "Cardiologist"
453
- - Symptoms: joint pain, stiffness, swelling → Answer: "Rheumatologist"
454
- - Symptoms: persistent cough, fever, sore throat → Answer: "Pulmonologist"
455
- - Symptoms: frequent headaches, dizziness, vision problems → Answer: "Neurologist"
456
-
457
- Now, based on the symptoms below, provide the specialization in one word.
458
- Symptoms: {symptoms}
459
- """
460
- prompt = PromptTemplate(input_variables=["symptoms"], template=prompt_template)
461
- chain = LLMChain(llm=llm, prompt=prompt)
462
-
463
- try:
464
- result = chain.run(symptoms=symptoms)
465
- specialization = result.split('\n')[-1].strip().lower()
466
-
467
- # Check if we have a match for the specialization in our doctor data
468
- relevant_doctors = doctor_df[doctor_df['Specialization'].str.contains(specialization, case=False, na=False)]
469
-
470
- if relevant_doctors.empty:
471
- # If no match, fallback to suggesting a General Practitioner
472
- return ("Based on your symptoms, I recommend consulting a General Practitioner. "
473
- "Unfortunately, no specific doctors matching your symptoms were found in our database.")
474
-
475
- # If doctors are found, format the details
476
- formatted_output = f"Based on your symptoms, I recommend consulting an {specialization.capitalize()}.\n\n"
477
- formatted_output += "Here are the details of a suitable doctor:\n\n"
478
-
479
- doctor = relevant_doctors.iloc[0] # Get the first matching doctor
480
- formatted_output += f"👨‍⚕️ **Doctor**: {doctor['Doctor Name']}\n"
481
- formatted_output += f"\n🏥 **Specialization**: {doctor['Specialization']}\n"
482
- formatted_output += f"\n📞 **Contact**: {doctor['Contact Number']}\n"
483
- formatted_output += f"\n🏢 **Address**: {doctor['Address']}\n"
484
-
485
- return formatted_output
486
-
487
- except Exception as e:
488
- # Fallback if an error occurs
489
- return "I apologize, but I encountered an issue while processing your request. Please try describing your symptoms again, or consider consulting a General Practitioner for a comprehensive evaluation."