Spaces:
Runtime error
Runtime error
DylanonWic
commited on
Commit
•
7118dfb
1
Parent(s):
edd1568
Upload 11 files
Browse files- chatbot.ipynb +530 -75
- chatbot.py +64 -74
- prompt.json +7 -0
- tools.ipynb +17 -29
- tools.py +53 -11
- utils.py +7 -0
chatbot.ipynb
CHANGED
@@ -17,99 +17,90 @@
|
|
17 |
"cell_type": "code",
|
18 |
"execution_count": 2,
|
19 |
"metadata": {},
|
20 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
"source": [
|
22 |
-
"from typing import Annotated, Literal, TypedDict\n",
|
23 |
-
"\n",
|
24 |
"from langchain_core.messages import HumanMessage\n",
|
25 |
"\n",
|
26 |
"# for llm model\n",
|
27 |
-
"from langchain_anthropic import ChatAnthropic\n",
|
28 |
"from langchain_openai import ChatOpenAI\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
"\n",
|
30 |
-
"
|
31 |
-
"
|
32 |
-
"from langgraph.graph import END, StateGraph, MessagesState\n",
|
33 |
-
"from langgraph.prebuilt import ToolNode\n",
|
34 |
-
"import tools\n",
|
35 |
-
"\n",
|
36 |
-
"\n",
|
37 |
-
"tool_node = tools.tool_node\n",
|
38 |
-
"tools.tools\n",
|
39 |
-
"\n",
|
40 |
-
"# model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\", temperature=0).bind_tools(tools)\n",
|
41 |
-
"model = ChatOpenAI(model=\"gpt-4o-mini\")\n",
|
42 |
-
"\n",
|
43 |
-
"# Define the function that determines whether to continue or not\n",
|
44 |
-
"def should_continue(state: MessagesState) -> Literal[\"tools\", END]:\n",
|
45 |
-
" messages = state['messages']\n",
|
46 |
-
" last_message = messages[-1]\n",
|
47 |
-
" # If the LLM makes a tool call, then we route to the \"tools\" node\n",
|
48 |
-
" if last_message.tool_calls:\n",
|
49 |
-
" return \"tools\"\n",
|
50 |
-
" # Otherwise, we stop (reply to the user)\n",
|
51 |
-
" return END\n",
|
52 |
-
"\n",
|
53 |
-
"\n",
|
54 |
-
"# Define the function that calls the model\n",
|
55 |
-
"def call_model(state: MessagesState):\n",
|
56 |
-
" messages = state['messages']\n",
|
57 |
-
" response = model.invoke(messages)\n",
|
58 |
-
" # We return a list, because this will get added to the existing list\n",
|
59 |
-
" return {\"messages\": [response]}\n",
|
60 |
"\n",
|
|
|
61 |
"\n",
|
62 |
-
"
|
63 |
-
"workflow = StateGraph(MessagesState)\n",
|
64 |
"\n",
|
65 |
-
"
|
66 |
-
"
|
67 |
-
"
|
|
|
|
|
|
|
68 |
"\n",
|
69 |
-
"
|
70 |
-
"# This means that this node is the first one called\n",
|
71 |
-
"workflow.set_entry_point(\"agent\")\n",
|
72 |
"\n",
|
73 |
-
"
|
74 |
-
"
|
75 |
-
"
|
76 |
-
"
|
77 |
-
"
|
78 |
-
"
|
79 |
-
"
|
80 |
")\n",
|
81 |
"\n",
|
82 |
-
"
|
83 |
-
"
|
84 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
"\n",
|
86 |
-
"# Initialize memory to persist state between graph runs\n",
|
87 |
-
"checkpointer = MemorySaver()\n",
|
88 |
"\n",
|
89 |
-
"
|
90 |
-
"
|
91 |
-
"
|
92 |
-
"
|
93 |
-
"app = workflow.compile(checkpointer=checkpointer)"
|
94 |
-
]
|
95 |
-
},
|
96 |
-
{
|
97 |
-
"cell_type": "code",
|
98 |
-
"execution_count": 6,
|
99 |
-
"metadata": {},
|
100 |
-
"outputs": [],
|
101 |
-
"source": [
|
102 |
-
"def submitUserMessage(message:str):\n",
|
103 |
-
" final_state = app.invoke(\n",
|
104 |
-
" {\"messages\": [HumanMessage(content=message)]},\n",
|
105 |
-
" config={\"configurable\": {\"thread_id\": 42}}\n",
|
106 |
" )\n",
|
107 |
-
"
|
|
|
|
|
|
|
|
|
108 |
]
|
109 |
},
|
110 |
{
|
111 |
"cell_type": "code",
|
112 |
-
"execution_count":
|
113 |
"metadata": {},
|
114 |
"outputs": [
|
115 |
{
|
@@ -126,22 +117,486 @@
|
|
126 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
127 |
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
128 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
130 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
|
131 |
]
|
132 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
{
|
134 |
"data": {
|
135 |
"text/plain": [
|
136 |
-
"
|
137 |
]
|
138 |
},
|
139 |
-
"execution_count":
|
140 |
"metadata": {},
|
141 |
"output_type": "execute_result"
|
142 |
}
|
143 |
],
|
144 |
"source": [
|
|
|
|
|
|
|
|
|
145 |
"submitUserMessage(\"ค้นหาร้านกาแฟใกล้มาบุญครอง\")"
|
146 |
]
|
147 |
}
|
|
|
17 |
"cell_type": "code",
|
18 |
"execution_count": 2,
|
19 |
"metadata": {},
|
20 |
+
"outputs": [
|
21 |
+
{
|
22 |
+
"name": "stderr",
|
23 |
+
"output_type": "stream",
|
24 |
+
"text": [
|
25 |
+
"/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:141: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.0.10 and will be removed in 0.3.0. An updated version of the class exists in the langchain-openai package and should be used instead. To use it run `pip install -U langchain-openai` and import as `from langchain_openai import ChatOpenAI`.\n",
|
26 |
+
" warn_deprecated(\n",
|
27 |
+
"/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:141: LangChainDeprecationWarning: The function `format_tool_to_openai_function` was deprecated in LangChain 0.1.16 and will be removed in 1.0. Use langchain_core.utils.function_calling.convert_to_openai_function() instead.\n",
|
28 |
+
" warn_deprecated(\n"
|
29 |
+
]
|
30 |
+
}
|
31 |
+
],
|
32 |
"source": [
|
|
|
|
|
33 |
"from langchain_core.messages import HumanMessage\n",
|
34 |
"\n",
|
35 |
"# for llm model\n",
|
|
|
36 |
"from langchain_openai import ChatOpenAI\n",
|
37 |
+
"from langchain.agents.format_scratchpad import format_to_openai_function_messages\n",
|
38 |
+
"from tools import find_place_from_text, nearby_search\n",
|
39 |
+
"from typing import Dict, List, Tuple\n",
|
40 |
+
"from langchain.agents import (\n",
|
41 |
+
" AgentExecutor,\n",
|
42 |
+
")\n",
|
43 |
+
"from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser\n",
|
44 |
+
"from langchain_community.chat_models import ChatOpenAI\n",
|
45 |
+
"from langchain_community.tools.convert_to_openai import format_tool_to_openai_function\n",
|
46 |
+
"from langchain_core.messages import AIMessage, HumanMessage\n",
|
47 |
+
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
|
48 |
+
"from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
|
49 |
"\n",
|
50 |
+
"# Bind the tools to the model\n",
|
51 |
+
"tools = [find_place_from_text, nearby_search] # Include both tools if needed\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
"\n",
|
53 |
+
"llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
|
54 |
"\n",
|
55 |
+
"llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])\n",
|
|
|
56 |
"\n",
|
57 |
+
"def _format_chat_history(chat_history: List[Tuple[str, str]]):\n",
|
58 |
+
" buffer = []\n",
|
59 |
+
" for human, ai in chat_history:\n",
|
60 |
+
" buffer.append(HumanMessage(content=human))\n",
|
61 |
+
" buffer.append(AIMessage(content=ai))\n",
|
62 |
+
" return buffer\n",
|
63 |
"\n",
|
64 |
+
"meta = utils.load_agent_meta()[0]\n",
|
|
|
|
|
65 |
"\n",
|
66 |
+
"prompt = ChatPromptTemplate.from_messages(\n",
|
67 |
+
" [\n",
|
68 |
+
" (\"system\", meta['prompt']),\n",
|
69 |
+
" MessagesPlaceholder(variable_name=\"chat_history\"),\n",
|
70 |
+
" (\"user\", \"{input}\"),\n",
|
71 |
+
" MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n",
|
72 |
+
" ]\n",
|
73 |
")\n",
|
74 |
"\n",
|
75 |
+
"agent = (\n",
|
76 |
+
" {\n",
|
77 |
+
" \"input\": lambda x: x[\"input\"],\n",
|
78 |
+
" \"chat_history\": lambda x: _format_chat_history(x[\"chat_history\"]),\n",
|
79 |
+
" \"agent_scratchpad\": lambda x: format_to_openai_function_messages(\n",
|
80 |
+
" x[\"intermediate_steps\"]\n",
|
81 |
+
" ),\n",
|
82 |
+
" }\n",
|
83 |
+
" | prompt\n",
|
84 |
+
" | llm_with_tools\n",
|
85 |
+
" | OpenAIFunctionsAgentOutputParser()\n",
|
86 |
+
")\n",
|
87 |
"\n",
|
|
|
|
|
88 |
"\n",
|
89 |
+
"class AgentInput(BaseModel):\n",
|
90 |
+
" input: str\n",
|
91 |
+
" chat_history: List[Tuple[str, str]] = Field(\n",
|
92 |
+
" ..., extra={\"widget\": {\"type\": \"chat\", \"input\": \"input\", \"output\": \"output\"}}\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
" )\n",
|
94 |
+
"\n",
|
95 |
+
"\n",
|
96 |
+
"agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True).with_types(\n",
|
97 |
+
" input_type=AgentInput\n",
|
98 |
+
")\n"
|
99 |
]
|
100 |
},
|
101 |
{
|
102 |
"cell_type": "code",
|
103 |
+
"execution_count": 3,
|
104 |
"metadata": {},
|
105 |
"outputs": [
|
106 |
{
|
|
|
117 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
118 |
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
119 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
120 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
121 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
122 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
123 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
124 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
125 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
|
126 |
+
]
|
127 |
+
},
|
128 |
+
{
|
129 |
+
"name": "stdout",
|
130 |
+
"output_type": "stream",
|
131 |
+
"text": [
|
132 |
+
"\n",
|
133 |
+
"\n",
|
134 |
+
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n"
|
135 |
+
]
|
136 |
+
},
|
137 |
+
{
|
138 |
+
"name": "stderr",
|
139 |
+
"output_type": "stream",
|
140 |
+
"text": [
|
141 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
142 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
143 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
144 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
|
145 |
+
]
|
146 |
+
},
|
147 |
+
{
|
148 |
+
"name": "stdout",
|
149 |
+
"output_type": "stream",
|
150 |
+
"text": [
|
151 |
+
"\u001b[32;1m\u001b[1;3m\n",
|
152 |
+
"Invoking: `nearby_search` with `{'input_dict': {'keyword': 'coffee shop', 'location_name': 'มาบุญครอง', 'radius': 1500, 'place_type': 'cafe'}}`\n",
|
153 |
+
"\n",
|
154 |
+
"\n",
|
155 |
+
"\u001b[0m"
|
156 |
+
]
|
157 |
+
},
|
158 |
+
{
|
159 |
+
"name": "stderr",
|
160 |
+
"output_type": "stream",
|
161 |
+
"text": [
|
162 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
163 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
164 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
165 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
166 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
167 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
168 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
169 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
170 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
171 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
172 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
173 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n",
|
174 |
+
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
175 |
+
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
|
176 |
+
]
|
177 |
+
},
|
178 |
+
{
|
179 |
+
"name": "stdout",
|
180 |
+
"output_type": "stream",
|
181 |
+
"text": [
|
182 |
+
"\u001b[33;1m\u001b[1;3m\n",
|
183 |
+
" address: 991/1 Rama I Rd, Pathum Wan\n",
|
184 |
+
"\n",
|
185 |
+
" location: {'lat': 13.7458781, 'lng': 100.5341476}\n",
|
186 |
+
"\n",
|
187 |
+
" name: BEANS Coffee Roaster Paragon\n",
|
188 |
+
"\n",
|
189 |
+
" opening hours: {'open_now': True}\n",
|
190 |
+
"\n",
|
191 |
+
" rating: 5\n",
|
192 |
+
"\n",
|
193 |
+
" plus code: 7P52PGWM+9M\n",
|
194 |
+
"\n",
|
195 |
+
"\n",
|
196 |
+
" \n",
|
197 |
+
" address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\n",
|
198 |
+
"\n",
|
199 |
+
" location: {'lat': 13.7497223, 'lng': 100.521221}\n",
|
200 |
+
"\n",
|
201 |
+
" name: Olympic Coffee\n",
|
202 |
+
"\n",
|
203 |
+
" opening hours: {'open_now': True}\n",
|
204 |
+
"\n",
|
205 |
+
" rating: 4.8\n",
|
206 |
+
"\n",
|
207 |
+
" plus code: 7P52PGXC+VF\n",
|
208 |
+
"\n",
|
209 |
+
"\n",
|
210 |
+
" \n",
|
211 |
+
" address: 994 Makkasan, Ratchathewi\n",
|
212 |
+
"\n",
|
213 |
+
" location: {'lat': 13.7495947, 'lng': 100.5426623}\n",
|
214 |
+
"\n",
|
215 |
+
" name: Earthy Roaster (Specialty Coffee)\n",
|
216 |
+
"\n",
|
217 |
+
" opening hours: {'open_now': True}\n",
|
218 |
+
"\n",
|
219 |
+
" rating: 4.8\n",
|
220 |
+
"\n",
|
221 |
+
" plus code: 7P52PGXV+R3\n",
|
222 |
+
"\n",
|
223 |
+
"\n",
|
224 |
+
" \n",
|
225 |
+
" address: MINT TOWER Bantadthong Phetchaburi Rd, Subdistrict Pathum Wan\n",
|
226 |
+
"\n",
|
227 |
+
" location: {'lat': 13.7450255, 'lng': 100.5235735}\n",
|
228 |
+
"\n",
|
229 |
+
" name: Treasure specialty coffee\n",
|
230 |
+
"\n",
|
231 |
+
" opening hours: {'open_now': True}\n",
|
232 |
+
"\n",
|
233 |
+
" rating: 4.9\n",
|
234 |
+
"\n",
|
235 |
+
" plus code: 7P52PGWF+2C\n",
|
236 |
+
"\n",
|
237 |
+
"\n",
|
238 |
+
" \n",
|
239 |
+
" address: ตึก Gaysorn Amarin (ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n",
|
240 |
+
"\n",
|
241 |
+
" location: {'lat': 13.7439676, 'lng': 100.5413037}\n",
|
242 |
+
"\n",
|
243 |
+
" name: The Basic Coffee BKK\n",
|
244 |
+
"\n",
|
245 |
+
" opening hours: {'open_now': True}\n",
|
246 |
+
"\n",
|
247 |
+
" rating: 4.7\n",
|
248 |
+
"\n",
|
249 |
+
" plus code: 7P52PGVR+HG\n",
|
250 |
+
"\n",
|
251 |
+
"\n",
|
252 |
+
" \n",
|
253 |
+
" address: 126 ซ. จุฬาลงกรณ์ 50 Wang Mai, Pathum Wan\n",
|
254 |
+
"\n",
|
255 |
+
" location: {'lat': 13.7344961, 'lng': 100.5268998}\n",
|
256 |
+
"\n",
|
257 |
+
" name: CRANNIES Coffee & Brunch\n",
|
258 |
+
"\n",
|
259 |
+
" opening hours: {'open_now': True}\n",
|
260 |
+
"\n",
|
261 |
+
" rating: 5\n",
|
262 |
+
"\n",
|
263 |
+
" plus code: 7P52PGMG+RQ\n",
|
264 |
+
"\n",
|
265 |
+
"\n",
|
266 |
+
" \n",
|
267 |
+
" address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n",
|
268 |
+
"\n",
|
269 |
+
" location: {'lat': 13.7537094, 'lng': 100.5328794}\n",
|
270 |
+
"\n",
|
271 |
+
" name: Bullet Thai Craft Beer\n",
|
272 |
+
"\n",
|
273 |
+
" opening hours: {'open_now': True}\n",
|
274 |
+
"\n",
|
275 |
+
" rating: 5\n",
|
276 |
+
"\n",
|
277 |
+
" plus code: 7P52QG3M+F5\n",
|
278 |
+
"\n",
|
279 |
+
"\n",
|
280 |
+
" \n",
|
281 |
+
" address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n",
|
282 |
+
"\n",
|
283 |
+
" location: {'lat': 13.7477989, 'lng': 100.5296324}\n",
|
284 |
+
"\n",
|
285 |
+
" name: Sip 'n Drip\n",
|
286 |
+
"\n",
|
287 |
+
" opening hours: {'open_now': True}\n",
|
288 |
+
"\n",
|
289 |
+
" rating: 4.9\n",
|
290 |
+
"\n",
|
291 |
+
" plus code: 7P52PGXH+4V\n",
|
292 |
+
"\n",
|
293 |
+
"\n",
|
294 |
+
" \n",
|
295 |
+
" address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n",
|
296 |
+
"\n",
|
297 |
+
" location: {'lat': 13.743762, 'lng': 100.541402}\n",
|
298 |
+
"\n",
|
299 |
+
" name: TABLA Craft Coffee\n",
|
300 |
+
"\n",
|
301 |
+
" opening hours: {'open_now': True}\n",
|
302 |
+
"\n",
|
303 |
+
" rating: 4.6\n",
|
304 |
+
"\n",
|
305 |
+
" plus code: 7P52PGVR+GH\n",
|
306 |
+
"\n",
|
307 |
+
"\n",
|
308 |
+
" \n",
|
309 |
+
" address: Velaa Sindhorn Village Langsuan, 87 Soi Langsuan, Lumphini, Pathum Wan\n",
|
310 |
+
"\n",
|
311 |
+
" location: {'lat': 13.7365082, 'lng': 100.5428638}\n",
|
312 |
+
"\n",
|
313 |
+
" name: The Coffee Academics\n",
|
314 |
+
"\n",
|
315 |
+
" opening hours: {'open_now': True}\n",
|
316 |
+
"\n",
|
317 |
+
" rating: 4.4\n",
|
318 |
+
"\n",
|
319 |
+
" plus code: 7P52PGPV+J4\n",
|
320 |
+
"\n",
|
321 |
+
"\n",
|
322 |
+
" \n",
|
323 |
+
" address: 445 Rama I Rd, Rong Muang, Pathum Wan\n",
|
324 |
+
"\n",
|
325 |
+
" location: {'lat': 13.7476317, 'lng': 100.5232939}\n",
|
326 |
+
"\n",
|
327 |
+
" name: D Coffee House\n",
|
328 |
+
"\n",
|
329 |
+
" opening hours: {'open_now': True}\n",
|
330 |
+
"\n",
|
331 |
+
" rating: 4.9\n",
|
332 |
+
"\n",
|
333 |
+
" plus code: 7P52PGXF+38\n",
|
334 |
+
"\n",
|
335 |
+
"\n",
|
336 |
+
" \n",
|
337 |
+
" address: ศูนย์รวมนักศึกษาแบ๊บติสต์ 473 Thanon Si Ayutthaya, Thung Phaya Thai, Ratchathewi\n",
|
338 |
+
"\n",
|
339 |
+
" location: {'lat': 13.758337, 'lng': 100.534177}\n",
|
340 |
+
"\n",
|
341 |
+
" name: Baptist coffee\n",
|
342 |
+
"\n",
|
343 |
+
" opening hours: {'open_now': True}\n",
|
344 |
+
"\n",
|
345 |
+
" rating: 5\n",
|
346 |
+
"\n",
|
347 |
+
" plus code: 7P52QG5M+8M\n",
|
348 |
+
"\n",
|
349 |
+
"\n",
|
350 |
+
" \n",
|
351 |
+
" address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\n",
|
352 |
+
"\n",
|
353 |
+
" location: {'lat': 13.7466928, 'lng': 100.5227848}\n",
|
354 |
+
"\n",
|
355 |
+
" name: Greatercafe Specialty Coffee Bangkok\n",
|
356 |
+
"\n",
|
357 |
+
" opening hours: {'open_now': True}\n",
|
358 |
+
"\n",
|
359 |
+
" rating: 4.7\n",
|
360 |
+
"\n",
|
361 |
+
" plus code: 7P52PGWF+M4\n",
|
362 |
+
"\n",
|
363 |
+
"\n",
|
364 |
+
" \n",
|
365 |
+
" address: Bldg., 1 st Fl 320 TangHuaPak (Hualamphong Rama IV Rd, Mahapruettaram Bang Rak\n",
|
366 |
+
"\n",
|
367 |
+
" location: {'lat': 13.7374409, 'lng': 100.5165419}\n",
|
368 |
+
"\n",
|
369 |
+
" name: Better Coffee\n",
|
370 |
+
"\n",
|
371 |
+
" opening hours: {'open_now': True}\n",
|
372 |
+
"\n",
|
373 |
+
" rating: 5\n",
|
374 |
+
"\n",
|
375 |
+
" plus code: 7P52PGP8+XJ\n",
|
376 |
+
"\n",
|
377 |
+
"\n",
|
378 |
+
" \n",
|
379 |
+
" address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\n",
|
380 |
+
"\n",
|
381 |
+
" location: {'lat': 13.7466896, 'lng': 100.5304572}\n",
|
382 |
+
"\n",
|
383 |
+
" name: Gallery Drip Coffee\n",
|
384 |
+
"\n",
|
385 |
+
" opening hours: {'open_now': True}\n",
|
386 |
+
"\n",
|
387 |
+
" rating: 4.6\n",
|
388 |
+
"\n",
|
389 |
+
" plus code: 7P52PGWJ+M5\n",
|
390 |
+
"\n",
|
391 |
+
"\n",
|
392 |
+
" \n",
|
393 |
+
" address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\n",
|
394 |
+
"\n",
|
395 |
+
" location: {'lat': 13.7408514, 'lng': 100.5230725}\n",
|
396 |
+
"\n",
|
397 |
+
" name: mm : MAKE MERRY\n",
|
398 |
+
"\n",
|
399 |
+
" opening hours: {'open_now': True}\n",
|
400 |
+
"\n",
|
401 |
+
" rating: 4.8\n",
|
402 |
+
"\n",
|
403 |
+
" plus code: 7P52PGRF+86\n",
|
404 |
+
"\n",
|
405 |
+
"\n",
|
406 |
+
" \n",
|
407 |
+
" address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\n",
|
408 |
+
"\n",
|
409 |
+
" location: {'lat': 13.7446247, 'lng': 100.5340785}\n",
|
410 |
+
"\n",
|
411 |
+
" name: GATTA CAFé\n",
|
412 |
+
"\n",
|
413 |
+
" opening hours: {'open_now': True}\n",
|
414 |
+
"\n",
|
415 |
+
" rating: 4.9\n",
|
416 |
+
"\n",
|
417 |
+
" plus code: 7P52PGVM+RJ\n",
|
418 |
+
"\n",
|
419 |
+
"\n",
|
420 |
+
" \n",
|
421 |
+
" address: 1873 Rama IV Rd, Khlong Tan Nuea, Watthana\n",
|
422 |
+
"\n",
|
423 |
+
" location: {'lat': 13.7335441, 'lng': 100.5377224}\n",
|
424 |
+
"\n",
|
425 |
+
" name: Redwood coffee and eatery\n",
|
426 |
+
"\n",
|
427 |
+
" opening hours: {'open_now': True}\n",
|
428 |
+
"\n",
|
429 |
+
" rating: 4.8\n",
|
430 |
+
"\n",
|
431 |
+
" plus code: 7P52PGMQ+C3\n",
|
432 |
+
"\n",
|
433 |
+
"\n",
|
434 |
+
" \n",
|
435 |
+
" address: B1 The Offices At Central World ชั้น 104 Rama I Rd, Pathum Wan\n",
|
436 |
+
"\n",
|
437 |
+
" location: {'lat': 13.7458267, 'lng': 100.5381669}\n",
|
438 |
+
"\n",
|
439 |
+
" name: Baankhunlek coffee สาขา CentralworldOffices\n",
|
440 |
+
"\n",
|
441 |
+
" opening hours: {'open_now': True}\n",
|
442 |
+
"\n",
|
443 |
+
" rating: 5\n",
|
444 |
+
"\n",
|
445 |
+
" plus code: 7P52PGWQ+87\n",
|
446 |
+
"\n",
|
447 |
+
"\n",
|
448 |
+
" \n",
|
449 |
+
" address: 3rd Floor, CentralWorld, Ratchadamri Rd, Pathum Wan\n",
|
450 |
+
"\n",
|
451 |
+
" location: {'lat': 13.7470656, 'lng': 100.5397062}\n",
|
452 |
+
"\n",
|
453 |
+
" name: Café BAGA Central World\n",
|
454 |
+
"\n",
|
455 |
+
" opening hours: {'open_now': True}\n",
|
456 |
+
"\n",
|
457 |
+
" rating: 4.7\n",
|
458 |
+
"\n",
|
459 |
+
" plus code: 7P52PGWQ+RV\n",
|
460 |
+
"\n",
|
461 |
+
"\n",
|
462 |
+
" \u001b[0m"
|
463 |
+
]
|
464 |
+
},
|
465 |
+
{
|
466 |
+
"name": "stderr",
|
467 |
+
"output_type": "stream",
|
468 |
+
"text": [
|
469 |
"Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
|
470 |
"LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
|
471 |
]
|
472 |
},
|
473 |
+
{
|
474 |
+
"name": "stdout",
|
475 |
+
"output_type": "stream",
|
476 |
+
"text": [
|
477 |
+
"\u001b[32;1m\u001b[1;3mHere is a list of coffee shops near มาบุญครอง (MBK Center):\n",
|
478 |
+
"\n",
|
479 |
+
"1. **BEANS Coffee Roaster Paragon**\n",
|
480 |
+
" - Address: 991/1 Rama I Rd, Pathum Wan\n",
|
481 |
+
" - Rating: 5.0\n",
|
482 |
+
" - Open Now: Yes\n",
|
483 |
+
"\n",
|
484 |
+
"2. **Olympic Coffee**\n",
|
485 |
+
" - Address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\n",
|
486 |
+
" - Rating: 4.8\n",
|
487 |
+
" - Open Now: Yes\n",
|
488 |
+
"\n",
|
489 |
+
"3. **Earthy Roaster (Specialty Coffee)**\n",
|
490 |
+
" - Address: 994 Makkasan, Ratchathewi\n",
|
491 |
+
" - Rating: 4.8\n",
|
492 |
+
" - Open Now: Yes\n",
|
493 |
+
"\n",
|
494 |
+
"4. **Treasure specialty coffee**\n",
|
495 |
+
" - Address: MINT TOWER Bantadthong Phetchaburi Rd, Pathum Wan\n",
|
496 |
+
" - Rating: 4.9\n",
|
497 |
+
" - Open Now: Yes\n",
|
498 |
+
"\n",
|
499 |
+
"5. **The Basic Coffee BKK**\n",
|
500 |
+
" - Address: ตึก Gaysorn Amarin, ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n",
|
501 |
+
" - Rating: 4.7\n",
|
502 |
+
" - Open Now: Yes\n",
|
503 |
+
"\n",
|
504 |
+
"6. **CRANNIES Coffee & Brunch**\n",
|
505 |
+
" - Address: 126 ซ. จุฬาลงกรณ์ 50 Wang Mai, Pathum Wan\n",
|
506 |
+
" - Rating: 5.0\n",
|
507 |
+
" - Open Now: Yes\n",
|
508 |
+
"\n",
|
509 |
+
"7. **Bullet Thai Craft Beer**\n",
|
510 |
+
" - Address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n",
|
511 |
+
" - Rating: 5.0\n",
|
512 |
+
" - Open Now: Yes\n",
|
513 |
+
"\n",
|
514 |
+
"8. **Sip 'n Drip**\n",
|
515 |
+
" - Address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n",
|
516 |
+
" - Rating: 4.9\n",
|
517 |
+
" - Open Now: Yes\n",
|
518 |
+
"\n",
|
519 |
+
"9. **TABLA Craft Coffee**\n",
|
520 |
+
" - Address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n",
|
521 |
+
" - Rating: 4.6\n",
|
522 |
+
" - Open Now: Yes\n",
|
523 |
+
"\n",
|
524 |
+
"10. **The Coffee Academics**\n",
|
525 |
+
" - Address: Velaa Sindhorn Village Langsuan, 87 Soi Langsuan, Lumphini, Pathum Wan\n",
|
526 |
+
" - Rating: 4.4\n",
|
527 |
+
" - Open Now: Yes\n",
|
528 |
+
"\n",
|
529 |
+
"11. **D Coffee House**\n",
|
530 |
+
" - Address: 445 Rama I Rd, Rong Muang, Pathum Wan\n",
|
531 |
+
" - Rating: 4.9\n",
|
532 |
+
" - Open Now: Yes\n",
|
533 |
+
"\n",
|
534 |
+
"12. **Baptist coffee**\n",
|
535 |
+
" - Address: ศูนย์รวมนักศึกษาแบ๊บติสต์ 473 Thanon Si Ayutthaya, Thung Phaya Thai, Ratchathewi\n",
|
536 |
+
" - Rating: 5.0\n",
|
537 |
+
" - Open Now: Yes\n",
|
538 |
+
"\n",
|
539 |
+
"13. **Greatercafe Specialty Coffee Bangkok**\n",
|
540 |
+
" - Address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\n",
|
541 |
+
" - Rating: 4.7\n",
|
542 |
+
" - Open Now: Yes\n",
|
543 |
+
"\n",
|
544 |
+
"14. **Better Coffee**\n",
|
545 |
+
" - Address: Bldg., 1 st Fl 320 TangHuaPak (Hualamphong Rama IV Rd, Mahapruettaram Bang Rak\n",
|
546 |
+
" - Rating: 5.0\n",
|
547 |
+
" - Open Now: Yes\n",
|
548 |
+
"\n",
|
549 |
+
"15. **Gallery Drip Coffee**\n",
|
550 |
+
" - Address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\n",
|
551 |
+
" - Rating: 4.6\n",
|
552 |
+
" - Open Now: Yes\n",
|
553 |
+
"\n",
|
554 |
+
"16. **mm : MAKE MERRY**\n",
|
555 |
+
" - Address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\n",
|
556 |
+
" - Rating: 4.8\n",
|
557 |
+
" - Open Now: Yes\n",
|
558 |
+
"\n",
|
559 |
+
"17. **GATTA CAFé**\n",
|
560 |
+
" - Address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\n",
|
561 |
+
" - Rating: 4.9\n",
|
562 |
+
" - Open Now: Yes\n",
|
563 |
+
"\n",
|
564 |
+
"18. **Redwood coffee and eatery**\n",
|
565 |
+
" - Address: 1873 Rama IV Rd, Khlong Tan Nuea, Watthana\n",
|
566 |
+
" - Rating: 4.8\n",
|
567 |
+
" - Open Now: Yes\n",
|
568 |
+
"\n",
|
569 |
+
"19. **Baankhunlek coffee สาขา CentralworldOffices**\n",
|
570 |
+
" - Address: B1 The Offices At Central World ชั้น 104 Rama I Rd, Pathum Wan\n",
|
571 |
+
" - Rating: 5.0\n",
|
572 |
+
" - Open Now: Yes\n",
|
573 |
+
"\n",
|
574 |
+
"20. **Café BAGA Central World**\n",
|
575 |
+
" - Address: 3rd Floor, CentralWorld, Ratchadamri Rd, Pathum Wan\n",
|
576 |
+
" - Rating: 4.7\n",
|
577 |
+
" - Open Now: Yes\n",
|
578 |
+
"\n",
|
579 |
+
"These coffee shops are within a radius of approximately 1500 meters from MBK Center and are currently open.\u001b[0m\n",
|
580 |
+
"\n",
|
581 |
+
"\u001b[1m> Finished chain.\u001b[0m\n"
|
582 |
+
]
|
583 |
+
},
|
584 |
{
|
585 |
"data": {
|
586 |
"text/plain": [
|
587 |
+
"\"Here is a list of coffee shops near มาบุญครอง (MBK Center):\\n\\n1. **BEANS Coffee Roaster Paragon**\\n - Address: 991/1 Rama I Rd, Pathum Wan\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n2. **Olympic Coffee**\\n - Address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\\n - Rating: 4.8\\n - Open Now: Yes\\n\\n3. **Earthy Roaster (Specialty Coffee)**\\n - Address: 994 Makkasan, Ratchathewi\\n - Rating: 4.8\\n - Open Now: Yes\\n\\n4. **Treasure specialty coffee**\\n - Address: MINT TOWER Bantadthong Phetchaburi Rd, Pathum Wan\\n - Rating: 4.9\\n - Open Now: Yes\\n\\n5. **The Basic Coffee BKK**\\n - Address: ตึก Gaysorn Amarin, ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\\n - Rating: 4.7\\n - Open Now: Yes\\n\\n6. **CRANNIES Coffee & Brunch**\\n - Address: 126 ซ. จุฬาลงกรณ์ 50 Wang Mai, Pathum Wan\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n7. **Bullet Thai Craft Beer**\\n - Address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n8. **Sip 'n Drip**\\n - Address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\\n - Rating: 4.9\\n - Open Now: Yes\\n\\n9. **TABLA Craft Coffee**\\n - Address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\\n - Rating: 4.6\\n - Open Now: Yes\\n\\n10. **The Coffee Academics**\\n - Address: Velaa Sindhorn Village Langsuan, 87 Soi Langsuan, Lumphini, Pathum Wan\\n - Rating: 4.4\\n - Open Now: Yes\\n\\n11. **D Coffee House**\\n - Address: 445 Rama I Rd, Rong Muang, Pathum Wan\\n - Rating: 4.9\\n - Open Now: Yes\\n\\n12. **Baptist coffee**\\n - Address: ศูนย์รวมนักศึกษาแบ๊บติสต์ 473 Thanon Si Ayutthaya, Thung Phaya Thai, Ratchathewi\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n13. **Greatercafe Specialty Coffee Bangkok**\\n - Address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\\n - Rating: 4.7\\n - Open Now: Yes\\n\\n14. **Better Coffee**\\n - Address: Bldg., 1 st Fl 320 TangHuaPak (Hualamphong Rama IV Rd, Mahapruettaram Bang Rak\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n15. **Gallery Drip Coffee**\\n - Address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\\n - Rating: 4.6\\n - Open Now: Yes\\n\\n16. **mm : MAKE MERRY**\\n - Address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\\n - Rating: 4.8\\n - Open Now: Yes\\n\\n17. **GATTA CAFé**\\n - Address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\\n - Rating: 4.9\\n - Open Now: Yes\\n\\n18. **Redwood coffee and eatery**\\n - Address: 1873 Rama IV Rd, Khlong Tan Nuea, Watthana\\n - Rating: 4.8\\n - Open Now: Yes\\n\\n19. **Baankhunlek coffee สาขา CentralworldOffices**\\n - Address: B1 The Offices At Central World ชั้น 104 Rama I Rd, Pathum Wan\\n - Rating: 5.0\\n - Open Now: Yes\\n\\n20. **Café BAGA Central World**\\n - Address: 3rd Floor, CentralWorld, Ratchadamri Rd, Pathum Wan\\n - Rating: 4.7\\n - Open Now: Yes\\n\\nThese coffee shops are within a radius of approximately 1500 meters from MBK Center and are currently open.\""
|
588 |
]
|
589 |
},
|
590 |
+
"execution_count": 3,
|
591 |
"metadata": {},
|
592 |
"output_type": "execute_result"
|
593 |
}
|
594 |
],
|
595 |
"source": [
|
596 |
+
"def submitUserMessage(user_input: str) -> str:\n",
|
597 |
+
" responce = agent_executor.invoke({\"input\": user_input, \"chat_history\": []})\n",
|
598 |
+
" return responce[\"output\"]\n",
|
599 |
+
"\n",
|
600 |
"submitUserMessage(\"ค้นหาร้านกาแฟใกล้มาบุญครอง\")"
|
601 |
]
|
602 |
}
|
chatbot.py
CHANGED
@@ -1,91 +1,81 @@
|
|
|
|
1 |
import os
|
2 |
import utils
|
3 |
|
4 |
utils.load_env()
|
5 |
-
|
6 |
|
7 |
-
|
8 |
from langchain_core.messages import HumanMessage
|
|
|
|
|
9 |
from langchain_openai import ChatOpenAI
|
10 |
-
from
|
11 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
13 |
-
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
14 |
-
import functools
|
15 |
-
import tools
|
16 |
|
17 |
-
#
|
18 |
-
|
19 |
|
20 |
-
|
21 |
-
# load models.
|
22 |
llm = ChatOpenAI(model="gpt-4o-mini")
|
23 |
|
24 |
-
|
25 |
-
def should_continue(state: MessagesState) -> Literal["tools", END]:
|
26 |
-
messages = state['messages']
|
27 |
-
last_message = messages[-1]
|
28 |
-
# If the LLM makes a tool call, then we route to the "tools" node
|
29 |
-
if last_message.tool_calls:
|
30 |
-
return "tools"
|
31 |
-
# Otherwise, we stop (reply to the user)
|
32 |
-
return END
|
33 |
-
|
34 |
-
|
35 |
-
# Define the function that calls the model
|
36 |
-
# Define the function that calls the model
|
37 |
-
def call_model(state: MessagesState):
|
38 |
-
messages = state['messages']
|
39 |
-
|
40 |
-
# Check if this is the first message in the conversation
|
41 |
-
if len(messages) == 1:
|
42 |
-
# Add the initial prompt before the user's first message
|
43 |
-
initial_prompt = HumanMessage(content="You are a market analyst specializing in feasibility studies. Your task is to analyze the potential of a new business location based on specific criteria. You will gather data from Google Maps about the presence and distribution of relevant points of interest, such as coffee shops, restaurants, or other businesses, near a specified location.")
|
44 |
-
messages.insert(0, initial_prompt)
|
45 |
-
|
46 |
-
# Call the model with the updated messages
|
47 |
-
response = llm.invoke(messages)
|
48 |
-
|
49 |
-
# Return the updated messages state
|
50 |
-
return {"messages": [response]}
|
51 |
-
|
52 |
-
|
53 |
-
# Define a new graph
|
54 |
-
workflow = StateGraph(MessagesState)
|
55 |
-
|
56 |
-
# Define the two nodes we will cycle between
|
57 |
-
workflow.add_node("agent", call_model)
|
58 |
-
workflow.add_node("tools", tool_node)
|
59 |
-
|
60 |
-
# Set the entrypoint as `agent`
|
61 |
-
workflow.set_entry_point("agent")
|
62 |
-
|
63 |
-
|
64 |
-
# We now add a conditional edge
|
65 |
-
workflow.add_conditional_edges(
|
66 |
-
# First, we define the start node. We use `agent`.
|
67 |
-
# This means these are the edges taken after the `agent` node is called.
|
68 |
-
"agent",
|
69 |
-
# Next, we pass in the function that will determine which node is called next.
|
70 |
-
should_continue,
|
71 |
-
)
|
72 |
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
-
# Finally, we compile it!
|
81 |
-
# This compiles it into a LangChain Runnable,
|
82 |
-
# meaning you can use it as you would any other runnable.
|
83 |
-
# Note that we're (optionally) passing the memory when compiling the graph
|
84 |
-
app = workflow.compile(checkpointer=checkpointer)
|
85 |
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
)
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# %%
|
2 |
import os
|
3 |
import utils
|
4 |
|
5 |
utils.load_env()
|
6 |
+
os.environ['LANGCHAIN_TRACING_V2'] = "true"
|
7 |
|
8 |
+
# %%
|
9 |
from langchain_core.messages import HumanMessage
|
10 |
+
|
11 |
+
# for llm model
|
12 |
from langchain_openai import ChatOpenAI
|
13 |
+
from langchain.agents.format_scratchpad import format_to_openai_function_messages
|
14 |
+
from tools import find_place_from_text, nearby_search
|
15 |
+
from typing import Dict, List, Tuple
|
16 |
+
from langchain.agents import (
|
17 |
+
AgentExecutor,
|
18 |
+
)
|
19 |
+
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
|
20 |
+
from langchain_community.chat_models import ChatOpenAI
|
21 |
+
from langchain_community.tools.convert_to_openai import format_tool_to_openai_function
|
22 |
+
from langchain_core.messages import AIMessage, HumanMessage
|
23 |
+
from langchain_core.pydantic_v1 import BaseModel, Field
|
24 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
|
|
|
|
|
25 |
|
26 |
+
# Bind the tools to the model
|
27 |
+
tools = [find_place_from_text, nearby_search] # Include both tools if needed
|
28 |
|
|
|
|
|
29 |
llm = ChatOpenAI(model="gpt-4o-mini")
|
30 |
|
31 |
+
llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
+
def _format_chat_history(chat_history: List[Tuple[str, str]]):
|
34 |
+
buffer = []
|
35 |
+
for human, ai in chat_history:
|
36 |
+
buffer.append(HumanMessage(content=human))
|
37 |
+
buffer.append(AIMessage(content=ai))
|
38 |
+
return buffer
|
39 |
+
|
40 |
+
meta = utils.load_agent_meta()[0]
|
41 |
+
|
42 |
+
prompt = ChatPromptTemplate.from_messages(
|
43 |
+
[
|
44 |
+
("system", meta['prompt']),
|
45 |
+
MessagesPlaceholder(variable_name="chat_history"),
|
46 |
+
("user", "{input}"),
|
47 |
+
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
48 |
+
]
|
49 |
+
)
|
50 |
|
51 |
+
agent = (
|
52 |
+
{
|
53 |
+
"input": lambda x: x["input"],
|
54 |
+
"chat_history": lambda x: _format_chat_history(x["chat_history"]),
|
55 |
+
"agent_scratchpad": lambda x: format_to_openai_function_messages(
|
56 |
+
x["intermediate_steps"]
|
57 |
+
),
|
58 |
+
}
|
59 |
+
| prompt
|
60 |
+
| llm_with_tools
|
61 |
+
| OpenAIFunctionsAgentOutputParser()
|
62 |
+
)
|
63 |
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
class AgentInput(BaseModel):
|
66 |
+
input: str
|
67 |
+
chat_history: List[Tuple[str, str]] = Field(
|
68 |
+
..., extra={"widget": {"type": "chat", "input": "input", "output": "output"}}
|
69 |
)
|
70 |
+
|
71 |
+
|
72 |
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True).with_types(
|
73 |
+
input_type=AgentInput
|
74 |
+
)
|
75 |
+
|
76 |
+
|
77 |
+
# %%
|
78 |
+
def submitUserMessage(user_input: str) -> str:
|
79 |
+
responce = agent_executor.invoke({"input": user_input, "chat_history": []})
|
80 |
+
return responce["output"]
|
81 |
+
|
prompt.json
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"name":"Market Analyst",
|
4 |
+
"prompt": "You are a market analyst specializing in feasibility studies. Your task is to analyze the potential of a new business location based on specific criteria. You will gather data from Google Maps about the presence and distribution of relevant points of interest, such as coffee shops, restaurants, or other businesses, near a specified location.",
|
5 |
+
"greet": ""
|
6 |
+
}
|
7 |
+
]
|
tools.ipynb
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
-
"execution_count":
|
6 |
"metadata": {},
|
7 |
"outputs": [],
|
8 |
"source": [
|
@@ -15,7 +15,7 @@
|
|
15 |
},
|
16 |
{
|
17 |
"cell_type": "code",
|
18 |
-
"execution_count":
|
19 |
"metadata": {},
|
20 |
"outputs": [],
|
21 |
"source": [
|
@@ -39,13 +39,21 @@
|
|
39 |
" \n",
|
40 |
" strout = \"\"\n",
|
41 |
" for r in result:\n",
|
42 |
-
"
|
43 |
-
" address
|
44 |
-
"
|
45 |
-
" name
|
46 |
-
"
|
47 |
-
" rating
|
48 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
" \"\"\"\n",
|
50 |
" return strout"
|
51 |
]
|
@@ -54,26 +62,6 @@
|
|
54 |
"cell_type": "code",
|
55 |
"execution_count": 4,
|
56 |
"metadata": {},
|
57 |
-
"outputs": [
|
58 |
-
{
|
59 |
-
"data": {
|
60 |
-
"text/plain": [
|
61 |
-
"\"\\n address: 587-589/7-9 ถ. รามอินทรา แขวงคันนายาว เขตคันนายาว กรุงเทพมหานคร 10230 ไทย\\n\\n location: {'lat': 13.8261789, 'lng': 100.6794462}\\n\\n name: แฟชั่นไอส์แลนด์\\n\\n opening hours: {'open_now': True}\\n\\n rating: 4.5\\n\\n \""
|
62 |
-
]
|
63 |
-
},
|
64 |
-
"execution_count": 4,
|
65 |
-
"metadata": {},
|
66 |
-
"output_type": "execute_result"
|
67 |
-
}
|
68 |
-
],
|
69 |
-
"source": [
|
70 |
-
"find_place_from_text(\"fashion island\")"
|
71 |
-
]
|
72 |
-
},
|
73 |
-
{
|
74 |
-
"cell_type": "code",
|
75 |
-
"execution_count": 1,
|
76 |
-
"metadata": {},
|
77 |
"outputs": [],
|
78 |
"source": [
|
79 |
"# gplace_tools.py\n",
|
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
+
"execution_count": 6,
|
6 |
"metadata": {},
|
7 |
"outputs": [],
|
8 |
"source": [
|
|
|
15 |
},
|
16 |
{
|
17 |
"cell_type": "code",
|
18 |
+
"execution_count": 13,
|
19 |
"metadata": {},
|
20 |
"outputs": [],
|
21 |
"source": [
|
|
|
39 |
" \n",
|
40 |
" strout = \"\"\n",
|
41 |
" for r in result:\n",
|
42 |
+
" # Use .get() to handle missing keys\n",
|
43 |
+
" address = r.get('vicinity', 'N/A')\n",
|
44 |
+
" location_info = r.get('geometry', {}).get('location', 'N/A')\n",
|
45 |
+
" name = r.get('name', 'N/A')\n",
|
46 |
+
" opening_hours = r.get('opening_hours', 'N/A')\n",
|
47 |
+
" rating = r.get('rating', 'N/A')\n",
|
48 |
+
" plus_code = r.get('plus_code', {}).get('global_code', 'N/A')\n",
|
49 |
+
" \n",
|
50 |
+
" strout += f\"\"\"\n",
|
51 |
+
" address: {address}\\n\n",
|
52 |
+
" location: {location_info}\\n\n",
|
53 |
+
" name: {name}\\n\n",
|
54 |
+
" opening hours: {opening_hours}\\n\n",
|
55 |
+
" rating: {rating}\\n\n",
|
56 |
+
" plus code: {plus_code}\\n\\n\n",
|
57 |
" \"\"\"\n",
|
58 |
" return strout"
|
59 |
]
|
|
|
62 |
"cell_type": "code",
|
63 |
"execution_count": 4,
|
64 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
"outputs": [],
|
66 |
"source": [
|
67 |
"# gplace_tools.py\n",
|
tools.py
CHANGED
@@ -1,4 +1,12 @@
|
|
1 |
import gplace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
# %%
|
4 |
def find_place_from_text(location:str):
|
@@ -14,23 +22,57 @@ def find_place_from_text(location:str):
|
|
14 |
rating: {r['rating']}\n
|
15 |
"""
|
16 |
|
17 |
-
def nearby_search(keyword:str, location:str, radius=2000, place_type=None):
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
strout = ""
|
23 |
for r in result:
|
24 |
-
|
25 |
-
address
|
26 |
-
|
27 |
-
name
|
28 |
-
|
29 |
-
rating
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
"""
|
32 |
return strout
|
33 |
|
|
|
34 |
# %%
|
35 |
# gplace_tools.py
|
36 |
from langgraph.prebuilt import ToolNode
|
|
|
1 |
import gplace
|
2 |
+
from typing import TypedDict, Optional
|
3 |
+
|
4 |
+
|
5 |
+
class NearbySearchInput(TypedDict):
|
6 |
+
keyword: str
|
7 |
+
location_name: str
|
8 |
+
radius: int
|
9 |
+
place_type: Optional[str]
|
10 |
|
11 |
# %%
|
12 |
def find_place_from_text(location:str):
|
|
|
22 |
rating: {r['rating']}\n
|
23 |
"""
|
24 |
|
25 |
+
# def nearby_search(keyword:str, location:str, radius=2000, place_type=None):
|
26 |
+
# """Searches for many places nearby the location based on a keyword. using keyword like \"coffee shop\", \"restaurants\". radius is the range to search from the location"""
|
27 |
+
# location = gplace.find_location(location, radius=radius)
|
28 |
+
# result = gplace.nearby_search(keyword, location, radius)
|
29 |
+
|
30 |
+
# strout = ""
|
31 |
+
# for r in result:
|
32 |
+
# strout = strout + f"""
|
33 |
+
# address: {r['vicinity']}\n
|
34 |
+
# location: {r['geometry']['location']}\n
|
35 |
+
# name: {r['name']}\n
|
36 |
+
# opening hours: {r['opening_hours']}\n
|
37 |
+
# rating: {r['rating']}\n
|
38 |
+
# plus code: {r['plus_code']['global_code']}\n\n
|
39 |
+
# """
|
40 |
+
# return strout
|
41 |
+
|
42 |
+
|
43 |
+
def nearby_search(input_dict: NearbySearchInput):
|
44 |
+
"""Searches for many places nearby the location based on a keyword. using keyword like \"coffee shop\", \"restaurants\". radius is the range to search from the location."""
|
45 |
+
|
46 |
+
keyword = input_dict['keyword']
|
47 |
+
location = input_dict['location_name']
|
48 |
+
radius = input_dict.get('radius', 2000)
|
49 |
+
place_type = input_dict.get('place_type', None)
|
50 |
+
|
51 |
+
# Call the internal function to find location
|
52 |
+
location_coords = gplace.find_location(location, radius=radius)
|
53 |
+
result = gplace.nearby_search(keyword, location_coords, radius)
|
54 |
|
55 |
strout = ""
|
56 |
for r in result:
|
57 |
+
# Use .get() to handle missing keys
|
58 |
+
address = r.get('vicinity', 'N/A')
|
59 |
+
location_info = r.get('geometry', {}).get('location', 'N/A')
|
60 |
+
name = r.get('name', 'N/A')
|
61 |
+
opening_hours = r.get('opening_hours', 'N/A')
|
62 |
+
rating = r.get('rating', 'N/A')
|
63 |
+
plus_code = r.get('plus_code', {}).get('global_code', 'N/A')
|
64 |
+
|
65 |
+
strout += f"""
|
66 |
+
address: {address}\n
|
67 |
+
location: {location_info}\n
|
68 |
+
name: {name}\n
|
69 |
+
opening hours: {opening_hours}\n
|
70 |
+
rating: {rating}\n
|
71 |
+
plus code: {plus_code}\n\n
|
72 |
"""
|
73 |
return strout
|
74 |
|
75 |
+
|
76 |
# %%
|
77 |
# gplace_tools.py
|
78 |
from langgraph.prebuilt import ToolNode
|
utils.py
CHANGED
@@ -1,5 +1,12 @@
|
|
1 |
from dotenv import load_dotenv
|
2 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
|
5 |
def load_env():
|
|
|
1 |
from dotenv import load_dotenv
|
2 |
import os
|
3 |
+
import json
|
4 |
+
|
5 |
+
|
6 |
+
def load_agent_meta():
|
7 |
+
with open('./prompt.json', 'r') as file:
|
8 |
+
prompt_data = json.load(file)
|
9 |
+
return prompt_data
|
10 |
|
11 |
|
12 |
def load_env():
|