Spaces:
Sleeping
Sleeping
File size: 7,361 Bytes
c5e1945 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
from langchain.tools.retriever import create_retriever_tool
from langchain_community.tools import TavilySearchResults
from langchain.tools import tool
from retriever import hybrid_retriever
import pytz
from datetime import datetime
from pydantic import BaseModel, Field
from typing import Optional
import json
import uuid
# Optimized retriever tool with faster settings
retriever_tool = create_retriever_tool(
hybrid_retriever,
name="company_knowledge_tool",
description="Fast tool for company info, history, products, and policies. Use only for Al Shifa Digital Healthcare questions."
)
# Optimized web search tool with reduced results for speed
websearch_tool = TavilySearchResults(
max_results=3,
include_answer=True,
include_raw_content=False,
include_images=False,
search_depth="basic",
name="Tavily_Search_Tool",
description="Fast search for medical questions and current info. Use for medical advice and up-to-date information."
)
@tool
def get_current_datetime_tool() -> str:
"""
Returns the current date, time, and day of the week for Saudi Arabia (Asia/Riyadh).
This is the only reliable source for date and time information. Use this tool
whenever a user asks about 'today', 'now', or any other time-sensitive query.
The output is in English but shows Saudi Arabia local time.
"""
try:
# Define the timezone for Saudi Arabia
saudi_tz = pytz.timezone('Asia/Riyadh')
# Get the current time in that timezone
now_saudi = datetime.now(saudi_tz)
# Manual mapping to ensure English output regardless of system locale
days_en = {
0: "Monday", 1: "Tuesday", 2: "Wednesday", 3: "Thursday",
4: "Friday", 5: "Saturday", 6: "Sunday"
}
months_en = {
1: "January", 2: "February", 3: "March", 4: "April",
5: "May", 6: "June", 7: "July", 8: "August",
9: "September", 10: "October", 11: "November", 12: "December"
}
# Get English names using manual mapping
day_name = days_en[now_saudi.weekday()]
month_name = months_en[now_saudi.month]
day = now_saudi.day
year = now_saudi.year
# Format time manually to avoid locale issues
hour = now_saudi.hour
minute = now_saudi.minute
# Convert to 12-hour format
if hour == 0:
hour_12 = 12
period = "AM"
elif hour < 12:
hour_12 = hour
period = "AM"
elif hour == 12:
hour_12 = 12
period = "PM"
else:
hour_12 = hour - 12
period = "PM"
time_str = f"{hour_12:02d}:{minute:02d} {period}"
# Create the final string
return f"Current date and time in Saudi Arabia: {day_name}, {month_name} {day}, {year} at {time_str}"
except Exception as e:
return f"Error getting current datetime: {str(e)}"
# --- Pydantic Model for Structured Tool Input ---
# All fields are now Optional to prevent validation errors at the agent level.
# The validation logic is moved inside the tool itself.
class BookingInput(BaseModel):
"""Inputs for the book_consultation tool."""
patient_name: Optional[str] = Field(None, description="The user's full name.")
age: Optional[str] = Field(None, description="The user's age.")
gender: Optional[str] = Field(None, description="The user's gender.")
contact_number: Optional[str] = Field(None, description="A phone number for confirmation.")
email: Optional[str] = Field(None, description="An email address for confirmation and reminders.")
reason_for_consultation: Optional[str] = Field(None, description="A brief description of the user's symptoms or reason for the visit.")
preferred_date: Optional[str] = Field(None, description="The user's desired date for the appointment.")
preferred_time: Optional[str] = Field(None, description="The user's desired time for the appointment.")
specialty: Optional[str] = Field(None, description="The specific medical field needed.")
doctor_preference: Optional[str] = Field(None, description="The name of a specific doctor, if requested.")
consultation_type: Optional[str] = Field(None, description="The method of consultation.")
@tool(args_schema=BookingInput)
def book_consultation_tool(patient_name: Optional[str] = None, age: Optional[str] = None, gender: Optional[str] = None, contact_number: Optional[str] = None, email: Optional[str] = None, reason_for_consultation: Optional[str] = None, preferred_date: Optional[str] = None, preferred_time: Optional[str] = None, consultation_type: Optional[str] = None, specialty: Optional[str] = None, doctor_preference: Optional[str] = None) -> str:
"""
Books a medical consultation. If required information is missing, it returns a message
asking for the missing details. Otherwise, it returns the booking data as a JSON object.
Email is optional and will be set to 'unknown@alshifa-care.com' if not provided.
"""
# --- 1. Internal Validation: Check for missing required information ---
missing_fields = []
if not patient_name:
missing_fields.append("اسم المريض الكامل (patient_name)")
if not age:
missing_fields.append("العمر (age)")
if not gender:
missing_fields.append("الجنس (gender)")
if not contact_number:
missing_fields.append("رقم التواصل (contact_number)")
if not reason_for_consultation:
missing_fields.append("سبب الاستشارة (reason_for_consultation)")
if not preferred_date:
missing_fields.append("التاريخ المفضل (preferred_date)")
if not preferred_time:
missing_fields.append("الوقت المفضل (preferred_time)")
# Set default email if not provided
if not email:
email = "unknown@alshifa-care.com"
# --- 2. Handle missing required fields ---
if missing_fields:
missing_fields_str = "\n- ".join([""] + missing_fields) # Add newline and bullet points
return f"""
عذراً، لا يمكن إتمام الحجز بسبب نقص المعلومات المطلوبة. يرجى توفير:
{missing_fields_str}
Sorry, we cannot complete the booking due to missing required information. Please provide:
{missing_fields_str}
"""
# --- 2. If all data is present, proceed with booking ---
booking_id = f"BK-{uuid.uuid4().hex[:8].upper()}"
timestamp = datetime.now().isoformat()
booking_data = {
"booking_id": booking_id,
"booking_timestamp": timestamp,
"patient_details": {"name": patient_name, "age": age, "gender": gender, "contact_number": contact_number, "email": email},
"consultation_details": {
"reason": reason_for_consultation,
"preferred_date": preferred_date,
"preferred_time": preferred_time,
"specialty": specialty or "Not Specified",
"doctor_preference": doctor_preference or "Any",
"type": consultation_type or "Video Call"
}
}
# 3. Return the final data as a formatted JSON string
return json.dumps(booking_data, indent=4, ensure_ascii=False) |