DylanonWic commited on
Commit
82df0a3
1 Parent(s): 4a81f80

Upload 17 files

Browse files
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import time
2
  import gradio as gr
3
- from chatbot import submitUserMessage
4
 
5
  def chat(message:str, history):
6
  return submitUserMessage(message)
 
1
  import time
2
  import gradio as gr
3
+ from chatbot_multiagent import submitUserMessage
4
 
5
  def chat(message:str, history):
6
  return submitUserMessage(message)
chatbot.ipynb CHANGED
@@ -2,7 +2,7 @@
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
- "execution_count": 4,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
@@ -15,23 +15,17 @@
15
  },
16
  {
17
  "cell_type": "code",
18
- "execution_count": 5,
19
  "metadata": {},
20
  "outputs": [
21
  {
22
- "ename": "JSONDecodeError",
23
- "evalue": "Invalid control character at: line 4 column 358 (char 398)",
24
- "output_type": "error",
25
- "traceback": [
26
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
27
- "\u001b[0;31mJSONDecodeError\u001b[0m Traceback (most recent call last)",
28
- "Cell \u001b[0;32mIn[5], line 32\u001b[0m\n\u001b[1;32m 29\u001b[0m buffer\u001b[38;5;241m.\u001b[39mappend(AIMessage(content\u001b[38;5;241m=\u001b[39mai))\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m buffer\n\u001b[0;32m---> 32\u001b[0m meta \u001b[38;5;241m=\u001b[39m \u001b[43mutils\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_agent_meta\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m 34\u001b[0m prompt \u001b[38;5;241m=\u001b[39m ChatPromptTemplate\u001b[38;5;241m.\u001b[39mfrom_messages(\n\u001b[1;32m 35\u001b[0m [\n\u001b[1;32m 36\u001b[0m (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msystem\u001b[39m\u001b[38;5;124m\"\u001b[39m, meta[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mprompt\u001b[39m\u001b[38;5;124m'\u001b[39m]),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 40\u001b[0m ]\n\u001b[1;32m 41\u001b[0m )\n\u001b[1;32m 43\u001b[0m agent \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 44\u001b[0m {\n\u001b[1;32m 45\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minput\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mlambda\u001b[39;00m x: x[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minput\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[38;5;241m|\u001b[39m OpenAIFunctionsAgentOutputParser()\n\u001b[1;32m 54\u001b[0m )\n",
29
- "File \u001b[0;32m~/Projects/Github/market-feasibility-analysis-chatbot/utils.py:8\u001b[0m, in \u001b[0;36mload_agent_meta\u001b[0;34m()\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mload_agent_meta\u001b[39m():\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./prompt.json\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m file:\n\u001b[0;32m----> 8\u001b[0m prompt_data \u001b[38;5;241m=\u001b[39m \u001b[43mjson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m prompt_data\n",
30
- "File \u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py:293\u001b[0m, in \u001b[0;36mload\u001b[0;34m(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mload\u001b[39m(fp, \u001b[38;5;241m*\u001b[39m, \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, object_hook\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, parse_float\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 275\u001b[0m parse_int\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, parse_constant\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, object_pairs_hook\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkw):\n\u001b[1;32m 276\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Deserialize ``fp`` (a ``.read()``-supporting file-like object containing\u001b[39;00m\n\u001b[1;32m 277\u001b[0m \u001b[38;5;124;03m a JSON document) to a Python object.\u001b[39;00m\n\u001b[1;32m 278\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 291\u001b[0m \u001b[38;5;124;03m kwarg; otherwise ``JSONDecoder`` is used.\u001b[39;00m\n\u001b[1;32m 292\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 293\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mloads\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 294\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mcls\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mobject_hook\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mobject_hook\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 295\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_float\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_float\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparse_int\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_int\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 296\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_constant\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_constant\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mobject_pairs_hook\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mobject_pairs_hook\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkw\u001b[49m\u001b[43m)\u001b[49m\n",
31
- "File \u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py:346\u001b[0m, in \u001b[0;36mloads\u001b[0;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m 341\u001b[0m s \u001b[38;5;241m=\u001b[39m s\u001b[38;5;241m.\u001b[39mdecode(detect_encoding(s), \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msurrogatepass\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 343\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m 344\u001b[0m parse_int \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m parse_float \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m 345\u001b[0m parse_constant \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_pairs_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kw):\n\u001b[0;32m--> 346\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_default_decoder\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 348\u001b[0m \u001b[38;5;28mcls\u001b[39m \u001b[38;5;241m=\u001b[39m JSONDecoder\n",
32
- "File \u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py:337\u001b[0m, in \u001b[0;36mJSONDecoder.decode\u001b[0;34m(self, s, _w)\u001b[0m\n\u001b[1;32m 332\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdecode\u001b[39m(\u001b[38;5;28mself\u001b[39m, s, _w\u001b[38;5;241m=\u001b[39mWHITESPACE\u001b[38;5;241m.\u001b[39mmatch):\n\u001b[1;32m 333\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the Python representation of ``s`` (a ``str`` instance\u001b[39;00m\n\u001b[1;32m 334\u001b[0m \u001b[38;5;124;03m containing a JSON document).\u001b[39;00m\n\u001b[1;32m 335\u001b[0m \n\u001b[1;32m 336\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 337\u001b[0m obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraw_decode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_w\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mend\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 338\u001b[0m end \u001b[38;5;241m=\u001b[39m _w(s, end)\u001b[38;5;241m.\u001b[39mend()\n\u001b[1;32m 339\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m end \u001b[38;5;241m!=\u001b[39m \u001b[38;5;28mlen\u001b[39m(s):\n",
33
- "File \u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py:353\u001b[0m, in \u001b[0;36mJSONDecoder.raw_decode\u001b[0;34m(self, s, idx)\u001b[0m\n\u001b[1;32m 344\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Decode a JSON document from ``s`` (a ``str`` beginning with\u001b[39;00m\n\u001b[1;32m 345\u001b[0m \u001b[38;5;124;03ma JSON document) and return a 2-tuple of the Python\u001b[39;00m\n\u001b[1;32m 346\u001b[0m \u001b[38;5;124;03mrepresentation and the index in ``s`` where the document ended.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 350\u001b[0m \n\u001b[1;32m 351\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 352\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 353\u001b[0m obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mscan_once\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 354\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopIteration\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n\u001b[1;32m 355\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m JSONDecodeError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpecting value\u001b[39m\u001b[38;5;124m\"\u001b[39m, s, err\u001b[38;5;241m.\u001b[39mvalue) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n",
34
- "\u001b[0;31mJSONDecodeError\u001b[0m: Invalid control character at: line 4 column 358 (char 398)"
35
  ]
36
  }
37
  ],
@@ -106,7 +100,7 @@
106
  },
