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

customer service - completed

Browse files
.gitignore CHANGED
@@ -1 +1,2 @@
1
  *.pyc
 
 
1
  *.pyc
2
+ /.chroma_db
src/langgraphagenticai/graph/graph_builder.py CHANGED
@@ -3,6 +3,7 @@ from langgraph.prebuilt import tools_condition,ToolNode
3
  from langchain_core.prompts import ChatPromptTemplate
4
  import datetime
5
  #module import
 
6
  from src.langgraphagenticai.tools.customtool import book_appointment, cancel_appointment, get_next_available_appointment
7
  from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
8
  from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
@@ -109,6 +110,9 @@ class GraphBuilder:
109
  # Set Entry Point and build the graph
110
  self.graph_builder.set_entry_point("agent")
111
 
 
 
 
112
 
113
  def setup_graph(self, usecase: str):
114
  """
@@ -120,6 +124,8 @@ class GraphBuilder:
120
  self.chatbot_with_tool_build_graph()
121
  elif usecase == "Appointment Receptionist":
122
  self.appointment_receptionist_bot_build_graph()
 
 
123
  else:
124
  raise ValueError("Invalid use case selected.")
125
  return self.graph_builder.compile()
 
3
  from langchain_core.prompts import ChatPromptTemplate
4
  import datetime
5
  #module import
6
+ from src.langgraphagenticai.node.customer_support_chatbot import Customer_Support_Bot
7
  from src.langgraphagenticai.tools.customtool import book_appointment, cancel_appointment, get_next_available_appointment
8
  from src.langgraphagenticai.tools.search_tool import create_tool_node, get_tools
9
  from src.langgraphagenticai.node.chatbot_with_tool_node import ChatbotWithToolNode
 
110
  # Set Entry Point and build the graph
111
  self.graph_builder.set_entry_point("agent")
112
 
113
+ def customer_support_build_graph(self):
114
+ obj_cs_bot = Customer_Support_Bot(llm=self.llm)
115
+ self.graph_builder = obj_cs_bot.chat_bot()
116
 
117
  def setup_graph(self, usecase: str):
118
  """
 
124
  self.chatbot_with_tool_build_graph()
125
  elif usecase == "Appointment Receptionist":
126
  self.appointment_receptionist_bot_build_graph()
127
+ elif usecase =="Customer Support":
128
+ self.customer_support_build_graph()
129
  else:
130
  raise ValueError("Invalid use case selected.")
131
  return self.graph_builder.compile()
