rairo commited on
Commit
4e54143
·
verified ·
1 Parent(s): 37c0979

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -41
app.py CHANGED
@@ -26,7 +26,7 @@ model = configure_gemini(os.environ['GOOGLE_API_KEY'])
26
  # Initialize Gemini models
27
  llm_flash_exp = ChatGoogleGenerativeAI(
28
  model="gemini-2.0-flash-exp",
29
- max_retries=2 # Limit retries to 2
30
  )
31
 
32
  class SmartShoppingAssistant:
@@ -36,38 +36,82 @@ class SmartShoppingAssistant:
36
  self.setup_agent()
37
 
38
  def find_closest_product(self, product_name, threshold=0.6):
39
- """Find the closest matching product name using fuzzy matching"""
40
  matches = get_close_matches(
41
  product_name.upper(),
42
  self.df['ProductName'].str.upper().tolist(),
43
- n=1,
44
  cutoff=threshold
45
  )
46
- return matches[0] if matches else None
47
 
48
- def search_products_fuzzy(self, product_names):
49
- """Search for products using fuzzy matching"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  results = pd.DataFrame()
51
- for name in product_names:
52
- closest_match = self.find_closest_product(name)
53
- if closest_match:
54
- matched_products = self.df[self.df['ProductName'].str.upper() == closest_match.upper()]
55
- results = pd.concat([results, matched_products])
 
 
 
 
 
 
 
 
 
 
 
 
56
  return results
57
 
58
  def setup_agent(self):
59
  """Set up the LangChain agent with necessary tools"""
60
  def search_products(query):
61
  try:
62
- # Extract product names from the query
63
- product_names = [name.strip('"\'') for name in query.split(' or ')]
64
- product_names = [name.split('==')[1].strip() if '==' in name else name for name in product_names]
65
 
66
- if 'RetailPrice' in self.df.columns:
67
- self.df['RetailPrice'] = pd.to_numeric(self.df['RetailPrice'].str.replace('$', ''), errors='coerce')
68
-
69
- results = self.search_products_fuzzy(product_names)
70
- return results.to_string() if not results.empty else "No products found matching your criteria."
 
 
 
 
71
  except Exception as e:
72
  return f"Error executing query: {str(e)}"
73
 
@@ -85,39 +129,40 @@ class SmartShoppingAssistant:
85
  llm=llm_flash_exp,
86
  agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
87
  verbose=True,
88
- max_iterations=3 # Limit the number of iterations
89
  )
90
 
91
  def process_natural_language_query(self, query):
92
- """Process natural language query and return relevant products"""
93
-
94
- product_list = self.df['ProductName'].tolist()
95
- product_string = ", ".join(product_list)
96
  try:
97
- prompt = f"""
98
- Convert this shopping request into a list of product names to search for. The response should be in the format:
99
- ProductName == "PRODUCT1" or ProductName == "PRODUCT2" or ProductName == "PRODUCT3"
 
100
 
101
  Shopping request: {query}
