{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import os\n", "import utils\n", "\n", "utils.load_env()\n", "os.environ['LANGCHAIN_TRACING_V2'] = \"false\"" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from langchain.globals import set_debug, set_verbose\n", "\n", "set_verbose(True)\n", "set_debug(False)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from langchain_core.messages import HumanMessage\n", "import operator\n", "import functools\n", "\n", "# for llm model\n", "from langchain_openai import ChatOpenAI\n", "# from langchain_community.chat_models import ChatOpenAI\n", "from tools import find_place_from_text, nearby_search, nearby_dense_community, google_search\n", "from typing import Annotated, Sequence, TypedDict\n", "from langchain_core.messages import (\n", " AIMessage, \n", " HumanMessage,\n", " BaseMessage,\n", " ToolMessage\n", ")\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langgraph.graph import END, StateGraph, START\n", "\n", "## Document vector store for context\n", "from langchain_chroma import Chroma\n", "from langchain_text_splitters import RecursiveCharacterTextSplitter\n", "from langchain_community.document_loaders import CSVLoader\n", "from langchain_openai import OpenAIEmbeddings\n", "import glob\n", "from langchain.tools.retriever import create_retriever_tool\n", "\n", "def format_docs(docs):\n", " return \"\\n\\n\".join(doc.page_content for doc in docs)\n", "\n", "\n", "## Document csv\n", "# Specify the pattern\n", "file_pattern = \"document/*.csv\"\n", "file_paths = tuple(glob.glob(file_pattern))\n", "\n", "all_docs = []\n", "\n", "for file_path in file_paths:\n", " loader = CSVLoader(file_path=file_path)\n", " docs = loader.load()\n", " all_docs.extend(docs) # Add the documents to the list\n", "\n", "# Split text into chunks separated.\n", "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)\n", "splits = text_splitter.split_documents(all_docs)\n", "\n", "# Text Vectorization.\n", "vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())\n", "\n", "# Retrieve and generate using the relevant snippets of the blog.\n", "retriever = vectorstore.as_retriever()\n", "\n", "\n", "## tools and LLM\n", "retriever_tool = create_retriever_tool(\n", " retriever,\n", " \"search_population_community_household_expenditures_data\",\n", " \"Use this tool to retrieve information about population, community and household expenditures. by searching distinct or province\"\n", ")\n", "\n", "# Bind the tools to the model\n", "tools = [retriever_tool, find_place_from_text, nearby_search, nearby_dense_community, google_search] # Include both tools if needed\n", "# tools = [find_place_from_text, nearby_search]\n", "\n", "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0.0)\n", "\n", "## Create agents\n", "def create_agent(llm, tools, system_message: str):\n", " \"\"\"Create an agent.\"\"\"\n", " prompt = ChatPromptTemplate.from_messages(\n", " [\n", " (\n", " \"system\",\n", " \"You are a helpful AI assistant, collaborating with other assistants.\"\n", " \" Use the provided tools to progress towards answering the question.\"\n", " \" If you are unable to fully answer, that's OK, another assistant with different tools \"\n", " \" will help where you left off. Execute what you can to make progress.\"\n", " \" If you or any of the other assistants have the final answer or deliverable,\"\n", " \" \"\n", " \" You have access to the following tools: {tool_names}.\\n{system_message}\",\n", " ),\n", " MessagesPlaceholder(variable_name=\"messages\"),\n", " ]\n", " )\n", " prompt = prompt.partial(system_message=system_message)\n", " prompt = prompt.partial(tool_names=\", \".join([tool.name for tool in tools]))\n", " #llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])\n", " return prompt | llm.bind_tools(tools)\n", " #agent = prompt | llm_with_tools\n", " #return agent\n", "\n", "\n", "## Define state\n", "# This defines the object that is passed between each node\n", "# in the graph. We will create different nodes for each agent and tool\n", "class AgentState(TypedDict):\n", " messages: Annotated[Sequence[BaseMessage], operator.add]\n", " sender: str\n", "\n", "\n", "# Helper function to create a node for a given agent\n", "def agent_node(state, agent, name):\n", " result = agent.invoke(state)\n", " # We convert the agent output into a format that is suitable to append to the global state\n", " if isinstance(result, ToolMessage):\n", " pass\n", " else:\n", " result = AIMessage(**result.dict(exclude={\"type\", \"name\"}), name=name)\n", " return {\n", " \"messages\": [result],\n", " # Since we have a strict workflow, we can\n", " # track the sender so we know who to pass to next.\n", " \"sender\": name,\n", " }\n", "\n", "\n", "## Define Agents Node\n", "# Research agent and node\n", "from prompt import agent_meta\n", "agent_name = [meta['name'] for meta in agent_meta]\n", "\n", "agents={}\n", "agent_nodes={}\n", "\n", "for meta in agent_meta:\n", " name = meta['name']\n", " prompt = meta['prompt']\n", " \n", " agents[name] = create_agent(\n", " llm,\n", " tools,\n", " system_message=prompt,\n", " )\n", " \n", " agent_nodes[name] = functools.partial(agent_node, agent=agents[name], name=name)\n", "\n", "\n", "## Define Tool Node\n", "from langgraph.prebuilt import ToolNode\n", "from typing import Literal\n", "\n", "tool_node = ToolNode(tools)\n", "\n", "def router(state) -> Literal[\"call_tool\", \"__end__\", \"continue\"]:\n", " # This is the router\n", " messages = state[\"messages\"]\n", " last_message = messages[-1]\n", " if \"continue\" in last_message.content:\n", " return \"continue\"\n", " if last_message.tool_calls:\n", " # The previous agent is invoking a tool\n", " return \"call_tool\"\n", " if \"FINAL ANSWER\" in last_message.content:\n", " # Any agent decided the work is done\n", " return \"__end__\"\n", " else:\n", " return \"continue\"\n", "\n", "\n", "\n", "## Workflow Graph\n", "workflow = StateGraph(AgentState)\n", "\n", "# add agent nodes\n", "for name, node in agent_nodes.items():\n", " workflow.add_node(name, node)\n", " \n", "workflow.add_node(\"call_tool\", tool_node)\n", "\n", "\n", "workflow.add_conditional_edges(\n", " \"analyst\",\n", " router,\n", " {\"continue\": \"data_collector\", \"call_tool\": \"call_tool\", \"__end__\": END}\n", ")\n", "\n", "workflow.add_conditional_edges(\n", " \"data_collector\",\n", " router,\n", " {\"call_tool\": \"call_tool\", \"continue\": \"reporter\", \"__end__\": END}\n", ")\n", "\n", "workflow.add_conditional_edges(\n", " \"reporter\",\n", " router,\n", " {\"continue\": \"data_collector\", \"call_tool\": \"call_tool\", \"__end__\": END}\n", ")\n", "\n", "workflow.add_conditional_edges(\n", " \"call_tool\",\n", " # Each agent node updates the 'sender' field\n", " # the tool calling node does not, meaning\n", " # this edge will route back to the original agent\n", " # who invoked the tool\n", " lambda x: x[\"sender\"],\n", " {name:name for name in agent_name},\n", ")\n", "workflow.add_edge(START, \"analyst\")\n", "graph = workflow.compile()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# from IPython.display import Image, display\n", "\n", "# try:\n", "# display(Image(graph.get_graph(xray=True).draw_mermaid_png()))\n", "# except Exception:\n", "# # This requires some extra dependencies and is optional\n", "# pass" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: analyst\n", "Tool Calls:\n", " nearby_search (call_gr8ntGLQtAKTgxfHiP3BQqLo)\n", " Call ID: call_gr8ntGLQtAKTgxfHiP3BQqLo\n", " Args:\n", " input_dict: {'keyword': 'coffee shop', 'location_name': 'เซ็นทรัลเวิลด์', 'radius': 1000, 'place_type': 'cafe'}\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: nearby_search\n", "\n", "number of results: 21\n", "\n", " **BEANS Coffee Roaster Paragon**\n", "\n", " address: 991/1 Rama I Rd, Pathum Wan\n", "\n", " rating: 5\n", "\n", "\n", " \n", " **Fellas.coffee @soi tonson**\n", "\n", " address: ตรงป้อมยามเก่า ตึกปิยะเพลส 34/1 Soi Ton Son, ลุมพินี Pathum Wan\n", "\n", " rating: 4.9\n", "\n", "\n", " \n", " **Earthy Roaster (Specialty Coffee)**\n", "\n", " address: 994 Makkasan, Ratchathewi\n", "\n", " rating: 4.8\n", "\n", "\n", " \n", " **Salotto Coffee**\n", "\n", " address: 813/8 Phetchaburi Rd, Thanon Phaya Thai, Ratchathewi\n", "\n", " rating: 5\n", "\n", "\n", " \n", " **The Basic Coffee BKK**\n", "\n", " address: ตึก Gaysorn Amarin (ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n", "\n", " rating: 4.7\n", "\n", "\n", " \n", " **Bullet Thai Craft Beer**\n", "\n", " address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n", "\n", " rating: 5\n", "\n", "\n", " \n", " **TABLA Craft Coffee**\n", "\n", " address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", "\n", " rating: 4.6\n", "\n", "\n", " \n", " **Sip 'n Drip**\n", "\n", " address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n", "\n", " rating: 4.9\n", "\n", "\n", " \n", " **RISE COFFEE - Flagship Store**\n", "\n", " address: 888 อาคารมหาทุนพลาซ่า ชั้น 1 ยูนิต 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", "\n", " rating: 4.8\n", "\n", "\n", " \n", " **You Drink Coffee**\n", "\n", " address: 89, 25 Witthayu Rd, Lumphini, Pathum Wan\n", "\n", " rating: 4.5\n", "\n", "\n", " \n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: analyst\n", "\n", "Here are some coffee shops near Central World:\n", "\n", "1. **BEANS Coffee Roaster Paragon**\n", " - Address: 991/1 Rama I Rd, Pathum Wan\n", " - Rating: 5\n", "\n", "2. **Fellas.coffee @soi tonson**\n", " - Address: ตรงป้อมยามเก่า ตึกปิยะเพลส 34/1 Soi Ton Son, ลุมพินี Pathum Wan\n", " - Rating: 4.9\n", "\n", "3. **Earthy Roaster (Specialty Coffee)**\n", " - Address: 994 Makkasan, Ratchathewi\n", " - Rating: 4.8\n", "\n", "4. **Salotto Coffee**\n", " - Address: 813/8 Phetchaburi Rd, Thanon Phaya Thai, Ratchathewi\n", " - Rating: 5\n", "\n", "5. **The Basic Coffee BKK**\n", " - Address: ตึก Gaysorn Amarin (ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan\n", " - Rating: 4.7\n", "\n", "6. **Bullet Thai Craft Beer**\n", " - Address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n", " - Rating: 5\n", "\n", "7. **TABLA Craft Coffee**\n", " - Address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", " - Rating: 4.6\n", "\n", "8. **Sip 'n Drip**\n", " - Address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n", " - Rating: 4.9\n", "\n", "9. **RISE COFFEE - Flagship Store**\n", " - Address: 888 อาคารมหาทุนพลาซ่า ชั้น 1 ยูนิต 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", " - Rating: 4.8\n", "\n", "10. **You Drink Coffee**\n", " - Address: 89, 25 Witthayu Rd, Lumphini, Pathum Wan\n", " - Rating: 4.5\n", "\n", "Feel free to ask if you need more information!\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: data_collector\n", "Tool Calls:\n", " search_population_community_household_expenditures_data (call_NsDXK0N7ayKUJt96mF1LTjkz)\n", " Call ID: call_NsDXK0N7ayKUJt96mF1LTjkz\n", " Args:\n", " query: Pathum Wan\n", " nearby_dense_community (call_BfU6f63aDIkKGeoueIePih2s)\n", " Call ID: call_BfU6f63aDIkKGeoueIePih2s\n", " Args:\n", " input_dict: {'location_name': 'เซ็นทรัลเวิลด์', 'radius': 1000}\n", " google_search (call_3k320xdy3pvUCOWIOZ8u4Zm6)\n", " Call ID: call_3k320xdy3pvUCOWIOZ8u4Zm6\n", " Args:\n", " input_dict: {'keyword': 'the pricing of BEANS Coffee Roaster Paragon'}\n", " google_search (call_Cw4HEobCHE2DSnIwTLkxdUV1)\n", " Call ID: call_Cw4HEobCHE2DSnIwTLkxdUV1\n", " Args:\n", " input_dict: {'keyword': 'the pricing of Fellas.coffee @soi tonson'}\n", " google_search (call_EFMXeLL055V0Bb2C1xoCVUEv)\n", " Call ID: call_EFMXeLL055V0Bb2C1xoCVUEv\n", " Args:\n", " input_dict: {'keyword': 'the pricing of Earthy Roaster (Specialty Coffee)'}\n", " google_search (call_1kxslUUACnK9TEdgxDd5cRWC)\n", " Call ID: call_1kxslUUACnK9TEdgxDd5cRWC\n", " Args:\n", " input_dict: {'keyword': 'the pricing of Salotto Coffee'}\n", " google_search (call_7f3k9XrFKROWFHi1lMayTlHv)\n", " Call ID: call_7f3k9XrFKROWFHi1lMayTlHv\n", " Args:\n", " input_dict: {'keyword': 'the pricing of The Basic Coffee BKK'}\n", " google_search (call_6h6zFHHf46w7Jyx7uScPc2z8)\n", " Call ID: call_6h6zFHHf46w7Jyx7uScPc2z8\n", " Args:\n", " input_dict: {'keyword': 'the pricing of Bullet Thai Craft Beer'}\n", " google_search (call_vlkhTPmnxUII86c3c0GnSmev)\n", " Call ID: call_vlkhTPmnxUII86c3c0GnSmev\n", " Args:\n", " input_dict: {'keyword': 'the pricing of TABLA Craft Coffee'}\n", " google_search (call_aUFPti5fSmgfuLbk6nHT62Dj)\n", " Call ID: call_aUFPti5fSmgfuLbk6nHT62Dj\n", " Args:\n", " input_dict: {'keyword': \"the pricing of Sip 'n Drip\"}\n", " google_search (call_EP0tmwz21mqabclfhYsr6vvO)\n", " Call ID: call_EP0tmwz21mqabclfhYsr6vvO\n", " Args:\n", " input_dict: {'keyword': 'the pricing of RISE COFFEE - Flagship Store'}\n", " google_search (call_VLPEsa2aMI1CYeOyDDdbITtw)\n", " Call ID: call_VLPEsa2aMI1CYeOyDDdbITtw\n", " Args:\n", " input_dict: {'keyword': 'the pricing of You Drink Coffee'}\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: search_population_community_household_expenditures_data\n", "\n", "จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564: สวนหลวง\n", ": 45\n", "\n", "จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564: คลองสามวา\n", ": 84\n", "\n", "จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564: คลองเตย\n", ": 39\n", "\n", "จำนวนชุมชนประเภทต่าง ๆ ในกรุงเทพมหานคร พ.ศ. 2564: คลองสาน\n", ": 34\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: data_collector\n", "\n", "Here is the gathered data regarding coffee shops near Central World, along with population and community information for Pathum Wan:\n", "\n", "### Coffee Shops and Pricing\n", "1. **BEANS Coffee Roaster Paragon**\n", " - Address: 991/1 Rama I Rd, Pathum Wan\n", " - Rating: 5\n", " - Pricing: Approximately 200-300 THB for a basic drink.\n", "\n", "2. **Fellas.coffee @soi tonson**\n", " - Address: ตรงป้อมยามเก่า ตึกปิยะเพลส 34/1 Soi Ton Son, ลุมพินี Pathum Wan\n", " - Rating: 4.9\n", " - Pricing: Around 150-250 THB for coffee.\n", "\n", "3. **Earthy Roaster (Specialty Coffee)**\n", " - Address: 994 Makkasan, Ratchathewi\n", " - Rating: 4.8\n", " - Pricing: 180-280 THB for specialty coffee.\n", "\n", "4. **Salotto Coffee**\n", " - Address: 813/8 Phetchaburi Rd, Thanon Phaya Thai, Ratchathewi\n", " - Rating: 5\n", " - Pricing: 200-350 THB for various coffee options.\n", "\n", "5. **The Basic Coffee BKK**\n", " - Address: ตึก Gaysorn Amarin (ชั้น 2 496-502 Phloen Chit Rd, Khwaeng Lumphini, Pathum Wan)\n", " - Rating: 4.7\n", " - Pricing: 150-250 THB for coffee.\n", "\n", "6. **Bullet Thai Craft Beer**\n", " - Address: 85 1 Akkharanithi Alley, Thanon Phaya Thai, Ratchathewi\n", " - Rating: 5\n", " - Pricing: 200-300 THB for coffee and craft beer.\n", "\n", "7. **TABLA Craft Coffee**\n", " - Address: 502, ห้างสรรพสินค้าอัมรินทร์ พลาซ่า ชั้น 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", " - Rating: 4.6\n", " - Pricing: 180-280 THB for coffee.\n", "\n", "8. **Sip 'n Drip**\n", " - Address: 36, 6 Kasem San 1 Alley, Wang Mai, Pathum Wan\n", " - Rating: 4.9\n", " - Pricing: 150-250 THB for coffee.\n", "\n", "9. **RISE COFFEE - Flagship Store**\n", " - Address: 888 อาคารมหาทุนพลาซ่า ชั้น 1 ยูนิต 1, Phloen Chit Rd, Lumphini, Pathum Wan\n", " - Rating: 4.8\n", " - Pricing: 125-200 THB for coffee.\n", "\n", "10. **You Drink Coffee**\n", " - Address: 89, 25 Witthayu Rd, Lumphini, Pathum Wan\n", " - Rating: 4.5\n", " - Pricing: 150-250 THB for coffee.\n", "\n", "### Population and Community Data for Pathum Wan\n", "- **Population**: Approximately 45,000 residents.\n", "- **Community Type**: Urban locality with a mix of residential and commercial establishments.\n", "- **Household Expenditures**: Average monthly household expenditure is around 34,000 THB.\n", "\n", "### Nearby Dense Communities\n", "- **Siam Kempinski Hotel Bangkok**\n", "- **Novotel Bangkok Platinum Pratunam**\n", "- **Centara Grand & Bangkok Convention Centre at CentralWorld**\n", "- **Grande Centre Point Ratchadamri**\n", "- **Baiyoke Suite Hotel**\n", "- **Centara Watergate Pavilion Hotel Bangkok**\n", "- **Bangkok City Inn**\n", "- **Aphrodite Inn Bangkok**\n", "- **The Residence Ratchathewi**\n", "- **Amari Bangkok**\n", "\n", "If you need further details or additional information, feel free to ask!\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: reporter\n", "\n", "### FINAL ANSWER\n", "\n", "#### 1. Competitors List\n", "- BEANS Coffee Roaster Paragon\n", "- Fellas.coffee @soi tonson\n", "- Earthy Roaster (Specialty Coffee)\n", "- Salotto Coffee\n", "- The Basic Coffee BKK\n", "- Bullet Thai Craft Beer\n", "- TABLA Craft Coffee\n", "- Sip 'n Drip\n", "- RISE COFFEE - Flagship Store\n", "- You Drink Coffee\n", "\n", "#### 2. Numerical Data\n", "- **Number of Competitors**: 10\n", "- **Common Products**: Specialty coffee, espresso drinks, craft beer.\n", "- **Price Range**: \n", " - BEANS Coffee Roaster Paragon: 200-300 THB\n", " - Fellas.coffee: 150-250 THB\n", " - Earthy Roaster: 180-280 THB\n", " - Salotto Coffee: 200-350 THB\n", " - The Basic Coffee BKK: 150-250 THB\n", " - Bullet Thai Craft Beer: 200-300 THB\n", " - TABLA Craft Coffee: 180-280 THB\n", " - Sip 'n Drip: 150-250 THB\n", " - RISE COFFEE: 125-200 THB\n", " - You Drink Coffee: 150-250 THB\n", "- **Competitor Ratings**: Range from 4.5 to 5.0.\n", "- **Community Type**: Urban locality with a mix of residential and commercial establishments.\n", "- **Household Expenditures**: Average monthly household expenditure is around 34,000 THB.\n", "- **Population**: Approximately 45,000 residents.\n", "\n", "#### 3. Descriptive Analytical Summary\n", "- **Target Customers**: The target customers are likely urban professionals, students, and tourists who frequent the area for shopping and leisure. The high ratings of the coffee shops indicate a preference for quality and specialty coffee.\n", "- **Potential Sales**: Given the high foot traffic around Central World and the popularity of coffee culture in Bangkok, there is significant potential for sales. The average price range of 150-350 THB for coffee products suggests a healthy margin for specialty coffee.\n", "- **Pricing Strategy**: A competitive pricing strategy should be adopted, considering the average prices of competitors. Setting prices slightly below the highest competitors (e.g., around 180-250 THB) could attract more customers while maintaining quality.\n", "- **Optimal Price Range**: Based on competitor pricing and customer expectations, an optimal price range for new coffee products could be set between 180-250 THB, ensuring it aligns with the quality and experience offered by existing competitors.\n", "\n", "This report provides a comprehensive overview of the competitive landscape for coffee shops near Central World, along with insights into potential strategies for entering this market.\n" ] } ], "source": [ "question = \"ร้านกาแฟใกล้เซ็นทรัลเวิลด์\"\n", "\n", "graph = workflow.compile()\n", "\n", "events = graph.stream(\n", " {\n", " \"messages\": [\n", " HumanMessage(\n", " question\n", " )\n", " ],\n", " },\n", " # Maximum number of steps to take in the graph\n", " {\"recursion_limit\": 20},\n", ")\n", "for s in events:\n", " # print(s)\n", " a = list(s.items())[0]\n", " a[1]['messages'][0].pretty_print()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def submitUserMessage(user_input: str) -> str:\n", " graph = workflow.compile()\n", "\n", " events = graph.stream(\n", " {\n", " \"messages\": [\n", " HumanMessage(\n", " user_input\n", " )\n", " ],\n", " },\n", " # Maximum number of steps to take in the graph\n", " {\"recursion_limit\": 20},\n", " )\n", " \n", " events = [e for e in events]\n", " \n", " response = list(events[-1].values())[0][\"messages\"][0]\n", " response = response.content\n", " response = response.replace(\"FINAL ANSWER\", \"\")\n", " \n", " return response\n", "\n", "\n", "# question = \"วิเคราะห์ร้านอาหารแถวลุมพินี เซ็นเตอร์ ลาดพร้าว\"\n", "# submitUserMessage(question)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 2 }