rairo commited on
Commit
1ec1a8e
·
verified ·
1 Parent(s): f223fe4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -188
app.py CHANGED
@@ -1,20 +1,18 @@
1
  import streamlit as st
2
  import pandas as pd
 
3
  from langchain.memory import ConversationBufferMemory
4
  from langchain_google_genai import ChatGoogleGenerativeAI
5
- import google.generativeai as genai
6
- from PIL import Image
7
- import PyPDF2
8
- import os
9
  from langchain.agents import initialize_agent, Tool
10
  from langchain.agents.agent_types import AgentType
11
  from difflib import get_close_matches
12
  from dotenv import load_dotenv
 
 
13
 
14
  # Load environment variables
15
  load_dotenv()
16
 
17
- # Configure Google API
18
  genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
19
 
20
  def configure_gemini(api_key):
@@ -22,12 +20,7 @@ def configure_gemini(api_key):
22
  return genai.GenerativeModel('gemini-2.0-flash-thinking-exp')
23
 
24
  model = configure_gemini(os.environ['GOOGLE_API_KEY'])
25
-
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:
33
  def __init__(self, products_df):
@@ -38,206 +31,96 @@ class SmartShoppingAssistant:
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
-
118
- tools = [
119
- Tool(
120
- name="Product Search",
121
- func=search_products,
122
- description="Search for products in the supermarket database using fuzzy matching"
123
- )
124
- ]
125
 