107
  {
108
  "cell_type": "code",
109
- "execution_count": null,
110
  "metadata": {},
111
  "outputs": [
112
  {
@@ -155,7 +149,7 @@
155
  "output_type": "stream",
156
  "text": [
157
  "\u001b[32;1m\u001b[1;3m\n",
158
- "Invoking: `nearby_search` with `{'input_dict': {'keyword': 'coffee shop', 'location_name': 'มาบุญครอง', 'radius': 1500, 'place_type': 'cafe'}}`\n",
159
  "\n",
160
  "\n",
161
  "\u001b[0m"
@@ -185,417 +179,289 @@
185
  "name": "stdout",
186
  "output_type": "stream",
187
  "text": [
188
- "\u001b[33;1m\u001b[1;3m\n",
189
- " address: 991/1 Rama I Rd, Pathum Wan\n",
190
  "\n",
191
- " location: {'lat': 13.7458781, 'lng': 100.5341476}\n",
192
  "\n",
193
- " name: BEANS Coffee Roaster Paragon\n",
 
 
194
  "\n",
195
  " opening hours: {'open_now': True}\n",
196
  "\n",
197
- " rating: 5\n",
198
  "\n",
199
- " plus code: 7P52PGWM+9M\n",
200
  "\n",
201
  "\n",
202
  " \n",
203
- " address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\n",
204
  "\n",
205
- " location: {'lat': 13.7497223, 'lng': 100.521221}\n",
206
  "\n",
207
- " name: Olympic Coffee\n",
208
  "\n",
209
  " opening hours: {'open_now': True}\n",
210
  "\n",
211
- " rating: 4.8\n",
212
  "\n",
213
- " plus code: 7P52PGXC+VF\n",
214
  "\n",
215
  "\n",
216
  " \n",
217
- " address: 994 Makkasan, Ratchathewi\n",
218
  "\n",
219
- " location: {'lat': 13.7495947, 'lng': 100.5426623}\n",
220
  "\n",
221
- " name: Earthy Roaster (Specialty Coffee)\n",
222
  "\n",
223
  " opening hours: {'open_now': True}\n",
224
  "\n",
225
  " rating: 4.8\n",
226
  "\n",
227
- " plus code: 7P52PGXV+R3\n",
228
  "\n",
229
  "\n",
230
  " \n",
231
- " address: MINT TOWER Bantadthong Phetchaburi Rd, Subdistrict Pathum Wan\n",
232
  "\n",
233
- " location: {'lat': 13.7450255, 'lng': 100.5235735}\n",
234
  "\n",
235
- " name: Treasure specialty coffee\n",
236
  "\n",
237
  " opening hours: {'open_now': True}\n",
238
  "\n",
239
  " rating: 4.9\n",
240
  "\n",
241
- " plus code: 7P52PGWF+2C\n",
242
  "\n",
243
  "\n",
244
  " \n",
245
- " address: ตึก Gaysorn Amarin (ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n",
246
  "\n",
247
- " location: {'lat': 13.7439676, 'lng': 100.5413037}\n",
248
  "\n",
249
- " name: The Basic Coffee BKK\n",
250
  "\n",
251
  " opening hours: {'open_now': True}\n",
252
  "\n",
253
- " rating: 4.7\n",
254
  "\n",
255
- " plus code: 7P52PGVR+HG\n",
256
  "\n",
257
  "\n",
258
  " \n",
259
- " address: 126 ซ. จุฬาลงกรณ์ 50 Wang Mai, Pathum Wan\n",
260
  "\n",
261
- " location: {'lat': 13.7344961, 'lng': 100.5268998}\n",
262
  "\n",
263
- " name: CRANNIES Coffee & Brunch\n",
264
  "\n",
265
  " opening hours: {'open_now': True}\n",
266
  "\n",
267
- " rating: 5\n",
268
  "\n",
269
- " plus code: 7P52PGMG+RQ\n",
270
  "\n",
271
  "\n",
272
  " \n",
273
- " address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n",
274
  "\n",
275
- " location: {'lat': 13.7537094, 'lng': 100.5328794}\n",
276
  "\n",
277
- " name: Bullet Thai Craft Beer\n",
278
  "\n",
279
  " opening hours: {'open_now': True}\n",
280
  "\n",
281
- " rating: 5\n",
282
  "\n",
283
- " plus code: 7P52QG3M+F5\n",
284
  "\n",
285
  "\n",
286
  " \n",
287
- " address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n",
288
  "\n",
289
- " location: {'lat': 13.7477989, 'lng': 100.5296324}\n",
290
  "\n",
291
- " name: Sip 'n Drip\n",
292
  "\n",
293
  " opening hours: {'open_now': True}\n",
294
  "\n",
295
- " rating: 4.9\n",
296
  "\n",
297
- " plus code: 7P52PGXH+4V\n",
298
  "\n",
299
  "\n",
300
  " \n",
301
- " address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n",
302
  "\n",
303
- " location: {'lat': 13.743762, 'lng': 100.541402}\n",
304
  "\n",
305
- " name: TABLA Craft Coffee\n",
306
  "\n",
307
- " opening hours: {'open_now': True}\n",
308
  "\n",
309
- " rating: 4.6\n",
310
  "\n",
311
- " plus code: 7P52PGVR+GH\n",
312
  "\n",
313
  "\n",
314
  " \n",
315
- " address: Velaa Sindhorn Village Langsuan, 87 Soi Langsuan, Lumphini, Pathum Wan\n",
316
  "\n",
317
- " location: {'lat': 13.7365082, 'lng': 100.5428638}\n",
318
  "\n",
319
- " name: The Coffee Academics\n",
320
  "\n",
321
  " opening hours: {'open_now': True}\n",
322
  "\n",
323
- " rating: 4.4\n",
324
  "\n",
325
- " plus code: 7P52PGPV+J4\n",
326
  "\n",
327
  "\n",
328
  " \n",
329
- " address: 445 Rama I Rd, Rong Muang, Pathum Wan\n",
330
  "\n",
331
- " location: {'lat': 13.7476317, 'lng': 100.5232939}\n",
332
  "\n",
333
- " name: D Coffee House\n",
334
  "\n",
335
  " opening hours: {'open_now': True}\n",
336
  "\n",
337
  " rating: 4.9\n",
338
  "\n",
339
- " plus code: 7P52PGXF+38\n",
340
  "\n",
341
  "\n",
342
  " \n",
343
- " address: ศูนย์รวมนักศึกษาแบ๊บติสต์ 473 Thanon Si Ayutthaya, Thung Phaya Thai, Ratchathewi\n",
344
  "\n",
345
- " location: {'lat': 13.758337, 'lng': 100.534177}\n",
346
  "\n",
347
- " name: Baptist coffee\n",
348
  "\n",
349
  " opening hours: {'open_now': True}\n",
350
  "\n",
351
- " rating: 5\n",
352
  "\n",
353
- " plus code: 7P52QG5M+8M\n",
354
  "\n",
355
  "\n",
356
  " \n",
357
- " address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\n",
358
  "\n",
359
- " location: {'lat': 13.7466928, 'lng': 100.5227848}\n",
360
  "\n",
361
- " name: Greatercafe Specialty Coffee Bangkok\n",
362
  "\n",
363
  " opening hours: {'open_now': True}\n",
364
  "\n",
365
- " rating: 4.7\n",
366
  "\n",
367
- " plus code: 7P52PGWF+M4\n",
368
  "\n",
369
  "\n",
370
  " \n",
371
- " address: Bldg., 1 st Fl 320 TangHuaPak (Hualamphong Rama IV Rd, Mahapruettaram Bang Rak\n",
372
  "\n",
373
- " location: {'lat': 13.7374409, 'lng': 100.5165419}\n",
374
  "\n",
375
- " name: Better Coffee\n",
376
  "\n",
377
  " opening hours: {'open_now': True}\n",
378
  "\n",
379
- " rating: 5\n",
380
  "\n",
381
- " plus code: 7P52PGP8+XJ\n",
382
  "\n",
383
  "\n",
384
  " \n",
385
- " address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\n",
386
  "\n",
387
- " location: {'lat': 13.7466896, 'lng': 100.5304572}\n",
388
  "\n",
389
- " name: Gallery Drip Coffee\n",
390
  "\n",
391
  " opening hours: {'open_now': True}\n",
392
  "\n",
393
- " rating: 4.6\n",
394
  "\n",
395
- " plus code: 7P52PGWJ+M5\n",
396
  "\n",
397
  "\n",
398
  " \n",
399
- " address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\n",
400
  "\n",
401
- " location: {'lat': 13.7408514, 'lng': 100.5230725}\n",
402
  "\n",
403
- " name: mm : MAKE MERRY\n",
404
  "\n",
405
  " opening hours: {'open_now': True}\n",
406
  "\n",
407
- " rating: 4.8\n",
408
  "\n",
409
- " plus code: 7P52PGRF+86\n",
410
  "\n",
411
  "\n",
412
  " \n",
413
- " address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\n",
414
  "\n",
415
- " location: {'lat': 13.7446247, 'lng': 100.5340785}\n",
416
  "\n",
417
- " name: GATTA CAFé\n",
418
  "\n",
419
  " opening hours: {'open_now': True}\n",
420
  "\n",
421
- " rating: 4.9\n",
422
  "\n",
423
- " plus code: 7P52PGVM+RJ\n",
424
  "\n",
425
  "\n",
426
  " \n",
427
- " address: 1873 Rama IV Rd, Khlong Tan Nuea, Watthana\n",
428
  "\n",
429
- " location: {'lat': 13.7335441, 'lng': 100.5377224}\n",
430
  "\n",
431
- " name: Redwood coffee and eatery\n",
432
  "\n",
433
  " opening hours: {'open_now': True}\n",
434
  "\n",
435
  " rating: 4.8\n",
436
  "\n",
437
- " plus code: 7P52PGMQ+C3\n",
438
  "\n",
439
  "\n",
440
  " \n",
441
- " address: B1 The Offices At Central World ชั้น 104 Rama I Rd, Pathum Wan\n",
442
  "\n",
443
- " location: {'lat': 13.7458267, 'lng': 100.5381669}\n",
444
  "\n",
445
- " name: Baankhunlek coffee สาขา CentralworldOffices\n",
446
  "\n",
447
  " opening hours: {'open_now': True}\n",
448
  "\n",
449
- " rating: 5\n",
450
  "\n",
451
- " plus code: 7P52PGWQ+87\n",
452
  "\n",
453
  "\n",
454
  " \n",
455
- " address: 3rd Floor, CentralWorld, Ratchadamri Rd, Pathum Wan\n",
456
  "\n",
457
- " location: {'lat': 13.7470656, 'lng': 100.5397062}\n",
458
  "\n",
459
- " name: Café BAGA Central World\n",
460
  "\n",
461
  " opening hours: {'open_now': True}\n",
462
  "\n",
463
- " rating: 4.7\n",
464
  "\n",
465
- " plus code: 7P52PGWQ+RV\n",
466
  "\n",
467
  "\n",
468
  " \u001b[0m"
469
  ]
470
- },
471
- {
472
- "name": "stderr",
473
- "output_type": "stream",
474
- "text": [
475
- "Unable to load requested LangChainTracer. To disable this warning, unset the LANGCHAIN_TRACING_V2 environment variables.\n",
476
- "LangSmithUserError('API key must be provided when using hosted LangSmith API')\n"
477
- ]
478
- },
479
- {
480
- "name": "stdout",
481
- "output_type": "stream",
482
- "text": [
483
- "\u001b[32;1m\u001b[1;3mHere is a list of coffee shops near มาบุญครอง (MBK Center):\n",
484
- "\n",
485
- "1. **BEANS Coffee Roaster Paragon**\n",
486
- " - Address: 991/1 Rama I Rd, Pathum Wan\n",
487
- " - Rating: 5.0\n",
488
- " - Open Now: Yes\n",
489
- "\n",
490
- "2. **Olympic Coffee**\n",
491
- " - Address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\n",
492
- " - Rating: 4.8\n",
493
- " - Open Now: Yes\n",
494
- "\n",
495
- "3. **Earthy Roaster (Specialty Coffee)**\n",
496
- " - Address: 994 Makkasan, Ratchathewi\n",
497
- " - Rating: 4.8\n",
498
- " - Open Now: Yes\n",
499
- "\n",
500
- "4. **Treasure specialty coffee**\n",
501
- " - Address: MINT TOWER Bantadthong Phetchaburi Rd, Pathum Wan\n",
502
- " - Rating: 4.9\n",
503
- " - Open Now: Yes\n",
504
- "\n",
505
- "5. **The Basic Coffee BKK**\n",
506
- " - Address: ตึก Gaysorn Amarin, ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n",
507
- " - Rating: 4.7\n",
508
- " - Open Now: Yes\n",
509
- "\n",
510
- "6. **CRANNIES Coffee & Brunch**\n",
511
- " - Address: 126 ซ. จุฬาลงกรณ์ 50 Wang Mai, Pathum Wan\n",
512
- " - Rating: 5.0\n",
513
- " - Open Now: Yes\n",
514
- "\n",
515
- "7. **Bullet Thai Craft Beer**\n",
516
- " - Address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n",
517
- " - Rating: 5.0\n",
518
- " - Open Now: Yes\n",
519
- "\n",
520
- "8. **Sip 'n Drip**\n",
521
- " - Address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n",
522
- " - Rating: 4.9\n",
523
- " - Open Now: Yes\n",
524
- "\n",
525
- "9. **TABLA Craft Coffee**\n",
526
- " - Address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n",
527
- " - Rating: 4.6\n",
528
- " - Open Now: Yes\n",
529
- "\n",
530
- "10. **The Coffee Academics**\n",
531
- " - Address: Velaa Sindhorn Village Langsuan, 87 Soi Langsuan, Lumphini, Pathum Wan\n",
532
- " - Rating: 4.4\n",
533
- " - Open Now: Yes\n",
534
- "\n",
535
- "11. **D Coffee House**\n",
536
- " - Address: 445 Rama I Rd, Rong Muang, Pathum Wan\n",
537
- " - Rating: 4.9\n",
538
- " - Open Now: Yes\n",
539
- "\n",
540
- "12. **Baptist coffee**\n",
541
- " - Address: ศูนย์รวมนักศึกษาแบ๊บติสต์ 473 Thanon Si Ayutthaya, Thung Phaya Thai, Ratchathewi\n",
542
- " - Rating: 5.0\n",
543
- " - Open Now: Yes\n",
544
- "\n",
545
- "13. **Greatercafe Specialty Coffee Bangkok**\n",
546
- " - Address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\n",
547
- " - Rating: 4.7\n",
548
- " - Open Now: Yes\n",
549
- "\n",
550
- "14. **Better Coffee**\n",
551
- " - Address: Bldg., 1 st Fl 320 TangHuaPak (Hualamphong Rama IV Rd, Mahapruettaram Bang Rak\n",
552
- " - Rating: 5.0\n",
553
- " - Open Now: Yes\n",
554
- "\n",
555
- "15. **Gallery Drip Coffee**\n",
556
- " - Address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\n",
557
- " - Rating: 4.6\n",
558
- " - Open Now: Yes\n",
559
- "\n",
560
- "16. **mm : MAKE MERRY**\n",
561
- " - Address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\n",
562
- " - Rating: 4.8\n",
563
- " - Open Now: Yes\n",
564
- "\n",
565
- "17. **GATTA CAFé**\n",
566
- " - Address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\n",
567
- " - Rating: 4.9\n",
568
- " - Open Now: Yes\n",
569
- "\n",
570
- "18. **Redwood coffee and eatery**\n",
571
- " - Address: 1873 Rama IV Rd, Khlong Tan Nuea, Watthana\n",
572
- " - Rating: 4.8\n",
573
- " - Open Now: Yes\n",
574
- "\n",
575
- "19. **Baankhunlek coffee สาขา CentralworldOffices**\n",
576
- " - Address: B1 The Offices At Central World ชั้น 104 Rama I Rd, Pathum Wan\n",
577
- " - Rating: 5.0\n",
578
- " - Open Now: Yes\n",
579
- "\n",
580
- "20. **Café BAGA Central World**\n",
581
- " - Address: 3rd Floor, CentralWorld, Ratchadamri Rd, Pathum Wan\n",
582
- " - Rating: 4.7\n",
583
- " - Open Now: Yes\n",
584
- "\n",
585
- "These coffee shops are within a radius of approximately 1500 meters from MBK Center and are currently open.\u001b[0m\n",
586
- "\n",
587
- "\u001b[1m> Finished chain.\u001b[0m\n"
588
- ]
589
- },
590
- {
591
- "data": {
592
- "text/plain": [
593
- "\"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.\""
594
- ]
595
- },
596
- "execution_count": 3,
597
- "metadata": {},
598
- "output_type": "execute_result"
599
  }
600
  ],
601
  "source": [
 
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
+ "execution_count": 1,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
 
15
  },
16
  {
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
  ],
 
100
  },
101
  {
102
  "cell_type": "code",
103
+ "execution_count": 3,
104
  "metadata": {},
105
  "outputs": [
106
  {
 
149
  "output_type": "stream",
150
  "text": [
151
  "\u001b[32;1m\u001b[1;3m\n",
152
+ "Invoking: `nearby_search` with `{'input_dict': {'keyword': 'ร้านกาแฟ', 'location_name': 'มาบุญครอง', 'radius': 1000, 'place_type': 'cafe'}}`\n",
153
  "\n",
154
  "\n",
155
  "\u001b[0m"
 
179
  "name": "stdout",
180
  "output_type": "stream",
181
  "text": [
182
+ "\u001b[33;1m\u001b[1;3mnumber of results more than 20\n",
 
183
  "\n",
184
+ " address: อาคารหอศิลปวัฒนธรรมแห่งกรุงเทพมหานคร(BACC) 939 Rama I Rd, Wang Mai, Pathum Wan\n",
185
  "\n",
186
+ " location: {'lat': 13.7466896, 'lng': 100.5304572}\n",
187
+ "\n",
188
+ " name: Gallery Drip Coffee\n",
189
  "\n",
190
  " opening hours: {'open_now': True}\n",
191
  "\n",
192
+ " rating: 4.6\n",
193
  "\n",
194
+ " plus code: 7P52PGWJ+M5\n",
195
  "\n",
196
  "\n",
197
  " \n",
198
+ " address: 445 Rama I Rd, Rong Muang, Pathum Wan\n",
199
  "\n",
200
+ " location: {'lat': 13.7476317, 'lng': 100.5232939}\n",
201
  "\n",
202
+ " name: D Coffee House\n",
203
  "\n",
204
  " opening hours: {'open_now': True}\n",
205
  "\n",
206
+ " rating: 4.9\n",
207
  "\n",
208
+ " plus code: 7P52PGXF+38\n",
209
  "\n",
210
  "\n",
211
  " \n",
212
+ " address: 43/4 Rama VI Rd, Rong Muang, Pathum Wan\n",
213
  "\n",
214
+ " location: {'lat': 13.7497223, 'lng': 100.521221}\n",
215
  "\n",
216
+ " name: Olympic Coffee\n",
217
  "\n",
218
  " opening hours: {'open_now': True}\n",
219
  "\n",
220
  " rating: 4.8\n",
221
  "\n",
222
+ " plus code: 7P52PGXC+VF\n",
223
  "\n",
224
  "\n",
225
  " \n",
226
+ " address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n",
227
  "\n",
228
+ " location: {'lat': 13.7477989, 'lng': 100.5296324}\n",
229
  "\n",
230
+ " name: Sip 'n Drip\n",
231
  "\n",
232
  " opening hours: {'open_now': True}\n",
233
  "\n",
234
  " rating: 4.9\n",
235
  "\n",
236
+ " plus code: 7P52PGXH+4V\n",
237
  "\n",
238
  "\n",
239
  " \n",
240
+ " address: 27 ซอย จุฬาลงกรณ์ 20 Wang Mai, Pathum Wan\n",
241
  "\n",
242
+ " location: {'lat': 13.7408514, 'lng': 100.5230725}\n",
243
  "\n",
244
+ " name: mm : MAKE MERRY\n",
245
  "\n",
246
  " opening hours: {'open_now': True}\n",
247
  "\n",
248
+ " rating: 4.8\n",
249
  "\n",
250
+ " plus code: 7P52PGRF+86\n",
251
  "\n",
252
  "\n",
253
  " \n",
254
+ " address: 2nd Floor Siam Square One 388 Rama I Rd, Pathum Wan\n",
255
  "\n",
256
+ " location: {'lat': 13.7446247, 'lng': 100.5340785}\n",
257
  "\n",
258
+ " name: GATTA CAFé\n",
259
  "\n",
260
  " opening hours: {'open_now': True}\n",
261
  "\n",
262
+ " rating: 4.9\n",
263
  "\n",
264
+ " plus code: 7P52PGVM+RJ\n",
265
  "\n",
266
  "\n",
267
  " \n",
268
+ " address: MINT TOWER Bantadthong Phetchaburi Rd, Subdistrict Pathum Wan\n",
269
  "\n",
270
+ " location: {'lat': 13.7450255, 'lng': 100.5235735}\n",
271
  "\n",
272
+ " name: Treasure specialty coffee\n",
273
  "\n",
274
  " opening hours: {'open_now': True}\n",
275
  "\n",
276
+ " rating: 4.9\n",
277
  "\n",
278
+ " plus code: 7P52PGWF+2C\n",
279
  "\n",
280
  "\n",
281
  " \n",
282
+ " address: 991/1 Rama I Rd, Pathum Wan\n",
283
  "\n",
284
+ " location: {'lat': 13.7458781, 'lng': 100.5341476}\n",
285
  "\n",
286
+ " name: BEANS Coffee Roaster Paragon\n",
287
  "\n",
288
  " opening hours: {'open_now': True}\n",
289
  "\n",
290
+ " rating: 5\n",
291
  "\n",
292
+ " plus code: 7P52PGWM+9M\n",
293
  "\n",
294
  "\n",
295
  " \n",
296
+ " address: 226 Siam Square Soi 7, Pathum Wan\n",
297
  "\n",
298
+ " location: {'lat': 13.7448544, 'lng': 100.5317337}\n",
299
  "\n",
300
+ " name: MONGKOL COFFEE X WARMBATCH ROASTERS\n",
301
  "\n",
302
+ " opening hours: N/A\n",
303
  "\n",
304
+ " rating: 4.9\n",
305
  "\n",
306
+ " plus code: 7P52PGVJ+WM\n",
307
  "\n",
308
  "\n",
309
  " \n",
310
+ " address: B106 เลขที่ 353, 355, Charoen Mueang Rd, Wang Mai, Pathum Wan\n",
311
  "\n",
312
+ " location: {'lat': 13.7402072, 'lng': 100.5244642}\n",
313
  "\n",
314
+ " name: Trentotto, Home of Coffee I'm Park\n",
315
  "\n",
316
  " opening hours: {'open_now': True}\n",
317
  "\n",
318
+ " rating: 4.8\n",
319
  "\n",
320
+ " plus code: 7P52PGRF+3Q\n",
321
  "\n",
322
  "\n",
323
  " \n",
324
+ " address: 83 85 ซอยจุฬา 16 Wang Mai, Pathum Wan\n",
325
  "\n",
326
+ " location: {'lat': 13.7419898, 'lng': 100.5236568}\n",
327
  "\n",
328
+ " name: Chawarin\n",
329
  "\n",
330
  " opening hours: {'open_now': True}\n",
331
  "\n",
332
  " rating: 4.9\n",
333
  "\n",
334
+ " plus code: 7P52PGRF+QF\n",
335
  "\n",
336
  "\n",
337
  " \n",
338
+ " address: 1/11 Rong Muang 5 Alley, Rong Muang, Pathum Wan\n",
339
  "\n",
340
+ " location: {'lat': 13.7466928, 'lng': 100.5227848}\n",
341
  "\n",
342
+ " name: Greatercafe Specialty Coffee Bangkok\n",
343
  "\n",
344
  " opening hours: {'open_now': True}\n",
345
  "\n",
346
+ " rating: 4.7\n",
347
  "\n",
348
+ " plus code: 7P52PGWF+M4\n",
349
  "\n",
350
  "\n",
351
  " \n",
352
+ " address: 266/15 Rama I Rd, Pathum Wan\n",
353
  "\n",
354
+ " location: {'lat': 13.7454978, 'lng': 100.5330408}\n",
355
  "\n",
356
+ " name: Mongkol COFFEE\n",
357
  "\n",
358
  " opening hours: {'open_now': True}\n",
359
  "\n",
360
+ " rating: 4.6\n",
361
  "\n",
362
+ " plus code: 7P52PGWM+66\n",
363
  "\n",
364
  "\n",
365
  " \n",
366
+ " address: 645, 47 Phetchaburi Rd, Thanon Phaya Thai, Ratchathewi\n",
367
  "\n",
368
+ " location: {'lat': 13.7518404, 'lng': 100.5362577}\n",
369
  "\n",
370
+ " name: 26y coffee\n",
371
  "\n",
372
  " opening hours: {'open_now': True}\n",
373
  "\n",
374
+ " rating: 4.9\n",
375
  "\n",
376
+ " plus code: 7P52QG2P+PG\n",
377
  "\n",
378
  "\n",
379
  " \n",
380
+ " address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n",
381
  "\n",
382
+ " location: {'lat': 13.7537094, 'lng': 100.5328794}\n",
383
  "\n",
384
+ " name: Bullet Thai Craft Beer\n",
385
  "\n",
386
  " opening hours: {'open_now': True}\n",
387
  "\n",
388
+ " rating: 5\n",
389
  "\n",
390
+ " plus code: 7P52QG3M+F5\n",
391
  "\n",
392
  "\n",
393
  " \n",
394
+ " address: ชั้น จี, 999/9 Rama I Rd, Pathum Wan\n",
395
  "\n",
396
+ " location: {'lat': 13.745689, 'lng': 100.5383407}\n",
397
  "\n",
398
+ " name: Pacamara Coffee Roasters (The Offices at CentralwOrld)\n",
399
  "\n",
400
  " opening hours: {'open_now': True}\n",
401
  "\n",
402
+ " rating: 4.4\n",
403
  "\n",
404
+ " plus code: 7P52PGWQ+78\n",
405
  "\n",
406
  "\n",
407
  " \n",
408
+ " address: Dragon Town ชั้น 2 เลขที่ 188/66 Wang Mai, Pathum Wan\n",
409
  "\n",
410
+ " location: {'lat': 13.7407797, 'lng': 100.5245334}\n",
411
  "\n",
412
+ " name: OKA x LOMNUA cafe & coffee roaster\n",
413
  "\n",
414
  " opening hours: {'open_now': True}\n",
415
  "\n",
416
+ " rating: 4.7\n",
417
  "\n",
418
+ " plus code: 7P52PGRF+8R\n",
419
  "\n",
420
  "\n",
421
  " \n",
422
+ " address: 1800 ถนน บรรทัดทอง Wang Mai, Pathum Wan\n",
423
  "\n",
424
+ " location: {'lat': 13.7389399, 'lng': 100.5221088}\n",
425
  "\n",
426
+ " name: Bantatthong Cafe\n",
427
  "\n",
428
  " opening hours: {'open_now': True}\n",
429
  "\n",
430
  " rating: 4.8\n",
431
  "\n",
432
+ " plus code: 7P52PGQC+HR\n",
433
  "\n",
434
  "\n",
435
  " \n",
436
+ " address: 535 31 ตรอก Wat Phraya Yang Alley, Khwaeng Thanon Phetchaburi, Ratchathewi\n",
437
  "\n",
438
+ " location: {'lat': 13.7513197, 'lng': 100.5264651}\n",
439
  "\n",
440
+ " name: Piccolo Vicolo Café\n",
441
  "\n",
442
  " opening hours: {'open_now': True}\n",
443
  "\n",
444
+ " rating: 4.7\n",
445
  "\n",
446
+ " plus code: 7P52QG2G+GH\n",
447
  "\n",
448
  "\n",
449
  " \n",
450
+ " address: 1, 50 Phetchaburi Rd, Thanon Phaya Thai, Ratchathewi\n",
451
  "\n",
452
+ " location: {'lat': 13.7520417, 'lng': 100.5386537}\n",
453
  "\n",
454
+ " name: MIND SLOWBAR (ประตูน้ำ เพชรบุรีซอย19)\n",
455
  "\n",
456
  " opening hours: {'open_now': True}\n",
457
  "\n",
458
+ " rating: 4.9\n",
459
  "\n",
460
+ " plus code: 7P52QG2Q+RF\n",
461
  "\n",
462
  "\n",
463
  " \u001b[0m"
464
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  }
466
  ],
467
  "source": [
chatbot_multiagent.ipynb ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "import os\n",
10
+ "import utils\n",
11
+ "\n",
12
+ "utils.load_env()\n",
13
+ "os.environ['LANGCHAIN_TRACING_V2'] = \"false\""
14
+ ]
15
+ },
16
+ {
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
+ "import operator\n",
35
+ "import functools\n",
36
+ "\n",
37
+ "# for llm model\n",
38
+ "from langchain_openai import ChatOpenAI\n",
39
+ "from langchain.agents.format_scratchpad import format_to_openai_function_messages\n",
40
+ "from tools import find_place_from_text, nearby_search\n",
41
+ "from typing import Dict, List, Tuple, Annotated, Sequence, TypedDict\n",
42
+ "from langchain.agents import (\n",
43
+ " AgentExecutor,\n",
44
+ ")\n",
45
+ "from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser\n",
46
+ "from langchain_community.chat_models import ChatOpenAI\n",
47
+ "from langchain_community.tools.convert_to_openai import format_tool_to_openai_function\n",
48
+ "from langchain_core.messages import (\n",
49
+ " AIMessage, \n",
50
+ " HumanMessage,\n",
51
+ " BaseMessage,\n",
52
+ " ToolMessage\n",
53
+ ")\n",
54
+ "from langchain_core.pydantic_v1 import BaseModel, Field\n",
55
+ "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
56
+ "from langgraph.graph import END, StateGraph, START\n",
57
+ "\n",
58
+ "## Document vector store for context\n",
59
+ "from langchain_core.runnables import RunnablePassthrough\n",
60
+ "from langchain_chroma import Chroma\n",
61
+ "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
62
+ "from langchain_community.document_loaders import CSVLoader\n",
63
+ "from langchain_openai import OpenAIEmbeddings\n",
64
+ "import glob\n",
65
+ "from langchain.tools import Tool\n",
66
+ "\n",
67
+ "def format_docs(docs):\n",
68
+ " return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
69
+ "\n",
70
+ "# Specify the pattern\n",
71
+ "file_pattern = \"document/*.csv\"\n",
72
+ "file_paths = tuple(glob.glob(file_pattern))\n",
73
+ "\n",
74
+ "all_docs = []\n",
75
+ "\n",
76
+ "for file_path in file_paths:\n",
77
+ " loader = CSVLoader(file_path=file_path)\n",
78
+ " docs = loader.load()\n",
79
+ " all_docs.extend(docs) # Add the documents to the list\n",
80
+ "\n",
81
+ "# Split text into chunks separated.\n",
82
+ "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)\n",
83
+ "splits = text_splitter.split_documents(all_docs)\n",
84
+ "\n",
85
+ "# Text Vectorization.\n",
86
+ "vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())\n",
87
+ "\n",
88
+ "# Retrieve and generate using the relevant snippets of the blog.\n",
89
+ "retriever = vectorstore.as_retriever()\n",
90
+ "\n",
91
+ "## tools and LLM\n",
92
+ "\n",
93
+ "retriever_tool = Tool(\n",
94
+ " name=\"Retriever\",\n",
95
+ " func=retriever.get_relevant_documents,\n",
96
+ " description=\"Use this tool to retrieve information about population, community and household expenditures.\"\n",
97
+ ")\n",
98
+ "\n",
99
+ "# Bind the tools to the model\n",
100
+ "tools = [retriever_tool, find_place_from_text, nearby_search] # Include both tools if needed\n",
101
+ "\n",
102
+ "llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
103
+ "\n",
104
+ "## Create agents\n",
105
+ "def create_agent(llm, tools, system_message: str):\n",
106
+ " \"\"\"Create an agent.\"\"\"\n",
107
+ " prompt = ChatPromptTemplate.from_messages(\n",
108
+ " [\n",
109
+ " (\n",
110
+ " \"system\",\n",
111
+ " \"You are a helpful AI assistant, collaborating with other assistants.\"\n",
112
+ " \" Use the provided tools to progress towards answering the question.\"\n",
113
+ " \" If you are unable to fully answer, that's OK, another assistant with different tools \"\n",
114
+ " \" will help where you left off. Execute what you can to make progress.\"\n",
115
+ " \" If you or any of the other assistants have the final answer or deliverable,\"\n",
116
+ " \" prefix your response with FINAL ANSWER so the team knows to stop.\"\n",
117
+ " \" You have access to the following tools: {tool_names}.\\n{system_message}\",\n",
118
+ " ),\n",
119
+ " MessagesPlaceholder(variable_name=\"messages\"),\n",
120
+ " ]\n",
121
+ " )\n",
122
+ " prompt = prompt.partial(system_message=system_message)\n",
123
+ " prompt = prompt.partial(tool_names=\", \".join([tool.name for tool in tools]))\n",
124
+ " llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])\n",
125
+ " # return prompt | llm.bind_tools(tools)\n",
126
+ " agent = prompt | llm_with_tools\n",
127
+ " return agent\n",
128
+ "\n",
129
+ "\n",
130
+ "## Define state\n",
131
+ "# This defines the object that is passed between each node\n",
132
+ "# in the graph. We will create different nodes for each agent and tool\n",
133
+ "class AgentState(TypedDict):\n",
134
+ " messages: Annotated[Sequence[BaseMessage], operator.add]\n",
135
+ " sender: str\n",
136
+ "\n",
137
+ "\n",
138
+ "# Helper function to create a node for a given agent\n",
139
+ "def agent_node(state, agent, name):\n",
140
+ " result = agent.invoke(state)\n",
141
+ " # We convert the agent output into a format that is suitable to append to the global state\n",
142
+ " if isinstance(result, ToolMessage):\n",
143
+ " pass\n",
144
+ " else:\n",
145
+ " result = AIMessage(**result.dict(exclude={\"type\", \"name\"}), name=name)\n",
146
+ " return {\n",
147
+ " \"messages\": [result],\n",
148
+ " # Since we have a strict workflow, we can\n",
149
+ " # track the sender so we know who to pass to next.\n",
150
+ " \"sender\": name,\n",
151
+ " }\n",
152
+ "\n",
153
+ "\n",
154
+ "## Define Agents Node\n",
155
+ "# Research agent and node\n",
156
+ "agent_meta = utils.load_agent_meta()\n",
157
+ "agent_name = [meta['name'] for meta in agent_meta]\n",
158
+ "\n",
159
+ "agents={}\n",
160
+ "agent_nodes={}\n",
161
+ "\n",
162
+ "for meta in agent_meta:\n",
163
+ " name = meta['name']\n",
164
+ " prompt = meta['prompt']\n",
165
+ " \n",
166
+ " agents[name] = create_agent(\n",
167
+ " llm,\n",
168
+ " [find_place_from_text, nearby_search],\n",
169
+ " system_message=prompt,\n",
170
+ " )\n",
171
+ " \n",
172
+ " agent_nodes[name] = functools.partial(agent_node, agent=agents[name], name=name)\n",
173
+ "\n",
174
+ "\n",
175
+ "## Define Tool Node\n",
176
+ "from langgraph.prebuilt import ToolNode\n",
177
+ "from typing import Literal\n",
178
+ "\n",
179
+ "tool_node = ToolNode(tools)\n",
180
+ "\n",
181
+ "def router(state) -> Literal[\"call_tool\", \"__end__\", \"continue\"]:\n",
182
+ " # This is the router\n",
183
+ " messages = state[\"messages\"]\n",
184
+ " last_message = messages[-1]\n",
185
+ " if last_message.tool_calls:\n",
186
+ " # The previous agent is invoking a tool\n",
187
+ " return \"call_tool\"\n",
188
+ " if \"FINAL ANSWER\" in last_message.content:\n",
189
+ " # Any agent decided the work is done\n",
190
+ " return \"__end__\"\n",
191
+ " return \"continue\"\n",
192
+ "\n",
193
+ "\n",
194
+ "## Workflow Graph\n",
195
+ "workflow = StateGraph(AgentState)\n",
196
+ "\n",
197
+ "# add agent nodes\n",
198
+ "for name, node in agent_nodes.items():\n",
199
+ " workflow.add_node(name, node)\n",
200
+ " \n",
201
+ "workflow.add_node(\"call_tool\", tool_node)\n",
202
+ "\n",
203
+ "\n",
204
+ "for meta in agent_meta:\n",
205
+ " workflow.add_conditional_edges(\n",
206
+ " meta[\"name\"],\n",
207
+ " router,\n",
208
+ " {\"continue\": meta['continue'], \"call_tool\": \"call_tool\", \"__end__\": END},\n",
209
+ " )\n",
210
+ "\n",
211
+ "workflow.add_conditional_edges(\n",
212
+ " \"call_tool\",\n",
213
+ " # Each agent node updates the 'sender' field\n",
214
+ " # the tool calling node does not, meaning\n",
215
+ " # this edge will route back to the original agent\n",
216
+ " # who invoked the tool\n",
217
+ " lambda x: x[\"sender\"],\n",
218
+ " {name: name for name in agent_name},\n",
219
+ ")\n",
220
+ "workflow.add_edge(START, \"analyst\")\n",
221
+ "graph = workflow.compile()"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": 3,
227
+ "metadata": {},
228
+ "outputs": [
229
+ {
230
+ "data": {
231
+ "image/jpeg": "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",
232
+ "text/plain": [
233
+ "<IPython.core.display.Image object>"
234
+ ]
235
+ },
236
+ "metadata": {},
237
+ "output_type": "display_data"
238
+ }
239
+ ],
240
+ "source": [
241
+ "from IPython.display import Image, display\n",
242
+ "\n",
243
+ "try:\n",
244
+ " display(Image(graph.get_graph(xray=True).draw_mermaid_png()))\n",
245
+ "except Exception:\n",
246
+ " # This requires some extra dependencies and is optional\n",
247
+ " pass"
248
+ ]
249
+ },
250
+ {
251
+ "cell_type": "code",
252
+ "execution_count": 4,
253
+ "metadata": {},
254
+ "outputs": [
255
+ {
256
+ "name": "stdout",
257
+ "output_type": "stream",
258
+ "text": [
259
+ "{'analyst': {'messages': [AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"location\":\"มาบุญครอง\"}', 'name': 'find_place_from_text'}}, response_metadata={'token_usage': {'completion_tokens': 21, 'prompt_tokens': 329, 'total_tokens': 350}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'function_call', 'logprobs': None}, name='analyst', id='run-e6c09af4-41ab-441b-b471-751510f63096-0')], 'sender': 'analyst'}}\n",
260
+ "----\n",
261
+ "{'data collector': {'messages': [AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"input_dict\":{\"keyword\":\"ร้านกาแฟ\",\"location_name\":\"มาบุญครอง\",\"radius\":1000,\"place_type\":\"cafe\"}}', 'name': 'nearby_search'}}, response_metadata={'token_usage': {'completion_tokens': 42, 'prompt_tokens': 326, 'total_tokens': 368}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'function_call', 'logprobs': None}, name='data collector', id='run-19518aa2-3c77-46bd-a35a-76e87188ade0-0')], 'sender': 'data collector'}}\n",
262
+ "----\n",
263
+ "{'reporter': {'messages': [AIMessage(content='ฉันได้ค้นหาร้านกาแฟใกล้มาบุญครองแล้ว นี่คือรายการร้านกาแฟที่น่าสนใจ:\\n\\n1. **ร้านกาแฟ A** \\n - ที่อยู่: ถนนมาบุญครอง\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 08:00 - 20:00\\n\\n2. **ร้านกาแฟ B**\\n - ที่อยู่: ซอยมาบุญครอง\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 09:00 - 21:00\\n\\n3. **ร้านกาแฟ C**\\n - ที่อยู่: มาบุญครอง ชั้น 2\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 07:30 - 19:30\\n\\nหากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับร้านใดหรือรายละเอียดเพิ่มเติม กรุณาแจ้งให้ทราบ!', response_metadata={'token_usage': {'completion_tokens': 203, 'prompt_tokens': 421, 'total_tokens': 624}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_507c9469a1', 'finish_reason': 'stop', 'logprobs': None}, name='reporter', id='run-68022425-467e-4b41-930a-fa283d11d60d-0')], 'sender': 'reporter'}}\n",
264
+ "----\n",
265
+ "{'data collector': {'messages': [AIMessage(content='FINAL ANSWER: ฉันได้ค้นหาร้านกาแฟใกล้มาบุญครองแล้ว นี่คือรายการร้านกาแฟที่น่าสนใจ:\\n\\n1. **ร้านกาแฟ A** \\n - ที่อยู่: ถนนมาบุญครอง\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 08:00 - 20:00\\n\\n2. **ร้านกาแฟ B**\\n - ที่อยู่: ซอยมาบุญครอง\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 09:00 - 21:00\\n\\n3. **ร้านกาแฟ C**\\n - ที่อยู่: มาบุญครอง ชั้น 2\\n - โทรศัพท์: 02-xxx-xxxx\\n - เวลาเปิด: 07:30 - 19:30\\n\\nหากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับร้านใดหรือรายละเอียดเพิ่มเติม กรุณาแจ้งให้ทราบ!', response_metadata={'token_usage': {'completion_tokens': 207, 'prompt_tokens': 577, 'total_tokens': 784}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, name='data collector', id='run-255ad92f-2960-440e-b20a-229da6f87b34-0')], 'sender': 'data collector'}}\n",
266
+ "----\n"
267
+ ]
268
+ }
269
+ ],
270
+ "source": [
271
+ "graph = workflow.compile()\n",
272
+ "\n",
273
+ "events = graph.stream(\n",
274
+ " {\n",
275
+ " \"messages\": [\n",
276
+ " HumanMessage(\n",
277
+ " content=\"ค้นหาร้านกาแฟใกล้มาบุญครอง\"\n",
278
+ " )\n",
279
+ " ],\n",
280
+ " },\n",
281
+ " # Maximum number of steps to take in the graph\n",
282
+ " {\"recursion_limit\": 10},\n",
283
+ ")\n",
284
+ "for s in events:\n",
285
+ " print(s)\n",
286
+ " print(\"----\")"
287
+ ]
288
+ },
289
+ {
290
+ "cell_type": "code",
291
+ "execution_count": 6,
292
+ "metadata": {},
293
+ "outputs": [
294
+ {
295
+ "data": {
296
+ "text/plain": [
297
+ "'รายชื่อร้านกาแฟใกล้มาบุญครอง ได้แก่:\\n\\n1. **ร้านกาแฟ A**\\n - ที่อยู่: ถนนพระราม 1\\n - ระยะทาง: 500 เมตรจากมาบุญครอง\\n - ความคิดเห็น: บริการดี บรรยากาศดี\\n\\n2. **ร้านกาแฟ B**\\n - ที่อยู่: สยามสแควร์\\n - ระยะทาง: 800 เมตรจากมาบุญครอง\\n - ความคิดเห็น: กาแฟอร่อย แนะนำเมนูพิเศษ\\n\\n3. **ร้านกาแฟ C**\\n - ที่อยู่: สวนลุมพินี\\n - ระยะทาง: 1.5 กม.จากมาบุญครอง\\n - ความคิดเห็น: มีมุมสงบ เหมาะสำหรับอ่านหนังสือ\\n\\n4. **ร้านกาแฟ D**\\n - ที่อยู่: ถนนสีลม\\n - ระยะทาง: 2 กม.จากมาบุญครอง\\n - ความคิดเห็น: คาเฟ่สไตล์โมเดิร์น มี Wi-Fi ฟรี\\n\\nหากต้องการข้อมูลเพิ่มเติมหรือคำแนะนำเพิ่มเติม สามารถสอบถามได้ค่ะ!'"
298
+ ]
299
+ },
300
+ "execution_count": 6,
301
+ "metadata": {},
302
+ "output_type": "execute_result"
303
+ }
304
+ ],
305
+ "source": [
306
+ "def submitUserMessage(user_input: str) -> str:\n",
307
+ " graph = workflow.compile()\n",
308
+ "\n",
309
+ " events = graph.stream(\n",
310
+ " {\n",
311
+ " \"messages\": [\n",
312
+ " HumanMessage(\n",
313
+ " content=user_input\n",
314
+ " )\n",
315
+ " ],\n",
316
+ " },\n",
317
+ " # Maximum number of steps to take in the graph\n",
318
+ " {\"recursion_limit\": 15},\n",
319
+ " )\n",
320
+ " \n",
321
+ " events = [e for e in events]\n",
322
+ " \n",
323
+ " response = events[-1]['data collector']['messages'][0].content.replace(\"FINAL ANSWER: \", \"\")\n",
324
+ " \n",
325
+ " return response\n",
326
+ "\n",
327
+ "submitUserMessage(\"ค้นหาร้านกาแฟใกล้มาบุญครอง\")"
328
+ ]
329
+ }
330
+ ],
331
+ "metadata": {
332
+ "kernelspec": {
333
+ "display_name": "Python 3",
334
+ "language": "python",
335
+ "name": "python3"
336
+ },
337
+ "language_info": {
338
+ "codemirror_mode": {
339
+ "name": "ipython",
340
+ "version": 3
341
+ },
342
+ "file_extension": ".py",
343
+ "mimetype": "text/x-python",
344
+ "name": "python",
345
+ "nbconvert_exporter": "python",
346
+ "pygments_lexer": "ipython3",
347
+ "version": "3.11.9"
348
+ }
349
+ },
350
+ "nbformat": 4,
351
+ "nbformat_minor": 2
352
+ }
chatbot_multiagent.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%
2
+ import os
3
+ import utils
4
+
5
+ utils.load_env()
6
+ os.environ['LANGCHAIN_TRACING_V2'] = "false"
7
+
8
+ # %%
9
+ from langchain_core.messages import HumanMessage
10
+ import operator
11
+ import functools
12
+
13
+ # for llm model
14
+ from langchain_openai import ChatOpenAI
15
+ from langchain.agents.format_scratchpad import format_to_openai_function_messages
16
+ from tools import find_place_from_text, nearby_search
17
+ from typing import Dict, List, Tuple, Annotated, Sequence, TypedDict
18
+ from langchain.agents import (
19
+ AgentExecutor,
20
+ )
21
+ from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
22
+ from langchain_community.chat_models import ChatOpenAI
23
+ from langchain_community.tools.convert_to_openai import format_tool_to_openai_function
24
+ from langchain_core.messages import (
25
+ AIMessage,
26
+ HumanMessage,
27
+ BaseMessage,
28
+ ToolMessage
29
+ )
30
+ from langchain_core.pydantic_v1 import BaseModel, Field
31
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
32
+ from langgraph.graph import END, StateGraph, START
33
+
34
+ ## Document vector store for context
35
+ from langchain_core.runnables import RunnablePassthrough
36
+ from langchain_chroma import Chroma
37
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
38
+ from langchain_community.document_loaders import CSVLoader
39
+ from langchain_openai import OpenAIEmbeddings
40
+ import glob
41
+ from langchain.tools import Tool
42
+
43
+ def format_docs(docs):
44
+ return "\n\n".join(doc.page_content for doc in docs)
45
+
46
+ # Specify the pattern
47
+ file_pattern = "document/*.csv"
48
+ file_paths = tuple(glob.glob(file_pattern))
49
+
50
+ all_docs = []
51
+
52
+ for file_path in file_paths:
53
+ loader = CSVLoader(file_path=file_path)
54
+ docs = loader.load()
55
+ all_docs.extend(docs) # Add the documents to the list
56
+
57
+ # Split text into chunks separated.
58
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
59
+ splits = text_splitter.split_documents(all_docs)
60
+
61
+ # Text Vectorization.
62
+ vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
63
+
64
+ # Retrieve and generate using the relevant snippets of the blog.
65
+ retriever = vectorstore.as_retriever()
66
+
67
+ ## tools and LLM
68
+
69
+ retriever_tool = Tool(
70
+ name="Retriever",
71
+ func=retriever.get_relevant_documents,
72
+ description="Use this tool to retrieve information about population, community and household expenditures."
73
+ )
74
+
75
+ # Bind the tools to the model
76
+ tools = [retriever_tool, find_place_from_text, nearby_search] # Include both tools if needed
77
+
78
+ llm = ChatOpenAI(model="gpt-4o-mini")
79
+
80
+ ## Create agents
81
+ def create_agent(llm, tools, system_message: str):
82
+ """Create an agent."""
83
+ prompt = ChatPromptTemplate.from_messages(
84
+ [
85
+ (
86
+ "system",
87
+ "You are a helpful AI assistant, collaborating with other assistants."
88
+ " Use the provided tools to progress towards answering the question."
89
+ " If you are unable to fully answer, that's OK, another assistant with different tools "
90
+ " will help where you left off. Execute what you can to make progress."
91
+ " If you or any of the other assistants have the final answer or deliverable,"
92
+ " prefix your response with FINAL ANSWER so the team knows to stop."
93
+ " You have access to the following tools: {tool_names}.\n{system_message}",
94
+ ),
95
+ MessagesPlaceholder(variable_name="messages"),
96
+ ]
97
+ )
98
+ prompt = prompt.partial(system_message=system_message)
99
+ prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))
100
+ llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])
101
+ # return prompt | llm.bind_tools(tools)
102
+ agent = prompt | llm_with_tools
103
+ return agent
104
+
105
+
106
+ ## Define state
107
+ # This defines the object that is passed between each node
108
+ # in the graph. We will create different nodes for each agent and tool
109
+ class AgentState(TypedDict):
110
+ messages: Annotated[Sequence[BaseMessage], operator.add]
111
+ sender: str
112
+
113
+
114
+ # Helper function to create a node for a given agent
115
+ def agent_node(state, agent, name):
116
+ result = agent.invoke(state)
117
+ # We convert the agent output into a format that is suitable to append to the global state
118
+ if isinstance(result, ToolMessage):
119
+ pass
120
+ else:
121
+ result = AIMessage(**result.dict(exclude={"type", "name"}), name=name)
122
+ return {
123
+ "messages": [result],
124
+ # Since we have a strict workflow, we can
125
+ # track the sender so we know who to pass to next.
126
+ "sender": name,
127
+ }
128
+
129
+
130
+ ## Define Agents Node
131
+ # Research agent and node
132
+ agent_meta = utils.load_agent_meta()
133
+ agent_name = [meta['name'] for meta in agent_meta]
134
+
135
+ agents={}
136
+ agent_nodes={}
137
+
138
+ for meta in agent_meta:
139
+ name = meta['name']
140
+ prompt = meta['prompt']
141
+
142
+ agents[name] = create_agent(
143
+ llm,
144
+ [find_place_from_text, nearby_search],
145
+ system_message=prompt,
146
+ )
147
+
148
+ agent_nodes[name] = functools.partial(agent_node, agent=agents[name], name=name)
149
+
150
+
151
+ ## Define Tool Node
152
+ from langgraph.prebuilt import ToolNode
153
+ from typing import Literal
154
+
155
+ tool_node = ToolNode(tools)
156
+
157
+ def router(state) -> Literal["call_tool", "__end__", "continue"]:
158
+ # This is the router
159
+ messages = state["messages"]
160
+ last_message = messages[-1]
161
+ if last_message.tool_calls:
162
+ # The previous agent is invoking a tool
163
+ return "call_tool"
164
+ if "FINAL ANSWER" in last_message.content:
165
+ # Any agent decided the work is done
166
+ return "__end__"
167
+ return "continue"
168
+
169
+
170
+ ## Workflow Graph
171
+ workflow = StateGraph(AgentState)
172
+
173
+ # add agent nodes
174
+ for name, node in agent_nodes.items():
175
+ workflow.add_node(name, node)
176
+
177
+ workflow.add_node("call_tool", tool_node)
178
+
179
+
180
+ for meta in agent_meta:
181
+ workflow.add_conditional_edges(
182
+ meta["name"],
183
+ router,
184
+ {"continue": meta['continue'], "call_tool": "call_tool", "__end__": END},
185
+ )
186
+
187
+ workflow.add_conditional_edges(
188
+ "call_tool",
189
+ # Each agent node updates the 'sender' field
190
+ # the tool calling node does not, meaning
191
+ # this edge will route back to the original agent
192
+ # who invoked the tool
193
+ lambda x: x["sender"],
194
+ {name: name for name in agent_name},
195
+ )
196
+ workflow.add_edge(START, "analyst")
197
+ graph = workflow.compile()
198
+
199
+ # %%
200
+ def submitUserMessage(user_input: str) -> str:
201
+ graph = workflow.compile()
202
+
203
+ events = graph.stream(
204
+ {
205
+ "messages": [
206
+ HumanMessage(
207
+ content=user_input
208
+ )
209
+ ],
210
+ },
211
+ # Maximum number of steps to take in the graph
212
+ {"recursion_limit": 15},
213
+ )
214
+
215
+ events = [e for e in events]
216
+
217
+ response = events[-1]['data collector']['messages'][0].content.replace("FINAL ANSWER: ", "")
218
+
219
+ return response
220
+
document/community type by district.csv ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564,,,,,,
2
+ จำแนกตามสำนักงานเขต และประเภทของชุมชน,,,,,,
3
+ สำนักงานเขต,ประเภทชุมชน,,,,,รวม
4
+ ,ชุมชนรูปแบบพิเศษ,ชานเมือง,เมือง,อาคารสูง,แออัด,
5
+ กลุ่มกรุงเทพกลาง,,,,,,
6
+ ดินแดง,-,-,10,5,8,23
7
+ ดุสิต,-,-,26,8,9,43
8
+ ป้อมปราบศัตรูพ่าย,-,-,4,-,10,14
9
+ พญาไท,-,-,-,9,13,22
10
+ พระนคร,-,-,15,-,5,20
11
+ ราชเทวี,-,-,-,7,18,25
12
+ วังทองหลาง,-,-,3,-,16,19
13
+ สัมพันธวงศ์,-,-,17,-,-,17
14
+ ห้วยขวาง,-,-,4,1,17,22
15
+ รวม,0,0,79,30,96,205
16
+ กลุ่มกรุงเทพใต้,,,,,,
17
+ คลองเตย,-,-,11,6,22,39
18
+ บางคอแหลม,-,-,1,1,26,28
19
+ บางนา,-,1,24,2,7,34
20
+ บางรัก,-,-,11,1,3,15
21
+ ปทุมวัน,-,-,2,3,12,17
22
+ พระโขนง,-,-,19,-,25,44
23
+ ยานนาวา,-,-,5,-,12,17
24
+ วัฒนา,-,-,2,-,14,16
25
+ สวนหลวง,-,-,43,-,2,45
26
+ สาทร,-,-,15,1,8,24
27
+ รวม,0,1,133,14,131,279
28
+ กลุ่มกรุงเทพเหนือ,,,,,,
29
+ จตุจักร,-,1,13,6,21,41
30
+ ดอนเมือง,-,1,78,-,17,96
31
+ บางเขน,-,2,56,8,7,73
32
+ บางซื่อ,-,-,2,1,47,50
33
+ ลาดพร้าว,-,2,28,2,4,36
34
+ สายไหม,-,6,68,1,4,79
35
+ หลักสี่,-,1,50,11,15,77
36
+ รวม,0,13,295,29,115,452
37
+ จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564,,,,,,
38
+ จำแนกตามสำนักงานเขต และประเภทของชุมชน (ต่อ),,,,,,
39
+ สำนักงานเขต,ประเภทชุมชน,,,,,รวม
40
+ ,ชานเมือง,เมือง,หมู่บ้านจัดสรร,อาคารสูง,แออัด,
41
+ กลุ่มกรุงเทพตะวันออก,,,,,,
42
+ คลองสามวา,-,56,28,-,-,84
43
+ คันนายาว,-,3,23,2,14,42
44
+ บางกะปิ,-,1,18,-,8,27
45
+ บึงกุ่ม,-,1,21,-,15,37
46
+ ประเวศ,-,1,38,3,3,45
47
+ มีนบุรี,-,31,30,1,1,63
48
+ ลาดกระบัง,-,30,33,1,1,65
49
+ สะพานสูง,-,21,4,-,4,29
50
+ หนองจอก,-,82,17,-,-,99
51
+ รวม,0,226,212,7,46,491
52
+ กลุ่มกรุงธนเหนือ,,,,,,
53
+ คลองสาน,-,-,5,-,29,34
54
+ จอมทอง,-,6,38,1,3,48
55
+ ตลิ่งชัน,-,27,8,-,8,43
56
+ ทวีวัฒนา,-,6,11,-,-,17
57
+ ธนบุรี,-,-,-,-,43,43
58
+ บางกอกน้อย,-,-,5,1,31,37
59
+ บางกอกใหญ่,-,-,2,-,28,30
60
+ บางพลัด,-,-,7,-,41,48
61
+ รวม,0,39,76,2,183,300
62
+ กลุ่มกรุงธนใต้,,,,,,
63
+ ทุ่งครุ,-,3,23,2,1,29
64
+ บางขุนเทียน,-,17,31,-,3,51
65
+ บางแค,-,5,19,-,23,47
66
+ บางบอน,-,3,7,-,2,12
67
+ ภาษีเจริญ,-,2,37,-,12,51
68
+ ราษฎร์บูรณะ,-,-,2,-,26,28
69
+ หนองแขม,-,42,26,1,2,71
70
+ รวม,0,72,145,3,69,289
71
+ รวมทั้งหมด,0,351,940,85,640,2016
72
+ แหล่งข้อมูล : สำนักงานการพัฒนาชุมชน สำนักพัฒนาสังคม กรุงเทพมหานคร (ข้อมูล ณ วันที่ 25 เม.ย. 65),,,,,,
73
+ หมายเหตุ : ระเบียบกรุงเทพมหานครว่าด้วยชุมชนและกรรมการชุมชน พ.ศ. 2564 ชุมชนแบ่งออกเป็น 5 ประเภท ได้แก่,,,,,,
74
+ หมายเหตุ : ชุมชนแออัด / ชุมชนเมือง / ชุมชนชาญเมือง / ชุมชนอาคารสูง / ชุมชนรูปแบบพิเศษ,,,,,,
document/thailand household expenditures by category.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "เปรียบเทียบร้อยละของค่าใช้จ่ายเฉลี่ยต่อเดือนของครัวเรือน จำแนกตามประเภทค่าใช้จ่าย
2
+ พ.ศ. 2558 - 2564",,,,,,,
3
+ ,,,,,,,
4
+ ประเภทค่าใช้จ่าย*,ร้อยละ,,,,,,
5
+ ,2558,2559,2560,2561,2562,2563,2564
6
+ อาหาร เครื่องดื่ม และยาสูบ,33.7,36.1,35,34.8,33.9,35.6,35.5
7
+ ค่าที่อยู่อาศัยและเครื่องใช้ภายในบ้าน,20.4,19.7,20,19.8,21,20.6,21.4
8
+ การเดินทางและยานพาหนะ,18.3,17.4,17,17.7,17.3,17.2,16
9
+ ใช้ส่วนบุคคล/เครื่องนุ่งห่ม/รองเท้า,6,5.2,5,5,5.9,4.7,4.9
10
+ การสื่อสาร,3.3,3.4,3,3.9,3.7,4,4
11
+ การบันเทิง/การจัดงานพิธี,1.4,1.2,1,1.1,0.9,1,1
12
+ การศึกษา,1.7,1.7,2,1.7,1.5,1.5,1.6
13
+ เวชภัณฑ์/ค่ารักษาพยาบาล,1.1,1.4,2,1.5,1.3,1.5,1.7
14
+ กิจกรรมทางศาสนา,1.2,1,1,1.1,1,0.9,0.9
15
+ "ค่าใช้จ่ายที่ไม่เกี่ยวกับการอุปโภคบริโภค เช่น ค่าภาษี ของขวัญ
16
+ เบี้ยประกันภัย ซื้อสลากกินแบง/หวย ดอกเบี้ย",12.9,12.9,##,13.4,13.5,13,13
document/thailand household expenditures by province.csv ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ค่าใช้จ่ายเฉลี่ยต่อเดือนของครัวเรือน เป็นรายภาค และจังหวัด พ.ศ. 2555 - 2564,,,,,,,,,,,
2
+ หน่วย: บาท,,,,,,,,,,,
3
+ ภาค,จังหวัด,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564
4
+ ทั่วราชอาณาจักร,ทั่วราชอาณาจักร,"18,766.00","19,061.00","20,892.00","21,157.00","21,144.00","21,436.50","21,346.00","20,742.12","21,329.00","21,616.00"
5
+ กรุงเทพมหานคร และ 3 จังหวัด,กรุงเทพมหานคร และ 3 จังหวัด,"31,971.00","32,425.00","31,606.00","30,882.00","32,091.00","33,126.02","33,408.00","30,778.10","31,142.00","31,382.00"
6
+ ,กรุงเทพมหานคร,"33,956.98","35,023.70","34,425.64","33,085.70","35,101.40","35,350.70","34,127.44","31,753.04","32,052.03","31,866.68"
7
+ ,สมุทรปราการ,"25,860.88","26,192.90","22,747.21","22,331.80","24,353.97","24,354.72","23,231.71","21,423.43","23,850.82","27,484.76"
8
+ ,นนทบุรี,"28,731.23","26,946.60","30,812.06","31,381.00","28,828.37","33,313.04","33,808.98","32,189.09","33,042.31","33,995.57"
9
+ ,ปทุมธานี,"30,668.81","29,514.00","30,197.07","29,770.00","31,271.04","33,604.46","43,300.51","37,086.11","33,823.84","31,639.92"
10
+ ภาคกลาง,ภาคกลาง,"19,762.00","19,728.00","21,144.00","21,055.00","20,493.00","21,119.75","21,168.00","20,644.55","21,771.00","22,332.00"
11
+ ,พระนครศรีอยุธยา,"25,215.89","20,493.70","20,409.63","22,218.10","23,095.32","23,780.19","22,790.08","24,439.76","23,391.26","25,326.92"
12
+ ,อ่างทอง,"21,273.24","21,182.50","19,633.96","17,573.60","20,371.91","17,162.48","17,294.67","17,010.98","17,726.59","17,020.79"
13
+ ,ลพบุรี,"17,356.96","15,944.80","14,910.71","17,968.90","15,875.50","16,012.15","17,016.83","16,829.71","19,180.09","21,324.54"
14
+ ,สิงห์บุรี,"23,474.62","22,118.20","19,631.55","22,136.80","19,381.46","20,262.78","19,773.04","19,884.51","20,303.62","20,146.07"
15
+ ,ชัยนาท,"15,535.57","17,766.60","17,090.91","17,163.10","17,495.47","16,162.12","17,187.28","15,762.99","19,835.74","18,292.27"
16
+ ,สระบุรี,"21,412.68","22,765.00","22,811.16","23,017.10","23,964.34","26,635.10","27,581.38","26,007.12","26,045.40","26,503.14"
17
+ ,ชลบุรี,"25,499.01","24,934.20","25,704.10","24,182.00","24,257.06","24,572.50","25,322.87","25,683.70","24,878.44","28,001.46"
18
+ ,ระยอง,"21,023.90","21,872.50","23,303.13","24,433.50","21,024.65","22,698.79","19,409.81","20,806.85","21,451.36","22,365.56"
19
+ ,จันทบุรี,"19,594.74","17,597.30","20,649.74","23,350.80","22,790.42","20,619.92","20,922.15","19,812.57","23,300.20","22,347.34"
20
+ ,ตราด,"15,662.72","16,706.30","18,126.65","18,989.00","18,913.56","20,404.69","20,198.98","18,883.88","19,563.16","19,796.09"
21
+ ,ฉะเชิงเทรา,"23,079.51","26,070.70","23,342.12","21,782.60","21,674.11","21,437.44","19,070.81","17,035.88","18,791.18","18,968.49"
22
+ ,ปราจีนบุรี,"19,733.75","18,314.70","20,789.55","20,994.50","18,156.85","19,268.28","20,782.66","21,677.72","22,470.73","23,318.79"
23
+ ,นครนายก,"16,459.52","17,696.90","17,482.59","18,153.50","17,877.62","18,601.09","19,152.88","19,717.14","20,609.12","21,775.45"
24
+ ,สระแก้ว,"19,531.06","18,571.10","20,227.36","20,576.70","18,413.18","17,609.53","17,543.55","15,827.78","16,939.41","17,347.26"
25
+ ,ราชบุรี,"16,760.17","17,253.20","17,514.63","15,083.90","19,341.33","25,367.36","22,833.63","20,122.78","22,383.58","22,171.08"
26
+ ,กาญจนบุรี,"17,220.34","17,301.10","17,186.70","15,764.80","18,221.02","18,001.28","20,738.75","18,717.16","21,385.86","22,346.86"
27
+ ,สุพรรณบุรี,"12,392.88","13,450.40","14,868.54","14,146.10","13,893.31","15,919.02","14,244.50","14,557.73","14,442.09","14,776.76"
28
+ ,นครปฐม,"20,409.22","21,305.40","25,876.36","26,025.20","22,498.78","20,711.53","24,962.41","24,254.93","24,502.62","24,003.25"
29
+ ,สมุทรสาคร,"18,164.89","18,565.40","22,559.61","22,876.70","21,644.56","20,806.50","20,573.08","19,664.33","23,993.17","22,694.64"
30
+ ,สมุทรสงคราม,"16,953.24","16,557.80","19,510.69","18,801.00","16,909.17","20,863.95","18,755.08","19,028.26","20,424.16","19,239.86"
31
+ ,เพชรบุรี,"19,140.50","18,469.40","20,170.13","22,154.20","20,756.34","23,061.47","20,207.39","20,789.27","22,976.64","22,242.70"
32
+ ,ประจวบคีรีขันธ์,"21,452.15","22,393.00","25,914.62","21,267.70","20,184.45","21,318.44","23,513.15","19,350.27","21,821.30","20,844.56"
33
+ ภาคเหนือ,ภาคเหนือ,"14,010.00","14,066.00","15,286.00","15,268.00","15,769.00","15,329.12","15,240.00","15,644.02","16,490.00","16,441.00"
34
+ ,เชียงใหม่,"14,585.38","11,703.50","13,731.68","11,863.80","14,455.34","15,206.77","15,468.58","15,659.49","18,887.48","17,572.74"
35
+ ,ลำพูน,"17,897.52","20,380.70","20,062.78","20,549.90","20,979.39","20,055.79","18,604.05","19,115.37","20,189.87","19,929.95"
36
+ ,ลำปาง,"15,193.60","15,101.90","16,020.52","15,314.80","16,883.51","16,641.56","16,645.81","17,612.59","16,375.99","15,948.34"
37
+ ,อุตรดิตถ์,"12,015.66","13,550.20","15,219.76","15,814.50","16,370.35","14,799.30","14,666.28","16,355.07","14,544.46","16,530.72"
38
+ ,แพร่,"13,958.50","15,478.60","15,454.61","16,449.20","15,617.89","14,474.40","14,843.86","15,802.50","14,822.23","15,052.87"
39
+ ,น่าน,"13,622.97","14,078.30","13,919.72","14,165.20","14,358.93","14,298.53","15,176.17","15,269.79","16,122.92","16,649.76"
40
+ ,พะเยา,"11,483.66","11,245.10","11,835.15","13,782.70","13,100.65","12,293.42","12,751.80","12,915.79","13,217.25","12,552.05"
41
+ ,เชียงราย,"11,390.92","11,068.20","11,230.83","12,074.60","12,877.74","10,440.72","11,213.48","12,635.31","11,532.11","12,907.69"
42
+ ,แม่ฮ่องสอน,"7,878.90","7,405.10","9,686.13","12,131.40","11,859.40","12,243.25","11,536.21","11,242.74","11,606.13","12,214.19"
43
+ ,นครสวรรค์,"13,932.97","14,268.40","16,192.62","17,128.40","16,076.25","16,045.18","14,794.13","16,001.51","16,568.68","16,151.74"
44
+ ,อุทัยธานี,"13,852.50","13,082.60","15,689.50","16,402.00","17,806.22","16,862.10","15,746.55","15,763.29","14,270.11","15,416.63"
45
+ ,กำแพงเพชร,"15,005.63","16,359.50","17,880.00","17,370.80","17,271.87","16,383.96","16,147.13","15,751.72","18,559.99","19,496.88"
46
+ ,ตาก,"12,656.51","13,148.80","13,918.75","15,175.60","14,140.54","13,112.67","12,527.72","13,910.20","14,719.82","16,506.34"
47
+ ,สุโขทัย,"14,320.57","15,311.50","14,905.00","17,246.40","16,101.76","14,968.09","14,548.42","15,166.31","14,097.73","14,033.63"
48
+ ,พิษณุโลก,"17,458.55","19,927.90","19,002.98","17,649.60","17,731.79","19,338.22","18,048.53","18,124.65","19,387.40","19,300.60"
49
+ ,พิจิตร,"15,483.60","14,791.00","18,687.19","16,854.30","17,734.08","15,868.65","16,601.52","15,752.25","16,327.40","17,398.17"
50
+ ,เพชรบูรณ์,"13,879.27","13,788.90","15,598.93","16,140.80","16,444.81","16,696.21","17,528.49","16,222.51","19,724.79","17,743.26"
51
+ ภาคตะวันออกเฉียงเหนือ,ภาคตะวันออกเฉียงเหนือ,"14,277.00","15,092.00","16,284.00","17,032.00","16,276.00","16,513.01","16,343.00","16,552.64","16,810.00","16,869.00"
52
+ ,นครราชสีมา,"15,396.63","15,618.20","17,771.26","18,645.40","18,488.78","17,840.83","18,195.67","16,888.61","17,939.45","16,289.06"
53
+ ,บุรีรัมย์,"12,938.87","14,342.90","13,951.72","16,086.50","13,053.88","12,686.46","14,580.11","13,502.86","15,289.74","18,834.94"
54
+ ,สุรินทร์,"14,746.46","18,583.80","17,068.78","18,536.90","16,289.26","16,306.82","18,208.86","18,003.99","18,999.16","20,018.13"
55
+ ,ศรีสะเกษ,"12,837.46","13,367.50","14,609.03","18,124.40","14,129.29","15,838.40","13,798.05","14,676.47","14,268.78","13,443.72"
56
+ ,อุบลราชธานี,"14,754.66","13,586.50","15,477.57","13,848.20","13,997.21","16,045.66","14,769.70","13,496.02","15,135.26","15,751.71"
57
+ ,ยโสธร,"12,109.63","12,549.10","15,867.23","14,453.20","15,979.68","13,554.46","12,748.09","13,591.40","12,907.04","14,391.11"
58
+ ,ชัยภูมิ,"16,090.09","15,022.10","17,162.94","16,332.10","17,704.80","17,237.63","15,591.56","15,402.15","15,930.45","16,177.83"
59
+ ,อำนาจเจริญ,"14,240.34","14,161.80","17,528.52","17,029.20","15,550.34","16,575.21","14,612.97","16,693.42","15,184.77","17,206.77"
60
+ ,บึงกาฬ,"17,098.45","20,282.50","20,073.17","23,696.60","22,238.65","19,661.96","18,347.12","22,225.38","21,421.45","19,539.55"
61
+ ,หนองบัวลำภู,"13,355.66","13,663.70","17,622.34","18,760.70","21,456.95","19,043.40","17,295.58","16,007.80","21,173.43","17,840.51"
62
+ ,ขอนแก่น,"12,677.47","13,914.70","15,700.07","16,880.00","15,091.55","16,544.29","17,589.11","17,662.59","17,320.99","15,054.60"
63
+ ,อุดรธานี,"18,346.97","21,438.90","21,619.51","22,535.10","19,103.20","20,015.07","18,696.16","22,576.64","16,692.86","19,747.02"
64
+ ,เลย,"14,313.80","14,916.20","15,789.06","16,231.70","18,625.25","19,102.70","21,055.18","19,220.31","21,015.45","21,012.91"
65
+ ,หนองคาย,"15,011.95","15,670.30","18,360.73","19,277.70","16,532.30","18,815.11","18,129.21","19,104.40","18,943.82","17,903.20"
66
+ ,มหาสารคาม,"14,714.21","15,506.20","14,253.58","14,654.20","18,430.56","17,664.79","17,286.87","18,308.83","19,027.99","20,000.26"
67
+ ,ร้อยเอ็ด,"16,708.42","15,347.50","17,761.85","17,755.50","16,379.71","16,770.21","15,685.74","17,320.40","15,738.71","15,606.70"
68
+ ,กาฬสินธุ์,"11,150.95","12,445.20","12,178.38","12,746.60","11,970.07","11,541.28","11,857.86","13,076.14","13,544.26","14,398.96"
69
+ ,สกลนคร,"11,232.68","13,021.30","13,474.68","14,549.00","15,268.78","15,159.10","15,130.25","14,840.92","16,318.73","16,757.96"
70
+ ,นครพนม,"10,826.03","11,447.10","12,562.25","13,973.10","13,501.08","13,324.50","14,416.97","16,233.73","16,187.32","15,604.73"
71
+ ,มุกดาหาร,"13,015.83","13,146.40","15,202.76","17,767.00","17,021.91","18,368.81","15,761.48","14,901.97","17,546.03","17,970.94"
72
+ ภาคใต้,ภาคใต้,"20,645.00","20,372.00","21,016.00","21,293.00","21,314.00","21,381.41","20,660.00","19,599.58","19,641.00","20,628.00"
73
+ ,นครศรีธรรมราช,"22,102.20","19,364.20","20,661.17","19,828.70","21,011.81","20,051.18","21,135.24","19,170.64","18,940.91","19,574.79"
74
+ ,กระบี่,"19,536.10","20,835.70","32,836.66","28,403.20","24,823.83","24,925.19","24,326.12","23,275.81","26,631.25","24,233.52"
75
+ ,พังงา,"19,208.84","17,899.60","21,719.34","20,716.90","20,255.66","19,958.35","20,703.32","17,998.67","19,292.16","21,200.60"
76
+ ,ภูเก็ต,"27,151.22","25,337.50","28,111.37","27,435.40","30,238.67","32,853.12","30,992.50","32,762.88","31,346.83","32,944.35"
77
+ ,สุราษฎร์ธานี,"27,927.27","28,118.60","26,410.48","26,165.30","24,743.15","24,186.29","25,212.15","23,489.94","23,307.61","25,539.36"
78
+ ,ระนอง,"20,343.22","22,586.60","18,246.94","18,616.90","18,511.33","18,496.89","17,130.73","17,186.76","17,945.54","17,916.32"
79
+ ,ชุมพร,"23,952.43","22,552.30","23,985.40","24,541.80","22,933.28","24,143.88","20,692.85","20,193.54","21,040.06","21,500.62"
80
+ ,สงขลา,"21,382.60","21,669.80","21,744.26","23,617.30","23,466.01","23,693.16","21,127.92","18,017.38","18,136.34","19,655.98"
81
+ ,สตูล,"20,189.97","22,714.70","19,715.22","19,591.20","20,732.92","18,810.72","19,335.78","18,589.49","20,127.52","20,845.48"
82
+ ,ตรัง,"19,617.83","20,922.30","17,107.10","19,794.90","18,599.29","18,768.44","18,648.61","20,143.01","17,904.52","18,296.68"
83
+ ,พัทลุง,"18,404.19","16,635.70","18,514.03","17,143.30","18,420.66","16,807.88","15,947.09","15,848.77","16,817.89","17,578.04"
84
+ ,ปัตตานี,"14,119.15","16,668.10","14,809.34","15,341.10","17,962.18","16,948.61","15,705.85","15,948.56","14,862.49","15,392.67"
85
+ ,ยะลา,"12,883.10","12,521.70","12,370.15","13,453.90","14,122.15","15,483.63","13,301.01","13,595.63","14,141.04","14,927.64"
86
+ ,นราธิวาส,"12,686.17","13,727.80","11,985.95","13,717.40","13,065.80","14,980.10","15,630.54","14,572.65","15,126.26","17,088.68"
document/thailand population data by district.csv ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ จำนวนชุมชน ประชากร ครอบครัว และหลังคาเรือนของชุมชนในกรุงเทพมหานคร พ.ศ. 2564,,,,,,,
2
+ ลำดับ,เขต,ชุมชน (ชุมชน),ประชากร (คน),ครอบครัว (ครอบครัว),หลังคาเรือน (หลัง),Indicator*,*ค่าใช้จ่ายในการเข้าถึงชุมชนมีประสิทธิภาพมากที่สุด
3
+ 25,บางกอกน้อย,37,"104,566","24,109","17,076",2826.108108,
4
+ 24,คลองเตย,39,"84,780","21,784","19,499",2173.846154,
5
+ 43,ปทุมวัน,17,"28,031","8,196","5,557",1648.882353,
6
+ 33,บางคอแหลม,28,"38,148","10,896","7,230",1362.428571,
7
+ 8,ลาดกระบัง,65,"88,325","25,624","24,489",1358.846154,
8
+ 37,สาทร,24,"32,077","8,994","5,411",1336.541667,
9
+ 29,บางนา,34,"42,890","15,132","17,210",1261.470588,
10
+ 5,หลักสี่,77,"96,430","19,341","17,867",1252.337662,
11
+ 9,มีนบุรี,63,"76,028","21,436","20,055",1206.793651,
12
+ 10,บางขุนเทียน,51,"60,038","13,802","13,443",1177.215686,
13
+ 31,สะพานสูง,29,"32,000","9,768","8,513",1103.448276,
14
+ 4,สายไหม,79,"86,847","25,419","24,903",1099.329114,
15
+ 19,ธนบุรี,43,"46,376","16,944","14,929",1078.511628,
16
+ 35,บางกะปิ,27,"28,835","8,700","8,283",1067.962963,
17
+ 16,สวนหลวง,45,"47,408","9,506","8,558",1053.511111,
18
+ 39,พญาไท,22,"22,958","6,364","5,982",1043.545455,
19
+ 44,ทวีวัฒนา,17,"17,506","5,140","4,807",1029.764706,
20
+ 42,วังทองหลาง,19,"19,123","5,570","4,694",1006.473684,
21
+ 17,ประเวศ,45,"43,855","10,324","10,304",974.5555556,
22
+ 28,คลองสาน,34,"33,024","10,219","7,339",971.2941176,
23
+ 27,ลาดพร้าว,36,"34,435","13,194","11,931",956.5277778,
24
+ 6,บางเขน,73,"69,281","22,503","22,396",949.0547945,
25
+ 48,บางรัก,15,"14,165","4,452","3,213",944.3333333,
26
+ 26,บึงกุ่ม,37,"34,245","10,702","10,365",925.5405405,
27
+ 36,ราชเทวี,25,"23,071","8,198","5,942",922.84,
28
+ 11,ภาษีเจริญ,51,"46,644","10,807","9,552",914.5882353,
29
+ 14,จอมทอง,48,"43,767","12,111","9,125",911.8125,
30
+ 13,บางพลัด,48,"42,870","13,392","9,530",893.125,
31
+ 38,ดินแดง,23,"19,950","12,049","6,184",867.3913043,
32
+ 47,วัฒนา,16,"13,575","5,378","3,625",848.4375,
33
+ 2,ดอนเมือง,96,"80,879","26,030","26,073",842.4895833,
34
+ 40,ห้วยขวาง,22,"18,528","4,481","3,805",842.1818182,
35
+ 15,บางแค,47,"38,987","9,647","7,687",829.5106383,
36
+ 32,ทุ่งครุ,29,"23,593","8,536","5,384",813.5517241,
37
+ 45,ยานนาวา,17,"13,820","3,476","2,995",812.9411765,
38
+ 7,หนองแขม,71,"55,310","17,811","16,741",779.0140845,
39
+ 20,ดุสิต,43,"33,416","12,031","8,638",777.1162791,
40
+ 3,คลองสามวา,84,"64,063","19,208","17,445",762.6547619,
41
+ 22,คันนายาว,42,"32,001","10,362","9,776",761.9285714,
42
+ 1,หนองจอก,99,"74,604","19,549","19,630",753.5757576,
43
+ 12,บางซื่อ,50,"37,670","12,130","7,814",753.4,
44
+ 41,พระนคร,20,"14,726","5,758","5,364",736.3,
45
+ 23,จตุจักร,41,"28,540","10,067","9,109",696.097561,
46
+ 21,ตลิ่งชัน,43,"29,734","9,171","7,372",691.4883721,
47
+ 49,ป้อมปราบศัตรูพ่าย,14,"8,332","2,898","2,841",595.1428571,
48
+ 18,พระโขนง,44,"26,030","7,728","5,998",591.5909091,
49
+ 34,ราษฎร์บูรณะ,28,"16,430","6,088","4,097",586.7857143,
50
+ 30,บางกอกใหญ่,30,"17,108","4,728","3,981",570.2666667,
51
+ 50,บางบอน,12,"6,533","2,141","2,472",544.4166667,
52
+ 46,สัมพันธวงศ์,17,"5,117","1,907","2,100",301,
53
+ รวม,,"2,016","1,996,669","583,801","507,334",,
54
+ แหล่งข้อมูล : สำนักงานการพัฒนาชุมชน สำนักพัฒนาสังคม กรุงเทพมหานคร (ข้อมูล ณ วันที่ 25 เม.ย. 65),,,,,,,
prompt.json CHANGED
@@ -1,7 +1,17 @@
1
  [
2
  {
3
- "name":"Market Analyst",
4
- "prompt": "You are a market feasibility analysis assistant specializing in gathering and analyzing data from Google Maps. Your task is to help users evaluate the market potential of a specific location by providing comprehensive insights into the business environment. When a user asks a question, you will: Respond in the same language as the query; Gather and provide data on the number of competitors in the area, the types of products or services offered by nearby businesses, and the population demographics in the area; Analyze the business environment based on this data and provide recommendations to the user; Ensure that your analysis is clear, concise, and tailored to the users needs.",
5
- "greet": ""
 
 
 
 
 
 
 
 
 
 
6
  }
7
  ]
 
