Spaces:
Sleeping
Sleeping
Commit
·
a831891
1
Parent(s):
e1283cc
appointment booking - completed
Browse files
README.md
CHANGED
|
@@ -159,7 +159,9 @@ To stop the Streamlit app, press `Ctrl+C` in the terminal where the app is runni
|
|
| 159 |
**Prompt 1**: Book an appointment for priti.
|
| 160 |
**Prompt 2**: Yes or No.
|
| 161 |
**Reference**:
|
| 162 |
-

|
|
|
|
|
|
|
| 163 |
|
| 164 |
### 4. Customer Support
|
| 165 |
**Reference**:
|
|
|
|
| 159 |
**Prompt 1**: Book an appointment for priti.
|
| 160 |
**Prompt 2**: Yes or No.
|
| 161 |
**Reference**:
|
| 162 |
+

|
| 163 |
+

|
| 164 |
+
|
| 165 |
|
| 166 |
### 4. Customer Support
|
| 167 |
**Reference**:
|
screenshots/graph_appointment_booking.png
ADDED
|
src/langgraphagenticai/graph/graph_builder.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
| 1 |
-
from langgraph.graph import StateGraph
|
| 2 |
-
from langgraph.prebuilt import tools_condition
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
| 4 |
from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
|
| 5 |
from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
|
| 6 |
from src.langgraphagenticai.node.basic_chatbot_node import BasicChatbotNode
|
|
@@ -57,6 +60,54 @@ class GraphBuilder:
|
|
| 57 |
|
| 58 |
# Set entry point and compile graph
|
| 59 |
self.graph_builder.set_entry_point("chatbot")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
def setup_graph(self, usecase: str):
|
|
@@ -67,6 +118,8 @@ class GraphBuilder:
|
|
| 67 |
self.basic_chatbot_build_graph()
|
| 68 |
elif usecase == "Chatbot with Tool":
|
| 69 |
self.chatbot_with_tool_build_graph()
|
|
|
|
|
|
|
| 70 |
else:
|
| 71 |
raise ValueError("Invalid use case selected.")
|
| 72 |
return self.graph_builder.compile()
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, END, MessagesState
|
| 2 |
+
from langgraph.prebuilt import tools_condition,ToolNode
|
| 3 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 4 |
+
import datetime
|
| 5 |
+
#module import
|
| 6 |
+
from src.langgraphagenticai.tools.customtool import book_appointment, cancel_appointment, get_next_available_appointment
|
| 7 |
from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
|
| 8 |
from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
|
| 9 |
from src.langgraphagenticai.node.basic_chatbot_node import BasicChatbotNode
|
|
|
|
| 60 |
|
| 61 |
# Set entry point and compile graph
|
| 62 |
self.graph_builder.set_entry_point("chatbot")
|
| 63 |
+
|
| 64 |
+
# Nodes
|
| 65 |
+
def call_caller_model(self,state: MessagesState):
|
| 66 |
+
state["current_time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 67 |
+
response = self.caller_model.invoke(state)
|
| 68 |
+
return {"messages": [response]}
|
| 69 |
+
|
| 70 |
+
# Edges
|
| 71 |
+
def should_continue_caller(self,state: MessagesState):
|
| 72 |
+
messages = state["messages"]
|
| 73 |
+
last_message = messages[-1]
|
| 74 |
+
if not last_message.tool_calls:
|
| 75 |
+
return "end"
|
| 76 |
+
else:
|
| 77 |
+
return "continue"
|
| 78 |
+
|
| 79 |
+
def appointment_receptionist_bot_build_graph(self):
|
| 80 |
+
caller_tools = [book_appointment, get_next_available_appointment, cancel_appointment]
|
| 81 |
+
tool_node = ToolNode(caller_tools)
|
| 82 |
+
|
| 83 |
+
caller_pa_prompt = """You are a personal assistant, and need to help the user to book or cancel appointments, you should check the available appointments before booking anything. Be extremely polite, so much so that it is almost rude.
|
| 84 |
+
Current time: {current_time}
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
caller_chat_template = ChatPromptTemplate.from_messages([
|
| 88 |
+
("system", caller_pa_prompt),
|
| 89 |
+
("placeholder", "{messages}"),
|
| 90 |
+
])
|
| 91 |
+
|
| 92 |
+
self.caller_model = caller_chat_template | self.llm.bind_tools(caller_tools)
|
| 93 |
+
|
| 94 |
+
# Add Nodes
|
| 95 |
+
self.graph_builder.add_node("agent", self.call_caller_model)
|
| 96 |
+
self.graph_builder.add_node("action", tool_node)
|
| 97 |
+
|
| 98 |
+
# Add Edges
|
| 99 |
+
self.graph_builder.add_conditional_edges(
|
| 100 |
+
"agent",
|
| 101 |
+
self.should_continue_caller,
|
| 102 |
+
{
|
| 103 |
+
"continue": "action",
|
| 104 |
+
"end": END,
|
| 105 |
+
},
|
| 106 |
+
)
|
| 107 |
+
self.graph_builder.add_edge("action", "agent")
|
| 108 |
+
|
| 109 |
+
# Set Entry Point and build the graph
|
| 110 |
+
self.graph_builder.set_entry_point("agent")
|
| 111 |
|
| 112 |
|
| 113 |
def setup_graph(self, usecase: str):
|
|
|
|
| 118 |
self.basic_chatbot_build_graph()
|
| 119 |
elif usecase == "Chatbot with Tool":
|
| 120 |
self.chatbot_with_tool_build_graph()
|
| 121 |
+
elif usecase == "Appointment Receptionist":
|
| 122 |
+
self.appointment_receptionist_bot_build_graph()
|
| 123 |
else:
|
| 124 |
raise ValueError("Invalid use case selected.")
|
| 125 |
return self.graph_builder.compile()
|
src/langgraphagenticai/tools/customtool.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_core.tools import tool
|
| 2 |
+
import datetime
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
APPOINTMENTS = []
|
| 6 |
+
|
| 7 |
+
@tool
|
| 8 |
+
def get_next_available_appointment():
|
| 9 |
+
"""Returns the next available appointment"""
|
| 10 |
+
current_time = datetime.datetime.now()
|
| 11 |
+
return f"One appointment available at {current_time + datetime.timedelta(minutes=(30 - current_time.minute % 30))}"
|
| 12 |
+
|
| 13 |
+
@tool
|
| 14 |
+
def book_appointment(appointment_year: int, appointment_month: int, appointment_day: int, appointment_hour: int, appointment_minute: int, appointment_name: str):
|
| 15 |
+
"""Book an appointment at the given time, you must know the exact time to book
|
| 16 |
+
|
| 17 |
+
Args:
|
| 18 |
+
appointment_year: The year of the appointment
|
| 19 |
+
appointment_month: The month of the appointment
|
| 20 |
+
appointment_day: The day of the appointment
|
| 21 |
+
appointment_hour: The hour of the appointment
|
| 22 |
+
appointment_minute: The minute of the appointment
|
| 23 |
+
appointment_name: The name of the person booking the appointment
|
| 24 |
+
"""
|
| 25 |
+
time = datetime.datetime(appointment_year, appointment_month, appointment_day, appointment_hour, appointment_minute)
|
| 26 |
+
for appointment in APPOINTMENTS:
|
| 27 |
+
if appointment.time >= time and appointment.time < time + datetime.timedelta(minutes=30):
|
| 28 |
+
return f"Appointment at {time} is already booked"
|
| 29 |
+
APPOINTMENTS.append({"time": time, "name": appointment_name})
|
| 30 |
+
return f"Appointment booked for {time}"
|
| 31 |
+
|
| 32 |
+
@tool
|
| 33 |
+
def cancel_appointment(appointment_year: int, appointment_month: int, appointment_day: int, appointment_hour: int, appointment_minute: int):
|
| 34 |
+
"""Cancel the appointment at the given time
|
| 35 |
+
|
| 36 |
+
Args:
|
| 37 |
+
appointment_year: The year of the appointment
|
| 38 |
+
appointment_month: The month of the appointment
|
| 39 |
+
appointment_day: The day of the appointment
|
| 40 |
+
appointment_hour: The hour of the appointment
|
| 41 |
+
appointment_minute: The minute of the appointment
|
| 42 |
+
"""
|
| 43 |
+
time = datetime.datetime(appointment_year, appointment_month, appointment_day, appointment_hour, appointment_minute)
|
| 44 |
+
for appointment in APPOINTMENTS:
|
| 45 |
+
if appointment["time"] == time:
|
| 46 |
+
APPOINTMENTS.remove(appointment)
|
| 47 |
+
return f"Appointment at {time} cancelled"
|
| 48 |
+
return f"No appointment found at {time}"
|
src/langgraphagenticai/ui/streamlitui/display_result.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
|
| 3 |
|
|
|
|
|
|
|
| 4 |
class DisplayResultStreamlit:
|
| 5 |
def __init__(self,usecase,graph,user_message):
|
| 6 |
self.usecase= usecase
|
|
@@ -37,8 +39,30 @@ class DisplayResultStreamlit:
|
|
| 37 |
elif type(message)==AIMessage and message.content:
|
| 38 |
with st.chat_message("assistant"):
|
| 39 |
st.write(message.content)
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
|
| 3 |
|
| 4 |
+
from src.langgraphagenticai.tools.customtool import APPOINTMENTS
|
| 5 |
+
|
| 6 |
class DisplayResultStreamlit:
|
| 7 |
def __init__(self,usecase,graph,user_message):
|
| 8 |
self.usecase= usecase
|
|
|
|
| 39 |
elif type(message)==AIMessage and message.content:
|
| 40 |
with st.chat_message("assistant"):
|
| 41 |
st.write(message.content)
|
| 42 |
+
elif usecase == "Appointment Receptionist":
|
| 43 |
+
CONVERSATION=[]
|
| 44 |
+
CONVERSATION.append(HumanMessage(content=user_message, type="human"))
|
| 45 |
+
state = {
|
| 46 |
+
"messages": CONVERSATION,
|
| 47 |
+
}
|
| 48 |
+
print(state)
|
| 49 |
+
new_state = graph.invoke(state)
|
| 50 |
+
CONVERSATION.extend(new_state["messages"][len(CONVERSATION):])
|
| 51 |
+
col1, col2 = st.columns(2)
|
| 52 |
+
with col1:
|
| 53 |
+
for message in CONVERSATION:
|
| 54 |
+
if message and message.content:
|
| 55 |
+
if type(message) == HumanMessage:
|
| 56 |
+
with st.chat_message("user"):
|
| 57 |
+
st.write(message.content)
|
| 58 |
+
else:
|
| 59 |
+
with st.chat_message("assistant"):
|
| 60 |
+
st.write(message.content)
|
| 61 |
+
|
| 62 |
+
with col2:
|
| 63 |
+
st.header("Appointments")
|
| 64 |
+
st.write(APPOINTMENTS)
|
| 65 |
+
# display graph
|
| 66 |
+
if graph:
|
| 67 |
+
st.write('state graph - workflow')
|
| 68 |
+
st.image(graph.get_graph(xray=True).draw_mermaid_png())
|
src/langgraphagenticai/ui/streamlitui/loadui.py
CHANGED
|
@@ -40,15 +40,10 @@ class LoadStreamlitUI:
|
|
| 40 |
|
| 41 |
if self.user_controls['selected_usecase'] == "Appointment Receptionist":
|
| 42 |
col1, col2 = st.columns(2)
|
| 43 |
-
|
| 44 |
with col1:
|
| 45 |
st.subheader("Appointment Manager")
|
| 46 |
-
|
| 47 |
with col2:
|
| 48 |
st.subheader("Appointments")
|
| 49 |
-
|
| 50 |
-
# TODO :: to be removed
|
| 51 |
-
st.warning("⌛Revamp is in progress...")
|
| 52 |
|
| 53 |
elif self.user_controls['selected_usecase']=="Customer Support":
|
| 54 |
# TODO :: to be removed
|
|
|
|
| 40 |
|
| 41 |
if self.user_controls['selected_usecase'] == "Appointment Receptionist":
|
| 42 |
col1, col2 = st.columns(2)
|
|
|
|
| 43 |
with col1:
|
| 44 |
st.subheader("Appointment Manager")
|
|
|
|
| 45 |
with col2:
|
| 46 |
st.subheader("Appointments")
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
elif self.user_controls['selected_usecase']=="Customer Support":
|
| 49 |
# TODO :: to be removed
|