genaitiwari commited on
Commit
e8b7d05
Β·
1 Parent(s): 3c3c588

travel planner - completed

Browse files
README.md CHANGED
@@ -168,6 +168,11 @@ To stop the Streamlit app, press `Ctrl+C` in the terminal where the app is runni
168
  ![cs flow](screenshots/cs_flow.png)
169
  ![customer support](screenshots/customer_support.png)
170
 
 
 
 
 
 
171
  ---
172
 
173
  ## πŸ“š Templates & Community
 
168
  ![cs flow](screenshots/cs_flow.png)
169
  ![customer support](screenshots/customer_support.png)
170
 
171
+ ### 5. Travel Planner
172
+ **Reference**:
173
+ ![tp flow](screenshots/tp_flow.png)
174
+ ![Travel planner](screenshots/travel_planner.png)
175
+
176
  ---
177
 
178
  ## πŸ“š Templates & Community
screenshots/tp_flow.png ADDED
screenshots/travel_planner.png ADDED
src/langgraphagenticai/graph/graph_builder.py CHANGED
@@ -3,12 +3,14 @@ from langgraph.prebuilt import tools_condition,ToolNode
3
  from langchain_core.prompts import ChatPromptTemplate
4
  import datetime
5
  #module import
 
6
  from src.langgraphagenticai.node.customer_support_chatbot import Customer_Support_Bot
7
  from src.langgraphagenticai.tools.customtool import book_appointment, cancel_appointment, get_next_available_appointment
8
  from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
9
  from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
10
  from src.langgraphagenticai.node.basic_chatbot_node import BasicChatbotNode
11
  from src.langgraphagenticai.state.state import State
 
12
 
13
  class GraphBuilder:
14
  """
@@ -62,6 +64,23 @@ class GraphBuilder:
62
  # Set entry point and compile graph
63
  self.graph_builder.set_entry_point("chatbot")
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  # Nodes
66
  def call_caller_model(self,state: MessagesState):
67
  state["current_time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
@@ -122,6 +141,8 @@ class GraphBuilder:
122
  self.basic_chatbot_build_graph()
123
  elif usecase == "Chatbot with Tool":
124
  self.chatbot_with_tool_build_graph()
 
 
125
  elif usecase == "Appointment Receptionist":
126
  self.appointment_receptionist_bot_build_graph()
127
  elif usecase =="Customer Support":
 
3
  from langchain_core.prompts import ChatPromptTemplate
4
  import datetime
5
  #module import
6
+ from src.langgraphagenticai.node import travel_planner_node
7
  from src.langgraphagenticai.node.customer_support_chatbot import Customer_Support_Bot
8
  from src.langgraphagenticai.tools.customtool import book_appointment, cancel_appointment, get_next_available_appointment
9
  from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
10
  from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
11
  from src.langgraphagenticai.node.basic_chatbot_node import BasicChatbotNode
12
  from src.langgraphagenticai.state.state import State
13
+ from src.langgraphagenticai.node.travel_planner_node import TravelPlannerNode
14
 
15
  class GraphBuilder:
16
  """
 
64
  # Set entry point and compile graph
65
  self.graph_builder.set_entry_point("chatbot")
66
 
67
+ def travel_planner_build_graph(self):
68
+ """
69
+ Builds a standalone travel planning graph with itinerary generation.
70
+ """
71
+ # Initialize the Travel Planner node
72
+ travel_planner_node = TravelPlannerNode(self.llm)
73
+
74
+ # Add the Travel Planner node to the graph
75
+ self.graph_builder.add_node("travel_planner", travel_planner_node.process)
76
+
77
+ # Set the entry point to the Travel Planner node
78
+ self.graph_builder.set_entry_point("travel_planner")
79
+
80
+ # Define the edge to end the graph after the Travel Planner completes
81
+ self.graph_builder.add_edge("travel_planner", END)
82
+
83
+ # Helper methods
84
  # Nodes
85
  def call_caller_model(self,state: MessagesState):
