OpenAI has recently launched a range of remarkable enhancements that have left users amazed. Among these additions, the OpenAI function calling feature has emerged as the most prominent addition. With this powerful functionality, developers gain the ability to select and invoke for resolving specific problems. A key aspect of OpenAI’s function calling feature is its seamless integration with external APIs, enabling developers to generate responses by leveraging external services.
In our previous blogs, we explored “How To Use OpenAI Function Calling To Create an Appointment Booking Chatbot”. Through this exploration, we created a chatbot that integrates with the Google Calendar API. This integration empowers the chatbot to efficiently handle appointment bookings and harness the full functionality of the Google calendar.
In this blog, we will explore how to create an appointment-booking chatbot, which integrates with the GoHighLevel platform for appointment management. GoHighLevel is a customer relationship management (CRM) platform that offers various features for businesses to manage their customer interactions, marketing campaigns, sales processes, and more. One of the features provided by GoHighLevel is the calendar functionality. The GoHighLevel calendar allows users to schedule and manage appointments and delete appointments.
Let’s start with the blog where we will explore how to create an appointment booking chatbot that seamlessly integrates with the GoHighLevel (GHL) platform.
We will start by setting up the GoHighLevel platform. We need to first go to the https://app.gohighlevel.com/ website and then claim our free 14-day trial. You need to give your Company Name, Name, Email ID, Phone number, and credit card details to sign up for the first time.
Once you have created an account, you will see below like dashboard:
We need to use GoHighLevel API, to manage appointment creation, updation, and deletion. In order to use the API, we need an API key.
There are 2 types of API keys available:
To manage appointments we need a Location API key. To generate a Location API key you need to first add a location by creating a sub-account.
To create a sub-account you need to first click the “Sub-Accounts” from the left panel and then hit “Create Sub-Account” as shown below:
It will open a screen like below, where you need to select “Blank Snapshot” under the title “Regular Account”.
Then, it will open a screen with a map like below. You need to select your location and then continue with your selected location by clicking the arrow.
After this, it will open a tab with the title “Add account”. You need to add your details and then hit the “save” button. It will create a sub-account with the given location.
Next, You need to switch to the recently created sub-account by clicking on “Click here to switch” from the left panel as shown in the below image:
It will open up a selection box that has all sub-accounts listed. You can choose one from the list, and the system will switch to that account. and then you can see a screen like below:
After creating a sub-account, you can retrieve the Location API key, which will be used for appointment management. To obtain the Location API key, first go to the “Settings” option located in the left panel and then select “Business Profile” from the available options. A screen will appear where you need to scroll down a bit, and you will find your Location API key as shown in the below image:
Moving forward, we need to add employees to our team. To add an employee, you need to follow the below steps:
Now, let’s proceed with creating a group that will help in team management. To create the group, you need to follow below steps:
In the Calendar URL, you can simply provide any string like “demo-calendar”.
Let’s now move forward and create a calendar that will facilitate appointment management functions. To create the calendar, follow the below steps:
For this demo, we have kept the “Appointment Slot Setting” as below:
Once you have created a calendar, the next step is to move it to the previously created group. To accomplish this, follow the steps below:
We have completed the basic setup of “GoHighLevel.” Now, we are fully prepared to utilize the GoHighLevel API for appointment creation, updating, and deletion. To use the GoHighLevel API, we need three types of IDs: Group ID, Calendar ID and User ID. We will obtain these IDs in the following steps.
To obtain the Group ID, you need to follow the below steps:
Your copied embed code will look like below:
<iframe src=”https://api.leadconnectorhq.com/widget/group/NZc2nxIeE6a2liSwqmNX” style=”width: 100%;border:none;overflow: hidden;” scrolling=”no” id=”<your_group_id>_1688194531391″></iframe><br><script src=”https://link.msgsndr.com/js/form_embed.js” type=”text/javascript”></script>
From the URL above, you can locate the ID field. The string before the “_” symbol represents your Group ID.
Moving forward in this step, we will obtain our Calendar ID.
To obtain the Calendar ID, you need to follow the below steps:
Your copied embed code will look like below as earlier:
<iframe src=”https://api.leadconnectorhq.com/widget/booking/kK8LwFPuNByksXB3h18s” style=”width: 100%;border:none;overflow: hidden;” scrolling=”no” id=”<your_calendar_id>_1688196021697″></iframe><br><script src=”https://link.msgsndr.com/js/form_embed.js” type=”text/javascript”></script>
In this step, let’s proceed to obtain the User ID.
To obtain the User ID, you need to follow the below steps:
After completion of these steps, we have all 3 IDs, now we will move forward to secret an appointment booking chatbot using python.
Now, it’s time to start with the development of the Python script for an appointment booking chatbot. To accomplish this, we will leverage OpenAI’s function calling feature, which integrates with the GHL Calendar for efficient appointment management.
First, we will import the required libraries:
import requests
import json
from datetime import date, datetime, timedelta
import time
import pytz
Next, we will define a utility function that will call ChatGPT and generate responses. To add this functionality to our script, include the following lines of code:
import openai
openai_api_key = ""
openai.api_key = openai_api_key
client = openai
GPT_MODEL = "gpt-4o-mini"
def chat_completion_request(messages, functions=None, function_call=None):
json_data = {"model": GPT_MODEL, "messages": messages}
if functions is not None:
json_data.update({"functions": functions})
if function_call is not None:
json_data.update({"function_call": function_call})
try:
completion = client.chat.completions.create(
**json_data
)
return completion
except Exception as e:
print("Unable to generate ChatCompletion response")
print(f"Exception: {e}")
return e
Moving forward, in this step, we will define a function that calls the GHL appointment booking endpoint. However, before that, we need to create another function that converts the date and time provided by the user into the ISO 8601 date format. The ISO 8601 format is an internationally recognized standard for representing dates and times.
We can define both functions as follows:
limit1 = datetime.strptime("10:00:00", "%H:%M:%S").time()
limit2 = datetime.strptime("17:00:00", "%H:%M:%S").time()
limit3 = datetime.strptime("12:00:00", "%H:%M:%S").time()
headers = {
'Authorization': 'Bearer '
}
def convert_to_iso8601(datetime_string, target_timezone):
datetime_format = "%Y-%m-%d %H:%M:%S"
dt = datetime.strptime(datetime_string, datetime_format)
source_timezone = pytz.timezone('Asia/Kolkata')
dt = source_timezone.localize(dt)
target_timezone = pytz.timezone(target_timezone)
dt = dt.astimezone(target_timezone)
iso8601_datetime = dt.strftime("%Y-%m-%dT%H:%M:%S%z")
iso8601_datetime = iso8601_datetime[:-2] + ":" + iso8601_datetime[-2:]
return iso8601_datetime
def appointment_booking(arguments):
try:
provided_date = datetime.strptime(json.loads(arguments)['date'], "%Y-%m-%d")
provided_time = datetime.strptime(json.loads(arguments)['time'].replace("PM","").replace("AM","").strip(), "%H:%M:%S").time()
try:
email_address = json.loads(arguments)['email_address']
except:
return "Please provide email ID for identification."
try:
phone_number = json.loads(arguments)['phone_number']
except:
return "Please provide a phone number for identification."
if provided_date and provided_time and email_address and phone_number:
start_date_time = str(provided_date.date()) + " " + str(provided_time)
iso8601_datetime = convert_to_iso8601(start_date_time, 'Asia/Kolkata')
if day_list[provided_date.weekday()] == "Saturday":
if provided_time >= limit1 and provided_time <= limit3:
url = "https://rest.gohighlevel.com/v1/appointments/"
payload = {
"calendarId": "kK8LwFPuNByksXB3h18s",
"selectedTimezone": "Asia/Calcutta",
"selectedSlot": iso8601_datetime,
"email": email_address,
"phone": phone_number
}
response = requests.request("POST", url, headers=headers, data=payload)
response = json.loads(response.text)
try:
if response['id']:
return "Appointment booked successfully."
except:
return response['selectedSlot']['message']
else:
return "Please try to book an appointment into working hours, which is 10 AM to 2 PM at saturday."
else:
if provided_time >= limit1 and provided_time <= limit2:
url = "https://rest.gohighlevel.com/v1/appointments/"
payload = {
"calendarId": "kK8LwFPuNByksXB3h18s",
"selectedTimezone": "Asia/Calcutta",
"selectedSlot": iso8601_datetime,
"email": email_address,
"phone": phone_number
}
response = requests.request("POST", url, headers=headers, data=payload)
response = json.loads(response.text)
try:
if response['id']:
return "Appointment booked successfully."
except:
return response['selectedSlot']['message']
else:
return "Please try to book an appointment into working hours, which is 10 AM to 7 PM."
else:
return "Please provide all the necessary information: Appointment date, time, email ID, Phone number."
except:
return "We are facing an error while processing your request. Please try again."
Now, let’s define a function that will update appointments using the GHL endpoint. To update an appointment, we need to find the corresponding ‘ID’ of the appointment. Therefore, we will first describe a function that fetches the ‘ID’ based on the parameters provided by the user. This function will then return the ‘ID’ to the update function.
We can define both functions as follows:
def get_all_booked_appointment(arguments):
try:
provided_date = datetime.strptime(json.loads(arguments)['date'], "%Y-%m-%d")
ending_date_time = datetime.strptime(json.loads(arguments)['date'], "%Y-%m-%d") + timedelta(days=1)
try:
email_address = json.loads(arguments)['email_address']
except:
return "Please provide email ID for identification."
if provided_date and email_address:
starting_timestamp = time.mktime(provided_date.timetuple()) * 1000
ending_timestamp = time.mktime(ending_date_time.timetuple()) * 1000
url = f"https://rest.gohighlevel.com/v1/appointments/?startDate={starting_timestamp}&endDate={ending_timestamp}&userId=oJbRc7r2HBYunuvJ3XC7&calendarId=kK8LwFPuNByksXB3h18s&teamId=ONZc2nxIeE6a2liSwqmNX&includeAll=true"
payload={}
response = requests.request("GET", url, headers=headers, data=payload)
response = json.loads(response.text)
events = []
for element in response['appointments']:
if element['contact']['email'] == email_address:
events.append(element)
if len(events) == 1:
id = events[0]['id']
return id
elif len(events) > 1:
print("You have multiple appointments with the same email address:")
count = 1
for ele in events:
print(str(count)+"]")
print(ele['address'])
print(ele['startTime'])
print(ele['endTime'])
print(ele['contact']['email'])
print()
count = count + 1
event_number = int(input("Please enter which appointment:"))
if event_number >= 1 and event_number <= len(events):
id = events[event_number - 1]['id']
return id
else:
return "Please select valid event number"
else:
return "No registered event found with this email ID."
else:
return "Please provide all the necessary information: Appointment date and email ID."
except:
return "We are facing an error while processing your request. Please try again."
def appointment_updation(arguments):
try:
provided_date = datetime.strptime(json.loads(arguments)['to_date'], "%Y-%m-%d")
provided_time = datetime.strptime(json.loads(arguments)['time'].replace("PM","").replace("AM","").strip(), "%H:%M:%S").time()
if provided_date and provided_time and json.loads(arguments)['date'] and json.loads(arguments)['email_address']:
start_date_time = str(provided_date.date()) + " " + str(provided_time)
iso8601_datetime = convert_to_iso8601(start_date_time, 'Asia/Kolkata')
if day_list[provided_date.date().weekday()] == "Saturday":
if provided_time >= limit1 and provided_time <= limit3:
id = get_all_booked_appointment(arguments)
if id == "Please select valid event number" or id == "No registered event found with this email ID." or id == "We are facing an error while processing your request. Please try again.":
return id
else:
url = f"https://rest.gohighlevel.com/v1/appointments/{id}"
payload = {
"selectedTimezone": "Asia/Calcutta",
"selectedSlot": iso8601_datetime
}
response = requests.request("PUT", url, headers=headers, data=payload)
response = json.loads(response.text)
try:
if response['id']:
return "Appointment updated successfully."
except:
return response['selectedSlot']['message']
else:
return "Please try to book an appointment into working hours, which is 10 AM to 2 PM at saturday."
else:
if provided_time >= limit1 and provided_time <= limit2:
id = get_all_booked_appointment(arguments)
if id == "Please select valid event number" or id == "No registered event found with this email ID." or id == "We are facing an error while processing your request. Please try again.":
return id
else:
url = f"https://rest.gohighlevel.com/v1/appointments/{id}"
payload = {
"selectedTimezone": "Asia/Calcutta",
"selectedSlot": iso8601_datetime
}
response = requests.request("PUT", url, headers=headers, data=payload)
response = json.loads(response.text)
try:
if response['id']:
return "Appointment updated successfully."
except:
return response['selectedSlot']['message']
else:
return "Please try to book an appointment into working hours, which is 10 AM to 7 PM."
else:
return "Please provide all the necessary information: Current appointment date, New appointment date, time and email ID."
except:
return "We are facing an error while processing your request. Please try again."
Next, we will define a function for deleting appointments. This function will first call the ‘get_all_booked_appointments’ function that we created earlier to fetch the corresponding ID of the appointment. The fetched ID will then be passed to the deletion endpoint of the GHL.
You need to add the below lines of code to define the deletion function:
def appointment_deletion(arguments):
try:
id = get_all_booked_appointment(arguments)
if id == "Please select valid event number" or id == "No registered event found with this email ID." or id == "We are facing an error while processing your request. Please try again.":
return id
else:
url = f"https://rest.gohighlevel.com/v1/appointments/{id}"
payload={}
response = requests.request("DELETE", url, headers=headers, data=payload)
if response.text == "OK":
return "Appointment deleted successfully."
except:
return "We are facing an error while processing your request. Please try again."
Now, we need to define the function specifications for appointment creation, updation, and deletion. These function specifications will be passed to ChatGPT, enabling it to determine which function to invoke based on the user’s argument.
functions = [
{
"name": "appointment_booking",
"description": "When user want to book appointment, then this function should be called.",
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"format": "date",
"example":"2023-07-23",
"description": "Date, when the user wants to book an appointment. The date must be in the format of YYYY-MM-DD.",
},
"time": {
"type": "string",
"example": "20:12:45",
"description": "time, on which user wants to book an appointment on a specified date. Time must be in %H:%M:%S format.",
},
"email_address": {
"type": "string",
"description": "email_address of the user gives for identification.",
},
"phone_number":{
"type" : "string",
"description": "Phone number given by user for identification."
}
},
"required": ["date","time","email_address","phone_number"],
},
},
{
"name": "appointment_updation",
"description": "When user want to reschedule appointment, then this function should be called.",
"parameters": {
"type": "object",
"properties": {
"to_date": {
"type": "string",
"format": "date",
"example":"2023-07-23",
"description": "It is the date on which the user wants to reschedule the appointment. The date must be in the format of YYYY-MM-DD.",
},
"date": {
"type": "string",
"format": "date",
"example":"2023-07-23",
"description": "It is the date from which the user wants to reschedule his/her appointment. The date must be in the format of YYYY-MM-DD.",
},
"time": {
"type": "string",
"example":"4:00:00",
"description": "It is the time on which the user wants to reschedule an appointment. Time must be in %H:%M:%S format.",
},
"email_address": {
"type": "string",
"description": "email_address of the user gives for identification.",
}
},
"required": ["date","to_date","time","email_address"],
},
},
{
"name": "appointment_deletion",
"description": "When user want to delete appointment, then this function should be called.",
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"format": "date",
"example":"2023-07-23",
"description": "Date, on which user has an appointment and wants to delete it. The date must be in the format of YYYY-MM-DD.",
},
"email_address": {
"type": "string",
"description": "email_address of the user gives for identification.",
}
},
"required": ["date","email_address"],
},
}]
Now, we are ready to test the appointment booking chatbot. You just need to add the following lines of code to run the chatbot.
day_list = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
messages = [{"role": "system", "content": f"""You are an expert in booking appointments, who can fulfill appointment scheduling, rescheduling, and deletion very efficiently. You need to remember the below guidelines while processing user requests.
Guidelines:
- You will ask for the appointment date and time, phone number, and email address, when the user wants to book an appointment.
- When the user wants to reschedule an appointment, then you will ask for the current appointment date, new date and time for the appointment, and email address. If the user didn't remember the current appointment details then inform the user that rescheduling will not be possible without these details.
- You will ask email address every time, as it is a must for user identification.
- Don't make assumptions about what values to plug into functions, if the user does not provide any of the required parameters then you must need to ask for clarification.
- If a user request is ambiguous, you also need to ask for clarification.
- If a user didn't specify "ante meridiem (AM)" or "post meridiem (PM)" while providing the time, then you must have to ask for clarification. If the user didn't provide day, month, and year while giving the time then you must have to ask for clarification.
You must need to satisfy the above guidelines while processing the request. You need to remember that today's date is {date.today()}."""}]
user_input = input("Please enter your question here: (if you want to exit then write 'exit' or 'bye'.) ")
while user_input.strip().lower() != "exit" and user_input.strip().lower() != "bye":
messages.append({"role": "user", "content": user_input})
# calling chat_completion_request to call ChatGPT completion endpoint
chat_response = chat_completion_request(
messages, functions=functions
)
# fetch response of ChatGPT and call the function
assistant_message = chat_response.json()["choices"][0]["message"]
if assistant_message['content']:
print("Response is: ", assistant_message['content'])
messages.append({"role": "assistant", "content": assistant_message['content']})
else:
fn_name = assistant_message["function_call"]["name"]
arguments = assistant_message["function_call"]["arguments"]
function = locals()[fn_name]
result = function(arguments)
print("Response is: ", result)
user_input = input("Please enter your question here: ")
You can see the booked appointments by clicking on the “Calendars” option, under the main menu as shown below:
In this blog, we explored the process of creating an appointment booking chatbot using OpenAI’s function calling feature. We learned how to integrate the GoHighLevel calendar API, allowing our chatbot to seamlessly interact with the calendar system. This integration enables users to book appointments effortlessly by conversing with the chatbot.
Our experts in Generative AI, Python Programming, and Chatbot Development can help you build innovative solutions and scale your business faster.