rairo commited on
Commit
d1d8db7
·
verified ·
1 Parent(s): 893c696

Create checkpointapp.py

Browse files
Files changed (1) hide show
  1. checkpointapp.py +243 -0
checkpointapp.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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):
21
+ genai.configure(api_key=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):
34
+ self.df = products_df
35
+ self.memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
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
+
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()