src/langgraphagenticai/node/customer_support_chatbot.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, MessagesState
2
+ from langchain_core.prompts import ChatPromptTemplate
3
+ from langgraph.prebuilt import ToolNode
4
+ from src.langgraphagenticai.tools.customer_support_tools import query_knowledge_base, search_for_product_reccommendations, data_protection_check, create_new_customer, place_order, retrieve_existing_customer_orders
5
+
6
+ import os
7
+
8
+
9
+ class Customer_Support_Bot:
10
+ def __init__(self,llm):
11
+ self.llm = llm
12
+
13
+
14
+ def chat_bot(self):
15
+
16
+ prompt = """#Purpose
17
+
18
+ You are a customer service chatbot for a flower shop company. You can help the customer achieve the goals listed below.
19
+
20
+ #Goals
21
+
22
+ 1. Answer questions the user might have relating to serivces offered
23
+ 2. Recommend products to the user based on their preferences
24
+ 3. Help the customer check on an existing order, or place a new order
25
+ 4. To place and manage orders, you will need a customer profile (with an associated id). If the customer already has a profile, perform a data protection check to retrieve their details. If not, create them a profile.
26
+
27
+ #Tone
28
+
29
+ Helpful and friendly. Use gen-z emojis to keep things lighthearted. You MUST always include a funny flower related pun in every response."""
30
+
31
+ chat_template = ChatPromptTemplate.from_messages(
32
+ [
33
+ ('system', prompt),
34
+ ('placeholder', "{messages}")
35
+ ]
36
+ )
37
+
38
+
39
+
40
+ tools = [query_knowledge_base, search_for_product_reccommendations, data_protection_check, create_new_customer, place_order, retrieve_existing_customer_orders]
41
+
42
+ llm = self.llm
43
+
44
+ llm_with_prompt = chat_template | llm.bind_tools(tools)
45
+
46
+
47
+ def call_agent(message_state: MessagesState):
48
+
49
+ response = llm_with_prompt.invoke(message_state)
50
+
51
+ return {
52
+ 'messages': [response]
53
+ }
54
+
55
+ def is_there_tool_calls(state: MessagesState):
56
+ last_message = state['messages'][-1]
57
+ if last_message.tool_calls:
58
+ return 'tool_node'
59
+ else:
60
+ return '__end__'
61
+
62
+
63
+ graph = StateGraph(MessagesState)
64
+
65
+ tool_node = ToolNode(tools)
66
+
67
+ graph.add_node('agent', call_agent)
68
+ graph.add_node('tool_node', tool_node)
69
+
70
+ graph.add_conditional_edges(
71
+ "agent",
72
+ is_there_tool_calls
73
+ )
74
+ graph.add_edge('tool_node', 'agent')
75
+
76
+ graph.set_entry_point('agent')
77
+
78
+ # app = graph.compile()
79
+ return graph
80
+
src/langgraphagenticai/tools/customer_support_tools.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.tools import tool
2
+ from typing import List, Dict
3
+ import json
4
+
5
+ from src.langgraphagenticai.vectorstores.vectore_store import FlowerShopVectorStore
6
+
7
+ vector_store = FlowerShopVectorStore()
8
+ INVENTORY_FILE_PATH = './data/inventory.json'
9
+
10
+ customers_database = [
11
+ {"name": "John Doe", "postcode": "SW1A 1AA", "dob": "1990-01-01", "customer_id": "CUST001", "first_line_address": "123 Main St", "phone_number": "07712345678", "email": "john.doe@example.com"},
12
+ {"name": "Jane Smith", "postcode": "E1 6AN", "dob": "1985-05-15", "customer_id": "CUST002", "first_line_address": "456 High St", "phone_number": "07723456789", "email": "jane.smith@example.com"},
13
+ ]
14
+
15
+ orders_database = [
16
+ {"order_id": "ORD001", "customer_id": "CUST001", "status": "Processing", "items": ["Red Roses Bouquet"], "quantity": [1]},
17
+ {"order_id": "ORD002", "customer_id": "CUST002", "status": "Shipped", "items": ["Mixed Tulips", "Vase"], "quantity": [3, 1]},
18
+ ]
19
+
20
+ with open(INVENTORY_FILE_PATH, 'r') as f:
21
+ inventory_database = json.load(f)
22
+
23
+ data_protection_checks = []
24
+
25
+ @tool
26
+ def data_protection_check(name: str, postcode: str, year_of_birth: int, month_of_birth: int, day_of_birth: int) -> Dict:
27
+ """
28
+ Perform a data protection check against a customer to retrieve customer details.
29
+
30
+ Args:
31
+ name (str): Customer first and last name
32
+ postcode (str): Customer registered address
33
+ year_of_birth (int): The year the customer was born
34
+ month_of_birth (int): The month the customer was born
35
+ day_of_birth (int): The day the customer was born
36
+
37
+ Returns:
38
+ Dict: Customer details (name, postcode, dob, customer_id, first_line_address, email)
39
+ """
40
+ data_protection_checks.append(
41
+ {
42
+ 'name': name,
43
+ 'postcode': postcode,
44
+ 'year_of_birth': year_of_birth,
45
+ 'month_of_birth': month_of_birth,
46
+ 'day_of_birth': day_of_birth
47
+ }
48
+ )
49
+ for customer in customers_database:
50
+ if (customer['name'].lower() == name.lower() and
51
+ customer['postcode'].lower() == postcode.lower() and
52
+ int(customer['dob'][0:4]) == year_of_birth and
53
+ int(customer["dob"][5:7]) == month_of_birth and
54
+ int(customer["dob"][8:10]) == day_of_birth):
55
+ return f"DPA check passed - Retrieved customer details:\n{customer}"
56
+
57
+ return "DPA check failed, no customer with these details found"
58
+
59
+ @tool
60
+ def create_new_customer(first_name: str, surname: str, year_of_birth: int, month_of_birth: int, day_of_birth: int, postcode: str, first_line_of_address: str, phone_number: str, email: str) -> str:
61
+ """
62
+ Creates a customer profile, so that they can place orders.
63
+
64
+ Args:
65
+ first_name (str): Customers first name
66
+ surname (str): Customers surname
67
+ year_of_birth (int): Year customer was born
68
+ month_of_birth (int): Month customer was born
69
+ day_of_birth (int): Day customer was born
70
+ postcode (str): Customer's postcode
71
+ first_line_address (str): Customer's first line of address
72
+ phone_number (str): Customer's phone number
73
+ email (str): Customer's email address
74
+
75
+ Returns:
76
+ str: Confirmation that the profile has been created or any issues with the inputs
77
+ """
78
+ if len(phone_number) != 11:
79
+ return "Phone number must be 11 digits"
80
+ customer_id = len(customers_database) + 1
81
+ customers_database.append({
82
+ 'name': first_name + ' ' + surname,
83
+ 'dob': f'{year_of_birth}-{month_of_birth:02}-{day_of_birth:02}',
84
+ 'postcode': postcode,
85
+ 'first_line_address': first_line_of_address,
86
+ 'phone_number': phone_number,
87
+ 'email': email,
88
+ 'customer_id': f'CUST{customer_id}'
89
+ })
90
+ return f"Customer registered, with customer_id {f'CUST{customer_id}'}"
91
+
92
+
93
+ @tool
94
+ def query_knowledge_base(query: str) -> List[Dict[str, str]]:
95
+ """
96
+ Looks up information in a knowledge base to help with answering customer questions and getting information on business processes.
97
+
98
+ Args:
99
+ query (str): Question to ask the knowledge base
100
+
101
+ Return:
102
+ List[Dict[str, str]]: Potentially relevant question and answer pairs from the knowledge base
103
+ """
104
+ return vector_store.query_faqs(query=query)
105
+
106
+
107
+
108
+ @tool
109
+ def search_for_product_reccommendations(description: str):
110
+ """
111
+ Looks up information in a knowledge base to help with product recommendation for customers. For example:
112
+
113
+ "Boquets suitable for birthdays, maybe with red flowers"
114
+ "A large boquet for a wedding"
115
+ "A cheap boquet with wildflowers"
116
+
117
+ Args:
118
+ query (str): Description of product features
119
+
120
+ Return:
121
+ List[Dict[str, str]]: Potentially relevant products
122
+ """
123
+ return vector_store.query_inventories(query=description)
124
+
125
+ @tool
126
+ def retrieve_existing_customer_orders(customer_id: str) -> List[Dict]:
127
+ """
128
+ Retrieves the orders associated with the customer, including their status, items and ids
129
+
130
+ Args:
131
+ customer_id (str): Customer unique id associated with the order
132
+
133
+ Returns:
134
+ List[Dict]: All the orders associated with the customer_id passed in
135
+ """
136
+ customer_orders = [order for order in orders_database if order['customer_id'] == customer_id]
137
+ if not customer_orders:
138
+ return f"No orders associated with this customer id: {customer_id}"
139
+ return customer_orders
140
+
141
+ @tool
142
+ def place_order(items: Dict[str, int], customer_id: str) -> str:
143
+ """
144
+ Places an order for the requested items, and for the required quantities.
145
+
146
+ Args:
147
+ items (Dict[str, int]): Dictionary of items to order, with item id as the key and the quantity of that item as the value.
148
+ customer_id (str): The customer to place the order for
149
+
150
+ Returns:
151
+ str: Message indicating that the order has been placed, or, it hasnt been placed due to an issue
152
+ """
153
+ # Check that the item ids are valid
154
+ # Check that the quantities of items are valid
155
+ availability_messages = []
156
+ valid_item_ids = [
157
+ item['id'] for item in inventory_database
158
+ ]
159
+ for item_id, quantity in items.items():
160
+ if item_id not in valid_item_ids:
161
+ availability_messages.append(f'Item with id {item_id} is not found in the inventory')
162
+ else:
163
+ inventory_item = [item for item in inventory_database if item['id'] == item_id][0]
164
+ if quantity > inventory_item['quantity']:
165
+ availability_messages.append(f'There is insufficient quantity in the inventory for this item {inventory_item["name"]}\nAvailable: {inventory_item["quantity"]}\nRequested: {quantity}')
166
+ if availability_messages:
167
+ return "Order cannot be placed due to the following issues: \n" + '\n'.join(availability_messages)
168
+
169
+ # Place the order (in pretend database)
170
+ order_id = len(orders_database) + 1
171
+ orders_database.append(
172
+ {
173
+ 'order_id': order_id,
174
+ 'customer_id': customer_id,
175
+ 'status': 'Waiting for payment',
176
+ 'items': list(items.keys()),
177
+ 'quantity': list(items.values())
178
+ }
179
+ )
180
+ # Update the inventory
181
+ for item_id, quantity in items.items():
182
+ inventory_item = [item for item in inventory_database if item['id'] == item_id][0]
183
+ inventory_item['quantity'] -= quantity
184
+ return f"Order with id {order_id} has been placed successfully"
src/langgraphagenticai/ui/streamlitui/display_result.py CHANGED
@@ -2,6 +2,7 @@ import streamlit as st
2
  from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