126
- self.agent = initialize_agent(
127
- tools=tools,
128
- memory=self.memory,
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
169
- except Exception as e:
170
- return f"Error processing image: {str(e)}"
171
-
172
- def extract_text_from_pdf(self, pdf_file):
173
- """Extract text from uploaded PDF"""
174
- try:
175
- pdf_reader = PyPDF2.PdfReader(pdf_file)
176
- text = ""
177
- for page in pdf_reader.pages:
178
- text += page.extract_text()
179
- return text
180
- except Exception as e:
181
- return f"Error processing PDF: {str(e)}"
182
 
183
- # Main function remains the same
184
  def main():
185
  st.set_page_config(page_title="Smart Shopping Assistant", layout="wide")
186
  st.title("🛒 Smart Shopping Assistant")
187
 
188
  @st.cache_data
189
  def load_product_data():
190
- return pd.read_csv('supermarket4.csv')
191
 
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(
198
- "Upload an image or PDF of your shopping list",
199
- type=['png', 'jpg', 'jpeg', 'pdf']
200
- )
201
-
202
- if uploaded_file:
203
- try:
204
- if uploaded_file.type.startswith('image'):
205
- with st.spinner("Extracting items from image..."):
206
- image = Image.open(uploaded_file)
207
- extracted_text = assistant.extract_text_from_image(image)
208
- st.session_state.query = extracted_text
209
- elif uploaded_file.type == 'application/pdf':
210
- with st.spinner("Extracting items from PDF..."):
211
- extracted_text = assistant.extract_text_from_pdf(uploaded_file)
212
- st.session_state.query = extracted_text
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
-
227
- if st.button("Search"):
228
- if query:
229
- with st.spinner("Searching for products..."):
230
- results = assistant.process_natural_language_query(query)
231
- st.write("### Results")
232
- st.write(results)
233
  else:
234
- st.warning("Please enter a search query or upload a shopping list.")
235
 
236
- with col2:
237
- st.header("Shopping Cart")
238
- if 'cart' not in st.session_state:
 
 
 
 
 
 
 
 
239
  st.session_state.cart = []
240
- st.write("Your cart is empty" if not st.session_state.cart else "Cart items here")
 
 
241
 
242
  if __name__ == "__main__":
243
- main()
 
1
  import streamlit as st
2
  import pandas as pd
3
+ import google.generativeai as genai
4
  from langchain.memory import ConversationBufferMemory
5
  from langchain_google_genai import ChatGoogleGenerativeAI
 
 
 
 
6
  from langchain.agents import initialize_agent, Tool
7
  from langchain.agents.agent_types import AgentType
8
  from difflib import get_close_matches
9
  from dotenv import load_dotenv
10
+ from fpdf import FPDF
11
+ import os
12
 
13
  # Load environment variables
14
  load_dotenv()
15
 
 
16
  genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
17
 
18
  def configure_gemini(api_key):
 
20
  return genai.GenerativeModel('gemini-2.0-flash-thinking-exp')
21
 
22
  model = configure_gemini(os.environ['GOOGLE_API_KEY'])
23
+ llm_flash_exp = ChatGoogleGenerativeAI(model="gemini-2.0-flash-exp", max_retries=2)
 
 
 
 
 
24
 
25
  class SmartShoppingAssistant:
26
  def __init__(self, products_df):
 
31
  def find_closest_product(self, product_name, threshold=0.6):
32
  matches = get_close_matches(
33
  product_name.upper(),
34
+ self.df[self.df['IsAvailable'] == "Yes"]['ProductName'].str.upper().tolist(),
35
+ n=5, # Get more matches
36
  cutoff=threshold
37
  )
38
  return matches if matches else []
39
 
40
+ def search_products_fuzzy(self, query):
41
+ results = []
42
+ closest_matches = self.find_closest_product(query)
43
+ for match in closest_matches:
44
+ matched_products = self.df[self.df['ProductName'].str.upper() == match.upper()]
45
+ if not matched_products.empty:
46
+ results.append(matched_products.iloc[0].to_dict())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  return results
48
+
49
  def setup_agent(self):
 
50
  def search_products(query):
51
+ results = self.search_products_fuzzy(query)
52
+ if results:
53
+ return "\n".join([f"{res['ProductName']} - ${res['RetailPrice']}" for res in results])
54
+ return "No products found."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ tools = [Tool(name="Product Search", func=search_products, description="Search for products in the supermarket")]
57
+ self.agent = initialize_agent(tools=tools, memory=self.memory, llm=llm_flash_exp, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
 
 
 
 
 
 
58
 
59
+ def process_query(self, query):
60
+ return self.agent.run(f"Find the best matches for: {query}")
61
+
62
+ def generate_receipt(cart_items):
63
+ pdf = FPDF()
64
+ pdf.add_page()
65
+ pdf.set_font("Arial", size=12)
66
+ pdf.cell(200, 10, txt="Supermarket Receipt", ln=True, align='C')
67
+ pdf.ln(10)
68
+ total = 0
69
+ for item in cart_items:
70
+ line = f"{item['ProductName']} - ${item['RetailPrice']}"
71
+ pdf.cell(200, 10, txt=line, ln=True)
72
+ total += item['RetailPrice']
73
+ pdf.ln(10)
74
+ pdf.cell(200, 10, txt=f"Total: ${total:.2f}", ln=True)
75
+ receipt_path = "receipt.pdf"
76
+ pdf.output(receipt_path)
77
+ return receipt_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
 
79
  def main():
80
  st.set_page_config(page_title="Smart Shopping Assistant", layout="wide")
81
  st.title("🛒 Smart Shopping Assistant")
82
 
83
  @st.cache_data
84
  def load_product_data():
85
+ return pd.read_csv('supermarket4i.csv')
86
 
87
  df = load_product_data()
88
  assistant = SmartShoppingAssistant(df)
89
 
90
+ if 'cart' not in st.session_state:
91
+ st.session_state.cart = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ query = st.text_input("Search for a product:")
94
+ if st.button("Search"):
95
+ if query:
96
+ results = assistant.search_products_fuzzy(query)
97
+ if results:
98
+ for res in results:
99
+ col1, col2 = st.columns([3, 1])
100
+ with col1:
101
+ st.write(f"**{res['ProductName']}** - ${res['RetailPrice']}")
102
+ with col2:
103
+ if st.button("Add to Cart", key=res['ProductName']):
104
+ st.session_state.cart.append(res)
105
+ st.rerun()
 
 
106
  else:
107
+ st.warning("No matching products found.")
108
 
109
+ st.header("Shopping Cart")
110
+ if st.session_state.cart:
111
+ total = sum(item['RetailPrice'] for item in st.session_state.cart)
112
+ for item in st.session_state.cart:
113
+ st.write(f"{item['ProductName']} - ${item['RetailPrice']}")
114
+ st.write(f"**Total: ${total:.2f}**")
115
+
116
+ if st.button("Checkout"):
117
+ receipt_path = generate_receipt(st.session_state.cart)
118
+ with open(receipt_path, "rb") as file:
119
+ st.download_button(label="Download Receipt", data=file, file_name="receipt.pdf", mime="application/pdf")
120
  st.session_state.cart = []
121
+ st.rerun()
122
+ else:
123
+ st.write("Your cart is empty.")
124
 
125
  if __name__ == "__main__":
126
+ main()