102
-
103
- Available products will be matched approximately or use you intelligent to look at product and list and see the ones that match
104
- , so focus on the main product names.
105
- Return only the search string, nothing else.
106
-
107
- This is the list of products: {product_string}
108
  """
109
 
110
- response = llm_flash_exp.predict(prompt)
111
- structured_query = response.strip()
 
 
112
 
113
- result = self.agent.run(f"Search for products matching the specified names: {structured_query}")
 
114
  return result
115
  except Exception as e:
116
  return f"Error processing query: {str(e)}"
117
 
118
  def extract_text_from_image(self, image):
119
  """Extract text from uploaded image using Gemini"""
120
- prompt = """Analyze this image and extract products text from the image"""
 
 
 
 
121
  try:
122
  response = model.generate_content([prompt, image])
123
  return response.text
@@ -147,7 +192,6 @@ def main():
147
  df = load_product_data()
148
  assistant = SmartShoppingAssistant(df)
149
 
150
- # Sidebar for file uploads
151
  with st.sidebar:
152
  st.header("Upload Shopping List")
153
  uploaded_file = st.file_uploader(
@@ -169,15 +213,14 @@ def main():
169
  except Exception as e:
170
  st.error(f"Error processing file: {str(e)}")
171
 
172
- # Main content area
173
  col1, col2 = st.columns([2, 1])
174
 
175
  with col1:
176
  st.header("Search Products")
177
  query = st.text_area(
178
- "Describe what you're looking for:",
179
  height=100,
180
- placeholder="Example: I need healthy breakfast cereals under $5",
181
  value=st.session_state.get('query', '')
182
  )
183
 
 
26
  # Initialize Gemini models
27
  llm_flash_exp = ChatGoogleGenerativeAI(
28
  model="gemini-2.0-flash-exp",
29
+ max_retries=2
30
  )
31
 
32
  class SmartShoppingAssistant:
 
36
  self.setup_agent()
37
 
38
  def find_closest_product(self, product_name, threshold=0.6):
 
39
  matches = get_close_matches(
40
  product_name.upper(),
41
  self.df['ProductName'].str.upper().tolist(),
42
+ n=3, # Increased to get more potential matches
43
  cutoff=threshold
44
  )
45
+ return matches if matches else []
46
 
47
+ def match_products_with_catalogue(self, extracted_items):
48
+ """Match extracted items with catalogue products using Gemini"""
49
+ product_list = self.df['ProductName'].tolist()
50
+ product_string = ", ".join(product_list)
51
+
52
+ prompt = f"""
53
+ Given these extracted items and quantities:
54
+ {extracted_items}
55
+
56
+ And this product catalogue:
57
+ {product_string}
58
+
59
+ Match each item with the most appropriate product from the catalogue.
60
+ For each item, provide:
61
+ 1. The exact product name from the catalogue
62
+ 2. The quantity (if specified, otherwise assume 1)
63
+ 3. Any specific requirements (brand, size, etc.)
64
+
65
+ Format the response as:
66
+ ProductName == "MATCHED_PRODUCT" quantity: NUMBER or ProductName == "MATCHED_PRODUCT" quantity: NUMBER
67
+
68
+ Only include products that have good matches in the catalogue.
69
+ """
70
+
71
+ try:
72
+ matches = llm_flash_exp.predict(prompt)
73
+ return matches.strip()
74
+ except Exception as e:
75
+ return f"Error matching products: {str(e)}"
76
+
77
+ def search_products_fuzzy(self, product_names_with_quantities):
78
+ """Search for products using fuzzy matching with quantity information"""
79
  results = pd.DataFrame()
80
+ for item in product_names_with_quantities:
81
+ product_info = item.split('quantity:')
82
+ product_name = product_info[0].strip()
83
+ quantity = int(product_info[1].strip()) if len(product_info) > 1 else 1
84
+
85
+ # Clean up product name
86
+ if 'ProductName ==' in product_name:
87
+ product_name = product_name.split('==')[1].strip(' "\'')
88
+
89
+ closest_matches = self.find_closest_product(product_name)
90
+ for match in closest_matches:
91
+ matched_products = self.df[self.df['ProductName'].str.upper() == match.upper()]
92
+ if not matched_products.empty:
93
+ matched_products['Quantity'] = quantity
94
+ results = pd.concat([results, matched_products])
95
+ break
96
+
97
  return results
98
 
99
  def setup_agent(self):
100
  """Set up the LangChain agent with necessary tools"""
101
  def search_products(query):
102
  try:
103
+ # Split into individual product entries
104
+ product_entries = [entry.strip() for entry in query.split('or')]
 
105
 
106
+ results = self.search_products_fuzzy(product_entries)
107
+ if not results.empty:
108
+ # Format results with quantity
109
+ formatted_results = results.apply(
110
+ lambda x: f"{x['ProductName']} (Quantity: {x['Quantity']})\nPrice: ${x['RetailPrice']:.2f}\n",
111
+ axis=1
112
+ )
113
+ return "\n".join(formatted_results)
114
+ return "No products found matching your criteria."
115
  except Exception as e:
116
  return f"Error executing query: {str(e)}"
117
 
 
129
  llm=llm_flash_exp,
130
  agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
131
  verbose=True,
132
+ max_iterations=3
133
  )
134
 
135
  def process_natural_language_query(self, query):
136
+ """Process natural language query with two-step matching"""
 
 
 
137
  try:
138
+ # First step: Extract items and quantities
139
+ extraction_prompt = f"""
140
+ Extract the products and their quantities from this shopping request.
141
+ Include any specific requirements mentioned.
142
 
143
  Shopping request: {query}
144
+
145
+ Format each item with its quantity (assume 1 if not specified).
 
 
 
 
146
  """
147
 
148
+ extracted_items = llm_flash_exp.predict(extraction_prompt)
149
+
150
+ # Second step: Match with catalogue
151
+ matched_products = self.match_products_with_catalogue(extracted_items)
152
 
153
+ # Third step: Search and return results
154
+ result = self.agent.run(f"Search for products matching the specified names: {matched_products}")
155
  return result
156
  except Exception as e:
157
  return f"Error processing query: {str(e)}"
158
 
159
  def extract_text_from_image(self, image):
160
  """Extract text from uploaded image using Gemini"""
161
+ prompt = """
162
+ Analyze this image and extract products and their quantities.
163
+ If quantities aren't specified, make reasonable assumptions based on typical shopping patterns.
164
+ List each item with its quantity.
165
+ """
166
  try:
167
  response = model.generate_content([prompt, image])
168
  return response.text
 
192
  df = load_product_data()
193
  assistant = SmartShoppingAssistant(df)
194
 
 
195
  with st.sidebar:
196
  st.header("Upload Shopping List")
197
  uploaded_file = st.file_uploader(
 
213
  except Exception as e:
214
  st.error(f"Error processing file: {str(e)}")
215
 
 
216
  col1, col2 = st.columns([2, 1])
217
 
218
  with col1:
219
  st.header("Search Products")
220
  query = st.text_area(
221
+ "Describe what you're looking for (include quantities if needed):",
222
  height=100,
223
+ placeholder="Example: 2 boxes of healthy breakfast cereals under $5, 1 gallon of milk",
224
  value=st.session_state.get('query', '')
225
  )
226