3
 
4
  from src.langgraphagenticai.tools.customtool import APPOINTMENTS
 
5
 
6
  class DisplayResultStreamlit:
7
  def __init__(self,usecase,graph,user_message):
@@ -58,10 +59,32 @@ class DisplayResultStreamlit:
58
  else:
59
  with st.chat_message("assistant"):
60
  st.write(message.content)
61
-
62
  with col2:
63
  st.header("Appointments")
64
  st.write(APPOINTMENTS)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  # display graph
66
  if graph:
67
  st.write('state graph - workflow')
 
2
  from langchain_core.messages import HumanMessage,AIMessage,ToolMessage
3
 
4
  from src.langgraphagenticai.tools.customtool import APPOINTMENTS
5
+ from src.langgraphagenticai.tools.customer_support_tools import customers_database, data_protection_checks
6
 
7
  class DisplayResultStreamlit:
8
  def __init__(self,usecase,graph,user_message):
 
59
  else:
60
  with st.chat_message("assistant"):
61
  st.write(message.content)
 
62
  with col2:
63
  st.header("Appointments")
64
  st.write(APPOINTMENTS)
65
+ elif usecase == "Customer Support":
66
+
67
+ main_col, right_col = st.columns([2, 1])
68
+ response = graph.invoke({
69
+ 'messages': user_message
70
+ })
71
+ with main_col:
72
+ st.session_state.message_history = response['messages']
73
+ for i in range(1, len(st.session_state.message_history) + 1):
74
+ this_message = st.session_state.message_history[-i]
75
+ if isinstance(this_message, AIMessage):
76
+ message_box = st.chat_message('assistant')
77
+ else:
78
+ message_box = st.chat_message('user')
79
+ if this_message.content:
80
+ message_box.markdown(this_message.content)
81
+ # 3. State variables
82
+ with right_col:
83
+ st.title('customers database')
84
+ st.write(customers_database)
85
+ st.title('data protection checks')
86
+ st.write(data_protection_checks)
87
+
88
  # display graph