86
  state["current_time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
 
141
  self.basic_chatbot_build_graph()
142
  elif usecase == "Chatbot with Tool":
143
  self.chatbot_with_tool_build_graph()
144
+ elif usecase == "Travel Planner":
145
+ self.travel_planner_build_graph()
146
  elif usecase == "Appointment Receptionist":
147
  self.appointment_receptionist_bot_build_graph()
148
  elif usecase =="Customer Support":
src/langgraphagenticai/main.py CHANGED
@@ -4,6 +4,7 @@ from src.langgraphagenticai.graph.graph_builder import GraphBuilder
4
  from src.langgraphagenticai.ui.streamlitui.loadui import LoadStreamlitUI
5
 
6
  import streamlit as st
 
7
 
8
 
9
  # MAIN Function START
@@ -52,6 +53,17 @@ def load_langgraph_agenticai_app():
52
 
53
  # Display output in UI
54
  try:
 
 
 
 
 
 
 
 
 
 
 
55
  DisplayResultStreamlit(usecase,graph,user_message).display_result_on_ui()
56
  except Exception as e:
57
  st.error(f"Error: Failed to display results on UI - {e}")
@@ -62,19 +74,4 @@ def load_langgraph_agenticai_app():
62
  except Exception as e:
63
  st.error(f"Unexpected error occurred: {e}")
64
 
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
 
4
  from src.langgraphagenticai.ui.streamlitui.loadui import LoadStreamlitUI
5
 
6
  import streamlit as st
7
+ import json
8
 
9
 
10
  # MAIN Function START
 
53
 
54
  # Display output in UI
55
  try:
56
+ # Add travel-specific parameters to message
57
+ if usecase == "Travel Planner":
58
+ travel_params = {
59
+ 'source' : user_input.get('source'),
60
+ 'city': user_input.get('destination'),
61
+ 'start_date': user_input.get('start_date').isoformat(),
62
+ 'end_date': user_input.get('end_date').isoformat(),
63
+ 'interests': user_input.get('preferences'),
64
+ 'user_message' : user_message
65
+ }
66
+ user_message = travel_params
67
  DisplayResultStreamlit(usecase,graph,user_message).display_result_on_ui()
68
  except Exception as e:
69
  st.error(f"Error: Failed to display results on UI - {e}")
 
74
  except Exception as e:
75
  st.error(f"Unexpected error occurred: {e}")
76
 
77
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/langgraphagenticai/node/travel_planner_node.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict
2
+ from langchain_core.prompts import ChatPromptTemplate
3
+ from src.langgraphagenticai.state.state import State
4
+ from langchain_core.messages import HumanMessage, AIMessage
5
+ import json
6
+
7
+ class TravelPlannerNode:
8
+ """
9
+ Travel Planner logic implementation.
10
+ """
11
+ def __init__(self, model):
12
+ self.llm = model
13
+ self.itinerary_prompt = ChatPromptTemplate.from_messages([
14
+ ("system", "You are a creative and detail-oriented travel assistant. Create a visually appealing and highly detailed travel itinerary from {source} to {city} for the user. "
15
+ "The itinerary should be based on the user's interests: {interests} and their additional request: {user_message}. "
16
+ "The trip will take place from {start_date} to {end_date}. "
17
+ "**Follow these guidelines to create the itinerary:**\n"
18
+ "1. **Structure:** Organize the itinerary into clear sections with subheadings for each day (e.g., 'Day 1: Arrival and Exploration').\n"
19
+ "2. **Activities:** Include a mix of activities (e.g., sightseeing, dining, adventure, relaxation) tailored to the user's interests.\n"
20
+ "3. **Flights and Accommodations:** Provide flight options (if applicable) and recommend accommodations with actual links to their location on Google Maps.\n"
21
+ "4. **Cost Estimation:** Add approximate costs for activities, flights, and accommodations.\n"
22
+ "5. **Emojis:** Use relevant emojis (e.g., ✈️ for flights, 🏨 for hotels, 🍽️ for dining) to make the itinerary visually engaging.\n"
23
+ "6. **Markdown Formatting:** Use bullet points, bold text, and subheadings for clarity and readability.\n"
24
+ "7. **Links:** Include clickable links for booking flights, accommodations, and activity reservations where applicable.\n"
25
+ "8. **No Introductory Explanation:** Jump straight into the itinerary without unnecessary introductions.\n"
26
+ "**Example Format:**\n"
27
+ "### Day 1: Arrival in {city} ✈️\n"
28
+ "- **Morning:** Arrive at {city} Airport. Transfer to your hotel 🏨. [Hotel Map Link](https://maps.google.com)\n"
29
+ "- **Afternoon:** Explore landmark and enjoy lunch at restaurant 🍽️. (Cost: ~ 50)\n"
30
+ "- **Evening:** Relax at location and enjoy dinner at restaurant 🍷. (Cost: ~ 70)\n"
31
+ "### Day 2: Adventure and Sightseeing πŸŒ„\n"
32
+ "- **Morning:** Visit attraction and enjoy activity. (Cost: ~ 30)\n"
33
+ "- **Afternoon:** Lunch at restaurant 🍽️. (Cost: ~ 40)\n"
34
+ "- **Evening:** Explore location and enjoy a guided tour. (Cost: ~ 60)\n"
35
+ "Ensure the itinerary is engaging, practical, and tailored to the user's preferences and cost should be in local currency"),
36
+ ("human", "Create an itinerary for my trip"),
37
+ ])
38
+ def process(self, state: State) -> Dict:
39
+ """
40
+ Processes the input state and generates a travel itinerary.
41
+ """
42
+ # Validate required fields
43
+ content_str = state.get("messages")[0].content.replace("'", '"')
44
+ content = json.loads(content_str)
45
+
46
+ # Validate required fields
47
+ if not content.get("city") or not content.get("interests") or not content.get("start_date") or not content.get("end_date"):
48
+ return {
49
+ "messages": [AIMessage(content="Please provide a city, interests, start date, and end date to generate an itinerary.")],
50
+ "itinerary": ""
51
+ }
52
+
53
+ # Generate the itinerary using the LLM
54
+ response = self.llm.invoke(self.itinerary_prompt.format_messages(
55
+ source=content["source"],
56
+ user_message = content["user_message"],
57
+ city=content["city"],
58
+ interests=content["interests"], # No need to join, as it's already a string
59
+ start_date=content["start_date"],
60
+ end_date=content["end_date"]
61
+ ))
62
+
63
+ # Update the state with the generated itinerary
64
+ return {
65
+ "messages": state.get("messages", []) + [AIMessage(content=response.content)], # Safely access "messages"
66
+ "itinerary": AIMessage(content=response.content),
67
+ "city": content["city"],
68
+ "interests": content["interests"],
69
+ "start_date": content["start_date"],
70
+ "end_date": content["end_date"]
71
+ }
src/langgraphagenticai/state/state.py CHANGED
@@ -1,9 +1,20 @@
1
  from typing import Annotated
2
  from typing_extensions import TypedDict
3
  from langgraph.graph.message import add_messages
 
 
4
 
5
  class State(TypedDict):
6
  """
7
  Represents the structure of the state used in the graph.
8
  """
9
  messages: Annotated[list, add_messages]
 
 
 
 
 
 
 
 
 
 
1
  from typing import Annotated
2
  from typing_extensions import TypedDict
3
  from langgraph.graph.message import add_messages
4
+ from typing import TypedDict, Annotated, List
5
+ from langchain_core.messages import HumanMessage, AIMessage
6
 
7
  class State(TypedDict):
8
  """
9
  Represents the structure of the state used in the graph.
10
  """
11
  messages: Annotated[list, add_messages]
12
+
13
+
14
+ class PlannerState(TypedDict):
15
+ messages: Annotated[List[HumanMessage | AIMessage], "Conversation history"]
16
+ city: str
17
+ interests: List[str]
18
+ itinerary: str
19
+ start_date: str
20
+ end_date: str
src/langgraphagenticai/ui/streamlitui/display_result.py CHANGED
@@ -1,5 +1,6 @@
1
  import streamlit as st
2
  from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
 
3
 
4
  from src.langgraphagenticai.tools.customtool import APPOINTMENTS
5
  from src.langgraphagenticai.tools.customer_support_tools import customers_database, data_protection_checks
@@ -40,6 +41,8 @@ class DisplayResultStreamlit:
40
  elif type(message)==AIMessage and message.content:
41
  with st.chat_message("assistant"):
42
  st.write(message.content)
 
 
43
  elif usecase == "Appointment Receptionist":
44
  CONVERSATION=[]
45
  CONVERSATION.append(HumanMessage(content=user_message, type="human"))
@@ -88,4 +91,61 @@ class DisplayResultStreamlit:
88
  # display graph
89
  if graph:
90
  st.write('state graph - workflow')
91
- st.image(graph.get_graph(xray=True).draw_mermaid_png())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
3
+ import json
4
 
5
  from src.langgraphagenticai.tools.customtool import APPOINTMENTS
6
  from src.langgraphagenticai.tools.customer_support_tools import customers_database, data_protection_checks
 
41
  elif type(message)==AIMessage and message.content:
42
  with st.chat_message("assistant"):
43
  st.write(message.content)
44
+ elif usecase == "Travel Planner":
45
+ self._display_travel_planner_results()
46
  elif usecase == "Appointment Receptionist":
47
  CONVERSATION=[]
48
  CONVERSATION.append(HumanMessage(content=user_message, type="human"))
 
91
  # display graph
92
  if graph:
93
  st.write('state graph - workflow')
94
+ st.image(graph.get_graph(xray=True).draw_mermaid_png())
95
+
96
+ def _display_travel_planner_results(self):
97
+ # Extract travel parameters from message
98
+ CONVERSATION=[]
99
+ CONVERSATION.append(HumanMessage(content=str(self.user_message), type="human"))
100
+ state = {
101
+ "messages": CONVERSATION,
102
+ }
103
+ print(state)
104
+ # Invoke the graph
105
+ response = self.graph.invoke(state)
106
+
107
+ # Display results
108
+ main_col, side_col = st.columns([3, 1])
109
+
110
+ with main_col:
111
+ st.subheader("✈️ Travel Itinerary")
112
+ if type(response['messages'][1]) == AIMessage:
113
+ self._display_itinerary_details(response['messages'][1].content)
114
+ else:
115
+ st.warning("No itinerary generated yet.")
116
+
117
+ with side_col:
118
+ st.subheader("πŸ“Œ Travel Details")
119
+ st.json({
120
+ "πŸ“ Source": self.user_message.get('source', ''),
121
+ "πŸ“ Destination": self.user_message.get('city', ''),
122
+ "πŸ“… Dates": f"{self.user_message.get('start_date', '')} to {self.user_message.get('end_date', '')}",
123
+ "🎯 Interests": self.user_message.get('interests', ''),
124
+ "πŸ§‘β€πŸ’» User Addition Request": self.user_message.get('user_message', '')
125
+ })
126
+
127
+ def _display_itinerary_details(self, itinerary_content):
128
+ """
129
+ Displays the itinerary details in a structured format.
130
+ """
131
+ with st.expander("πŸ“… Full Itinerary"):
132
+ # Parse the itinerary content
133
+ sections = {
134
+ "Destination": itinerary_content
135
+ }
136
+
137
+ # Display destination and dates
138
+ st.markdown(f"{sections['Destination']}")
139
+
140
+
141
+ def _display_tool_calls(self, message):
142
+ """
143
+ Displays details of tool calls made during the itinerary generation.
144
+ """
145
+ with st.expander("βš™οΈ System Operations"):
146
+ st.markdown("**πŸ”§ Tool Execution Details**")
147
+ st.json({
148
+ "Tool Used": message.name,
149
+ "Parameters": message.additional_kwargs,
150
+ "Result": message.content
151
+ })
src/langgraphagenticai/ui/streamlitui/loadui.py CHANGED
@@ -1,5 +1,6 @@
1
  import streamlit as st
2
  import os
 
3
 
4
  from src.langgraphagenticai.ui.uiconfigfile import Config
5
  from langchain_core.messages import AIMessage, HumanMessage
@@ -29,7 +30,10 @@ class LoadStreamlitUI:
29
  # API key input
30
  self.user_controls["GROQ_API_KEY"] = st.session_state["GROQ_API_KEY"] = st.text_input("API Key",
31
  type="password")
32
-
 
 
 
33
 
34
  # Use case selection
35
  self.user_controls["selected_usecase"] = st.selectbox("Select Usecases", usecase_options)
@@ -64,7 +68,31 @@ class LoadStreamlitUI:
64
  if st.button('Clear Chat'):
65
  st.session_state.message_history = []
66
 
67
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
 
70
  return self.user_controls
 
1
  import streamlit as st
2
  import os
3
+ from datetime import date
4
 
5
  from src.langgraphagenticai.ui.uiconfigfile import Config
6
  from langchain_core.messages import AIMessage, HumanMessage
 
30
  # API key input
31
  self.user_controls["GROQ_API_KEY"] = st.session_state["GROQ_API_KEY"] = st.text_input("API Key",
32
  type="password")
33
+ # Validate API key
34
+ if not self.user_controls["GROQ_API_KEY"]:
35
+ st.warning("⚠️ Please enter your GROQ API key to proceed.")
36
+
37
 
38
  # Use case selection
39
  self.user_controls["selected_usecase"] = st.selectbox("Select Usecases", usecase_options)
 
68
  if st.button('Clear Chat'):
69
  st.session_state.message_history = []
70
 
71
+ elif self.user_controls['selected_usecase']=="Travel Planner":
72
+ st.subheader("✈️ AI Travel Planner")
73
+ col1, col2 = st.columns(2)
74
+
75
+ with col1:
76
+ source = st.text_input("πŸ“ Source", value="London", help="Enter your travel source")
77
+ destination = st.text_input("πŸ“ Destination", value="Goa", help="Enter your travel destination")
78
+ preferences = st.text_area(
79
+ "🎯 Travel Preferences",
80
+ placeholder="E.g., I prefer beach destinations, luxury stays, and adventure activities.",
81
+ help="Describe your travel preferences"
82
+ )
83
+
84
+ with col2:
85
+ start_date = st.date_input("πŸ“… Start Date", value=date.today(), help="Select your travel start date")
86
+ end_date = st.date_input("πŸ“… End Date", value=date.today(), help="Select your travel end date")
87
+
88
+ if destination and preferences and start_date and end_date:
89
+ self.user_controls.update({
90
+ "source": source,
91
+ "destination": destination,
92
+ "preferences": preferences,
93
+ "start_date": start_date,
94
+ "end_date": end_date,
95
+ })
96
 
97
 
98
  return self.user_controls
src/langgraphagenticai/ui/uiconfigfile.ini CHANGED
@@ -1,6 +1,6 @@
1
  [DEFAULT]
2
  PAGE_TITLE = LangGraph: Build Stateful Agentic AI graph
3
  LLM_OPTIONS = Groq
4
- USECASE_OPTIONS = Basic Chatbot, Chatbot with Tool, Appointment Receptionist, Customer Support
5
  GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i
6
 
 
1
  [DEFAULT]
2
  PAGE_TITLE = LangGraph: Build Stateful Agentic AI graph
3
  LLM_OPTIONS = Groq
4
+ USECASE_OPTIONS = Basic Chatbot, Chatbot with Tool, Travel Planner, Appointment Receptionist, Customer Support
5
  GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i
6