1
  [
2
  {
3
+ "name": "analyst",
4
+ "prompt": "You are the Analyst responsible for understanding the user's needs and guiding the data collection process. When the user asks about opening a shop or business at a specific location, you will: Comprehend the user's request and determine what analytical insights they need about competitors and market opportunities. Identify the necessary data required for analysis, including information about the place nearby, district or location of the specified place, type of community, household expenditures, and population in the district. Clearly communicate these data requirements to the Data Collector.",
5
+ "continue": "data collector"
6
+ },
7
+ {
8
+ "name": "data collector",
9
+ "prompt": "You are the Data Collector responsible for gathering data based on the Analyst's instructions. When you receive a request from the Analyst, you will: Use the necessary tools to gather data related to the specified location, including information about nearby places, districts, community types, household expenditures, and population demographics. Ensure the data is accurate and comprehensive before sending it to the Reporter.",
10
+ "continue": "reporter"
11
+ },
12
+ {
13
+ "name": "reporter",
14
+ "prompt": "You are the Reporter responsible for compiling the data into a clear and informative report for the user. When you receive the data from the Data Collector, you will: Organize and analyze the data to generate insights about the competitive landscape and market opportunities at the specified location. Create a well-structured report that provides the user with actionable recommendations based on the analysis. Ensure the report is clear, concise, and delivered in the same language as the user's original request. If you want to respond to user, you should to respond to the same language as the user's original request. Except the FINAL_ANSWER keep it the same.",
15
+ "continue": "data collector"
16
  }
17
  ]
tools.py CHANGED
@@ -51,7 +51,7 @@ def nearby_search(input_dict: NearbySearchInput):
51
  result = gplace.nearby_search(keyword, location_coords, radius)
52
 
53
  number_results = len(result)
54
- strout = "number of results: {}\n".format(number_results)
55
  for r in result:
56
  # Use .get() to handle missing keys
57
  address = r.get('vicinity', 'N/A')
 
51
  result = gplace.nearby_search(keyword, location_coords, radius)
52
 
53
  number_results = len(result)
54
+ strout = "number of results more than {}\n".format(number_results) if number_results==20 else "number of results: {}\n".format(number_results)
55
  for r in result:
56
  # Use .get() to handle missing keys
57
  address = r.get('vicinity', 'N/A')