89
  if graph:
90
  st.write('state graph - workflow')
src/langgraphagenticai/ui/streamlitui/loadui.py CHANGED
@@ -1,7 +1,8 @@
1
  import streamlit as st
2
  import os
3
 
4
- from src.langgraphagenticai.ui.configfile import Config
 
5
 
6
 
7
  class LoadStreamlitUI:
@@ -46,7 +47,24 @@ class LoadStreamlitUI:
46
  st.subheader("Appointments")
47
 
48
  elif self.user_controls['selected_usecase']=="Customer Support":
49
- # TODO :: to be removed
50
- st.warning("⌛Revamp is in progress...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  return self.user_controls
 
1
  import streamlit as st
2
  import os
3
 
4
+ from src.langgraphagenticai.ui.uiconfigfile import Config
5
+ from langchain_core.messages import AIMessage, HumanMessage
6
 
7
 
8
  class LoadStreamlitUI:
 
47
  st.subheader("Appointments")
48
 
49
  elif self.user_controls['selected_usecase']=="Customer Support":
50
+ st.subheader('Flower Shop Chatbot' + '💐')
51
+ greeting="Hi 🙋🏻‍♀️, I am the flower shop chatbot. How can I help?"
52
+
53
+ if 'message_history' not in st.session_state:
54
+ st.session_state.message_history = [AIMessage(content=greeting)]
55
+
56
+ with st.chat_message("assistant"):
57
+ st.write(greeting)
58
+
59
+ # 1. Buttons for chat - Clear Button
60
+
61
+
62
+
63
+ with st.sidebar:
64
+ if st.button('Clear Chat'):
65
+ st.session_state.message_history = []
66
+
67
+
68
+
69
 
70
  return self.user_controls
src/langgraphagenticai/ui/{configfile.ini → uiconfigfile.ini} RENAMED
File without changes
src/langgraphagenticai/ui/{configfile.py → uiconfigfile.py} RENAMED
@@ -2,7 +2,7 @@ from configparser import ConfigParser
2
 
3
 
4
  class Config:
5
- def __init__(self, config_file="./src/langgraphagenticai/ui/configfile.ini"):
6
  self.config = ConfigParser()
7
  self.config.read(config_file)
8
 
 
2
 
3
 
4
  class Config:
5
+ def __init__(self, config_file="./src/langgraphagenticai/ui/uiconfigfile.ini"):
6
  self.config = ConfigParser()
7
  self.config.read(config_file)
8
 
src/langgraphagenticai/vectorstores/vectore_store.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from chromadb import PersistentClient, EmbeddingFunction, Embeddings
2
+ from llama_index.embeddings.huggingface import HuggingFaceEmbedding
3
+ from typing import List
4
+ import json
5
+
6
+
7
+ MODEL_NAME = 'dunzhang/stella_en_1.5B_v5'
8
+ DB_PATH = './.chroma_db'
9
+ FAQ_FILE_PATH= './data/FAQ.json'
10
+ INVENTORY_FILE_PATH = './data/inventory.json'
11
+
12
+ class Product:
13
+ def __init__(self, name: str, id: str, description: str, type: str, price: float, quantity: int):
14
+ self.name = name
15
+ self.id = id
16
+ self.description = description
17
+ self.type = type
18
+ self.price = price
19
+ self.quantity = quantity
20
+
21
+ class QuestionAnswerPairs:
22
+ def __init__(self, question: str, answer: str):
23
+ self.question = question
24
+ self.answer = answer
25
+
26
+ class CustomEmbeddingClass(EmbeddingFunction):
27
+ def __init__(self, model_name):
28
+ self.embedding_model = HuggingFaceEmbedding(model_name=MODEL_NAME)
29
+
30
+ def __call__(self, input_texts: List[str]) -> Embeddings:
31
+ return [self.embedding_model.get_text_embedding(text) for text in input_texts]
32
+
33
+ class FAQCollection:
34
+ def __init__(self):
35
+ self.documents = []
36
+ self.ids = []
37
+ self.metadatas = []
38
+
39
+ def add(self, documents, ids, metadatas):
40
+ self.documents.extend(documents)
41
+ self.ids.extend(ids)
42
+ self.metadatas.extend(metadatas)
43
+
44
+ def display(self):
45
+ for doc, id_, meta in zip(self.documents, self.ids, self.metadatas):
46
+ print(f"ID: {id_}, Document: {doc}, Metadata: {meta}")
47
+
48
+ # Define the InventoryCollection class
49
+ class InventoryCollection:
50
+ def __init__(self):
51
+ self.documents = []
52
+ self.ids = []
53
+ self.metadatas = []
54
+
55
+ def add(self, documents, ids, metadatas):
56
+ self.documents.extend(documents)
57
+ self.ids.extend(ids)
58
+ self.metadatas.extend(metadatas)
59
+
60
+ def display(self):
61
+ for doc, id_, meta in zip(self.documents, self.ids, self.metadatas):
62
+ print(f"ID: {id_}, Document: {doc}, Metadata: {meta}")
63
+
64
+
65
+
66
+
67
+ class FlowerShopVectorStore:
68
+ def __init__(self):
69
+ db = PersistentClient(path=DB_PATH)
70
+
71
+ custom_embedding_function = CustomEmbeddingClass(MODEL_NAME)
72
+
73
+ self.faq_collection = db.get_or_create_collection(name='FAQ', embedding_function=custom_embedding_function)
74
+ self.inventory_collection = db.get_or_create_collection(name='Inventory', embedding_function=custom_embedding_function)
75
+
76
+ if self.faq_collection.count() == 0:
77
+ try :
78
+ self._load_faq_collection(FAQ_FILE_PATH)
79
+ except Exception as e:
80
+ raise ValueError(e)
81
+
82
+
83
+ if self.inventory_collection.count() == 0:
84
+ self._load_inventory_collection(INVENTORY_FILE_PATH)
85
+
86
+ def _load_faq_collection(self, faq_file_path: str):
87
+ try:
88
+
89
+ with open(faq_file_path, 'r') as f:
90
+ faqs = json.load(f)
91
+
92
+ # Create an instance of FAQCollection
93
+ obj_faq_collection = FAQCollection()
94
+
95
+ obj_faq_collection.add(
96
+ documents=[faq['question'] for faq in faqs] + [faq['answer'] for faq in faqs],
97
+ ids=[str(i) for i in range(0, 2*len(faqs))],
98
+ metadatas = faqs + faqs
99
+ )
100
+ self.faq_collection = obj_faq_collection
101
+ except Exception as ex:
102
+ raise ValueError(ex)
103
+
104
+ def _load_inventory_collection(self, inventory_file_path: str):
105
+ with open(inventory_file_path, 'r') as f:
106
+ inventories = json.load(f)
107
+
108
+ # Create an instance of InventoryCollection
109
+ obj_inventory_collection = InventoryCollection()
110
+
111
+ obj_inventory_collection.add(
112
+ documents=[inventory['description'] for inventory in inventories],
113
+ ids=[str(i) for i in range(0, len(inventories))],
114
+ metadatas = inventories
115
+ )
116
+ self.inventory_collection = obj_inventory_collection
117
+
118
+ def query_faqs(self, query: str):
119
+ return self.faq_collection.query(query_texts=[query], n_results=5)
120
+
121
+ def query_inventories(self, query: str):
122
+ return self.inventory_collection.query(query_texts=[query], n_results=5)