DylanonWic commited on
Commit
7118dfb
1 Parent(s): edd1568

Upload 11 files

Browse files
Files changed (6) hide show
  1. chatbot.ipynb +530 -75
  2. chatbot.py +64 -74
  3. prompt.json +7 -0
  4. tools.ipynb +17 -29
  5. tools.py +53 -11
  6. 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
- "from langchain_core.tools import tool\n",
31
- "from langgraph.checkpoint.memory import MemorySaver\n",
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
- "# Define a new graph\n",
63
- "workflow = StateGraph(MessagesState)\n",
64
  "\n",
65
- "# Define the two nodes we will cycle between\n",
66
- "workflow.add_node(\"agent\", call_model)\n",
67
- "workflow.add_node(\"tools\", tool_node)\n",
 
 
 
68
  "\n",
69
- "# Set the entrypoint as `agent`\n",
70
- "# This means that this node is the first one called\n",
71
- "workflow.set_entry_point(\"agent\")\n",
72
  "\n",
73
- "# We now add a conditional edge\n",
74
- "workflow.add_conditional_edges(\n",
75
- " # First, we define the start node. We use `agent`.\n",
76
- " # This means these are the edges taken after the `agent` node is called.\n",
77
- " \"agent\",\n",
78
- " # Next, we pass in the function that will determine which node is called next.\n",
79
- " should_continue,\n",
80
  ")\n",
81
  "\n",
82
- "# We now add a normal edge from `tools` to `agent`.\n",
83
- "# This means that after `tools` is called, `agent` node is called next.\n",
84
- "workflow.add_edge(\"tools\", 'agent')\n",
 
 
 
 
 
 
 
 
 
85
  "\n",
86
- "# Initialize memory to persist state between graph runs\n",
87
- "checkpointer = MemorySaver()\n",
88
  "\n",
89
- "# Finally, we compile it!\n",
90
- "# This compiles it into a LangChain Runnable,\n",
91
- "# meaning you can use it as you would any other runnable.\n",
92
- "# Note that we're (optionally) passing the memory when compiling the graph\n",
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
- " return final_state[\"messages\"][-1].content"
 
 
 
 
108
  ]
109
  },
110
  {
111
  "cell_type": "code",
112
- "execution_count": 7,
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
- "'บริเวณมาบุญครองในกรุงเทพฯ มีร้านกาแฟหลายแห่งที่น่าสนใจ คุณสามารถลองไปที่ร้านเหล่านี้ได้:\\n\\n1. **ร้านกาแฟโฟลว์ (Flow Coffee)** - ร้านกาแฟเล็กๆ ที่มีบรรยากาศสบาย เหมาะสำหรับนั่งทำงานหรือนั่งชิลล์\\n2. **ร้านกาแฟ On the Way** - ร้านกาแฟที่มีเมนูหลากหลายและบรรยากาศดี\\n3. **ร้านกาแฟชิค (Chic)** - ร้านกาแฟที่มีการตกแต่งน่ารักและเครื่องดื่มหลากหลาย\\n4. **ร้านกาแฟ Starbucks** - มีสาขาหลายแห่งในกรุงเทพฯ รวมถึงใกล้บริเวณมาบุญครอง\\n5. **ร้านกาแฟดอยช้าง** - ที่มีชื่อเสียงในเรื่องของกาแฟจากดอยช้าง\\n\\nคุณสามารถค้นหาร้านกาแฟเพิ่มเติมได้จาก Google Maps หรือแอปพลิเคชันค้นหาร้านอาหารต่างๆ เพื่อดูรีวิวและข้อมูลเพิ่มเติมเกี่ยวกับร้านกาแฟใกล้มาบุญครองได้ค่ะ'"
137
  ]
138
  },
139
- "execution_count": 7,
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
- # os.environ['LANGCHAIN_TRACING_V2'] = "true"
6
 
7
- from typing import Literal
8
  from langchain_core.messages import HumanMessage
 
 
9
  from langchain_openai import ChatOpenAI
10
- from langgraph.checkpoint.memory import MemorySaver
11
- from langgraph.graph import END, StateGraph, MessagesState
 
 
 
 
 
 
 
 
 
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
- # define tools node.
18
- tool_node = tools.tool_node
19
 
20
-
21
- # load models.
22
  llm = ChatOpenAI(model="gpt-4o-mini")
23
 
24
- # Define the function that determines whether to continue or not
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
- # We now add a normal edge from `tools` to `agent`.
74
- # This means that after `tools` is called, `agent` node is called next.
75
- workflow.add_edge("tools", 'agent')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- # Initialize memory to persist state between graph runs
78
- checkpointer = MemorySaver()
 
 
 
 
 
 
 
 
 
 
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
- def submitUserMessage(message:str):
87
- final_state = app.invoke(
88
- {"messages": [HumanMessage(content=message)]},
89
- config={"configurable": {"thread_id": 42}}
90
  )
91
- return final_state["messages"][-1].content
 
 
 
 
 
 
 
 
 
 
 
 
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": 2,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
@@ -15,7 +15,7 @@
15
  },
16
  {
17
  "cell_type": "code",
18
- "execution_count": 3,
19
  "metadata": {},
20
  "outputs": [],
21
  "source": [
@@ -39,13 +39,21 @@
39
  " \n",
40
  " strout = \"\"\n",
41
  " for r in result:\n",
42
- " strout = strout + f\"\"\"\n",
43
- " address: {r['vicinity']}\\n\n",
44
- " location: {r['geometry']['location']}\\n\n",
45
- " name: {r['name']}\\n\n",
46
- " opening hours: {r['opening_hours']}\\n\n",
47
- " rating: {r['rating']}\\n\n",
48
- " plus code: {r['plus_code']['global_code']}\\n\\n\n",
 
 
 
 
 
 
 
 
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
- """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"""
19
- location = gplace.find_location(location, radius=radius)
20
- result = gplace.nearby_search(keyword, location, radius)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  strout = ""
23
  for r in result:
24
- strout = strout + f"""
25
- address: {r['vicinity']}\n
26
- location: {r['geometry']['location']}\n
27
- name: {r['name']}\n
28
- opening hours: {r['opening_hours']}\n
29
- rating: {r['rating']}\n
30
- plus code: {r['plus_code']['global_code']}\n\n
 
 
 
 
 
 
 
 
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():