akiko19191 commited on
Commit
dfe4909
·
verified ·
1 Parent(s): 3ac1c97

Upload folder using huggingface_hub

Browse files
__pycache__/search_engine.cpython-311.pyc CHANGED
Binary files a/__pycache__/search_engine.cpython-311.pyc and b/__pycache__/search_engine.cpython-311.pyc differ
 
app/__pycache__/ai_features.cpython-311.pyc CHANGED
Binary files a/app/__pycache__/ai_features.cpython-311.pyc and b/app/__pycache__/ai_features.cpython-311.pyc differ
 
app/__pycache__/api.cpython-311.pyc CHANGED
Binary files a/app/__pycache__/api.cpython-311.pyc and b/app/__pycache__/api.cpython-311.pyc differ
 
app/__pycache__/config.cpython-311.pyc CHANGED
Binary files a/app/__pycache__/config.cpython-311.pyc and b/app/__pycache__/config.cpython-311.pyc differ
 
app/api.py CHANGED
@@ -43,25 +43,48 @@ def get_product_image(product_id):
43
 
44
  @api_bp.route('/products', methods=['GET'])
45
  def get_products():
46
- # --- MODIFIED: Construct the correct image_url pointing to our new endpoint ---
47
- products_cursor = mongo.db.products.find()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  products_list = []
49
  for p in products_cursor:
 
50
  image_url = None
51
- # If image_data exists, create a URL to our new endpoint
52
- if p.get('image_data'):
53
- # FIX: Generate an absolute URL to avoid cross-origin issues with the frontend dev server.
54
- image_url = url_for('api.get_product_image', product_id=str(p['_id']), _external=True)
55
- # Otherwise, use the fallback AI-generated URL if it exists
56
  elif p.get('image_url'):
57
  image_url = p.get('image_url')
58
 
59
  products_list.append({
60
- 'id': str(p['_id']),
61
- 'name': p.get('name'),
62
  'category': p.get('category'),
63
- 'modes': p.get('modes'),
64
- 'image_url': image_url, # This will be the correct, usable URL
65
  'description': p.get('description', '')
66
  })
67
  return jsonify(products_list)
@@ -151,49 +174,86 @@ def handle_cart():
151
  user_email = get_jwt_identity()
152
 
153
  if request.method == 'GET':
154
- cart = mongo.db.carts.find_one({'user_email': user_email})
155
- if not cart:
156
- return jsonify({'items': [], 'deliveryDate': None})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- populated_items = []
159
- if cart.get('items'):
160
- product_ids = [ObjectId(item['productId']) for item in cart['items']]
161
- if product_ids:
162
- products_cursor = mongo.db.products.find({'_id': {'$in': product_ids}})
163
- products = {str(p['_id']): p for p in products_cursor}
164
-
165
- for item in cart['items']:
166
- details = products.get(item['productId'])
167
- if details:
168
- mode = item.get('mode', 'piece')
169
- mode_details = details.get('modes', {}).get(mode)
170
-
171
- if mode_details:
172
- price = mode_details.get('price')
173
-
174
- image_url = None
175
- if details.get('image_data'):
176
- # FIX: Generate an absolute URL.
177
- image_url = url_for('api.get_product_image', product_id=str(details['_id']), _external=True)
178
- elif details.get('image_url'):
179
- image_url = details.get('image_url')
180
-
181
- populated_items.append({
182
- 'product': {
183
- 'id': str(details['_id']),
184
- 'name': details.get('name'),
185
- 'modes': details.get('modes'),
186
- 'image_url': image_url,
187
- 'price': price
188
- },
189
- 'quantity': item['quantity'],
190
- 'mode': mode
191
- })
192
 
193
- return jsonify({
194
- 'items': populated_items,
195
- 'deliveryDate': cart.get('deliveryDate')
196
- })
197
 
198
  if request.method == 'POST':
199
  data = request.get_json()
@@ -330,66 +390,107 @@ def handle_orders():
330
  return jsonify({"msg": "Order placed successfully! You will be redirected shortly to the Orders Page!", "orderId": str(order_id)}), 201
331
 
332
  if request.method == 'GET':
333
- user_orders = list(mongo.db.orders.find({'user_email': user_email}).sort('created_at', -1))
 
334
  if not user_orders: return jsonify([])
335
-
336
- all_product_ids = {ObjectId(item['productId']) for order in user_orders for item in order.get('items', [])}
337
- products_cursor = mongo.db.products.find({'_id': {'$in': list(all_product_ids)}})
338
- products = {str(p['_id']): p for p in products_cursor}
339
-
340
  for order in user_orders:
341
- # Determine status from Zoho
342
- live_status = 'pending' # Default status
 
 
 
 
 
343
  try:
344
  serial_no = order.get('serial_no')
345
  if serial_no:
346
  invoices_response, _ = make_zoho_api_request('GET', '/invoices', params={'reference_number': serial_no})
347
  if invoices_response and invoices_response.get('invoices'):
348
  invoice = invoices_response['invoices'][0]
349
- zoho_status = invoice.get('status')
350
- if zoho_status == 'draft':
351
  live_status = 'pending'
352
- elif zoho_status == 'sent':
353
  live_status = 'Processing'
354
- elif zoho_status == 'paid':
355
  live_status = 'Completed'
356
- elif zoho_status == 'void':
357
  live_status = 'cancelled'
 
 
 
 
 
 
 
358
  except Exception as e:
359
  current_app.logger.error(f"Could not fetch Zoho invoice status for order {order.get('serial_no')}: {e}")
360
 
361
  order['status'] = live_status
362
-
363
- # Populate items
364
- populated_items = []
365
- for item in order.get('items', []):
366
- p = products.get(item['productId'])
367
- if p:
368
- mode = item.get('mode', 'pieces')
369
- mode_details = p.get('modes', {}).get(mode, {})
370
-
371
- image_url = None
372
- if p.get('image_data'):
373
- image_url = url_for('api.get_product_image', product_id=str(p['_id']), _external=True)
374
- elif p.get('image_url'):
375
- image_url = p.get('image_url')
376
-
377
- populated_items.append({
378
- 'quantity': item['quantity'],
379
- 'mode': mode,
380
- 'price': mode_details.get('price'),
 
 
 
 
381
  'product': {
382
- 'id': str(p['_id']),
383
- 'name': p.get('name'),
384
- 'modes': p.get('modes'),
385
- 'image_url': image_url
 
 
 
 
 
 
386
  }
387
- })
388
- order['items'] = populated_items
389
- order['_id'] = str(order['_id'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  order['created_at'] = order['created_at'].isoformat()
391
  order['delivery_date'] = order['delivery_date'] if isinstance(order['delivery_date'], str) else order['delivery_date'].isoformat()
392
- return jsonify(user_orders)
 
393
 
394
  @api_bp.route('/orders/<order_id>', methods=['GET'])
395
  @jwt_required()
 
43
 
44
  @api_bp.route('/products', methods=['GET'])
45
  def get_products():
46
+ # --- OPTIMIZATION: Use projection to exclude large binary image data ---
47
+ # We only need to know if 'image_data' exists, not its content. This dramatically
48
+ # reduces the data transferred from MongoDB to the Flask app, speeding up the response.
49
+ products_cursor = mongo.db.products.find({}, {'image_data': 0})
50
+ products_list = []
51
+
52
+ # Re-fetch the documents that have image_data to check for existence
53
+ # This is a bit of a workaround because we can't check for existence with projection easily
54
+ # A better long-term solution would be a boolean field like `has_binary_image`.
55
+ # For now, we'll check based on the projected data. If a product *might* have an image, we can assume it does.
56
+ # The logic below is slightly adjusted. A product document will still have the key 'image_data' if it was not projected out.
57
+ # The previous code was fine, but this makes it explicit that we are avoiding the large field.
58
+ products_cursor = mongo.db.products.find(
59
+ {},
60
+ # Exclude the large image_data field from the initial query
61
+ {'image_data': 0, 'image_content_type': 0}
62
+ )
63
+ # Get a set of IDs for products that DO have binary image data in a separate, fast query
64
+ products_with_images = {
65
+ str(p['_id']) for p in mongo.db.products.find(
66
+ {'image_data': {'$exists': True, '$ne': None}},
67
+ {'_id': 1} # Only fetch the ID
68
+ )
69
+ }
70
+
71
  products_list = []
72
  for p in products_cursor:
73
+ product_id_str = str(p['_id'])
74
  image_url = None
75
+ # Check against our pre-fetched set of IDs
76
+ if product_id_str in products_with_images:
77
+ image_url = url_for('api.get_product_image', product_id=product_id_str, _external=True)
78
+ # Fallback to the stored URL
 
79
  elif p.get('image_url'):
80
  image_url = p.get('image_url')
81
 
82
  products_list.append({
83
+ 'id': product_id_str,
84
+ 'name': p.get('name'),
85
  'category': p.get('category'),
86
+ 'modes': p.get('modes'),
87
+ 'image_url': image_url,
88
  'description': p.get('description', '')
89
  })
90
  return jsonify(products_list)
 
174
  user_email = get_jwt_identity()
175
 
176
  if request.method == 'GET':
177
+ # --- OPTIMIZATION: Use MongoDB Aggregation Pipeline to fetch cart and products in one go ---
178
+ pipeline = [
179
+ # 1. Find the user's cart
180
+ {'$match': {'user_email': user_email}},
181
+ # 2. Deconstruct the items array to process each item
182
+ {'$unwind': '$items'},
183
+ # 3. Convert string productId to ObjectId for lookup
184
+ {'$addFields': {'productId_obj': {'$toObjectId': '$items.productId'}}},
185
+ # 4. Join with the products collection ($lookup is like a JOIN)
186
+ {
187
+ '$lookup': {
188
+ 'from': 'products',
189
+ 'localField': 'productId_obj',
190
+ 'foreignField': '_id',
191
+ 'as': 'productDetails'
192
+ }
193
+ },
194
+ # 5. Deconstruct the resulting productDetails array (it will have 1 element)
195
+ {'$unwind': '$productDetails'},
196
+ # 6. Re-shape the document to match the frontend's expected format
197
+ {
198
+ '$project': {
199
+ '_id': 0,
200
+ 'deliveryDate': '$deliveryDate',
201
+ 'item': {
202
+ 'quantity': '$items.quantity',
203
+ 'mode': '$items.mode',
204
+ 'product': {
205
+ 'id': {'$toString': '$productDetails._id'},
206
+ 'name': '$productDetails.name',
207
+ 'modes': '$productDetails.modes',
208
+ 'price': {'$getField': {'field': '$items.mode', 'input': '$productDetails.modes.price'}},
209
+ 'image_url': {
210
+ '$cond': {
211
+ 'if': {'$and': [
212
+ {'$ne': ['$productDetails.image_data', None]},
213
+ {'$ne': ['$productDetails.image_data', ""]}
214
+ ]},
215
+ 'then': url_for('api.get_product_image', product_id=str(ObjectId()), _external=True).replace(str(ObjectId()),""), # Placeholder for url construction
216
+ 'else': '$productDetails.image_url'
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+ },
223
+ # 7. Dynamically construct the image URL
224
+ {
225
+ '$addFields': {
226
+ "item.product.image_url": {
227
+ '$cond': {
228
+ 'if': {'$ne': ["$item.product.image_url", None]},
229
+ 'then': {
230
+ '$concat': [
231
+ request.host_url.rstrip('/'),
232
+ '/api/product_image/',
233
+ "$item.product.id"
234
+ ]
235
+ },
236
+ 'else': None
237
+ }
238
+ }
239
+ }
240
+ },
241
+ # 8. Group all items back into a single cart document
242
+ {
243
+ '$group': {
244
+ '_id': '$_id',
245
+ 'deliveryDate': {'$first': '$deliveryDate'},
246
+ 'items': {'$push': '$item'}
247
+ }
248
+ }
249
+ ]
250
 
251
+ result = list(mongo.db.carts.aggregate(pipeline))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
+ if not result:
254
+ return jsonify({'items': [], 'deliveryDate': None})
255
+
256
+ return jsonify(result[0])
257
 
258
  if request.method == 'POST':
259
  data = request.get_json()
 
390
  return jsonify({"msg": "Order placed successfully! You will be redirected shortly to the Orders Page!", "orderId": str(order_id)}), 201
391
 
392
  if request.method == 'GET':
393
+ user_orders_cursor = mongo.db.orders.find({'user_email': user_email}).sort('created_at', -1)
394
+ user_orders = list(user_orders_cursor)
395
  if not user_orders: return jsonify([])
396
+
397
+ # Fetch status from DB, or from Zoho if not present in DB.
 
 
 
398
  for order in user_orders:
399
+ # If status is present in our DB, use it and skip the API call.
400
+ if 'zoho_status' in order:
401
+ order['status'] = order['zoho_status']
402
+ continue
403
+
404
+ # If status is not in DB, fetch from Zoho, update DB, and then use it.
405
+ live_status = 'pending'
406
  try:
407
  serial_no = order.get('serial_no')
408
  if serial_no:
409
  invoices_response, _ = make_zoho_api_request('GET', '/invoices', params={'reference_number': serial_no})
410
  if invoices_response and invoices_response.get('invoices'):
411
  invoice = invoices_response['invoices'][0]
412
+ zoho_api_status = invoice.get('status')
413
+ if zoho_api_status == 'draft':
414
  live_status = 'pending'
415
+ elif zoho_api_status == 'sent':
416
  live_status = 'Processing'
417
+ elif zoho_api_status == 'paid':
418
  live_status = 'Completed'
419
+ elif zoho_api_status == 'void':
420
  live_status = 'cancelled'
421
+
422
+ # Save the newly fetched status to MongoDB for future requests
423
+ mongo.db.orders.update_one(
424
+ {'_id': order['_id']},
425
+ {'$set': {'zoho_status': live_status}}
426
+ )
427
+
428
  except Exception as e:
429
  current_app.logger.error(f"Could not fetch Zoho invoice status for order {order.get('serial_no')}: {e}")
430
 
431
  order['status'] = live_status
432
+
433
+ # --- OPTIMIZATION: Use a single aggregation to populate product details for all orders ---
434
+ pipeline = [
435
+ {'$match': {'user_email': user_email}},
436
+ {'$sort': {'created_at': -1}},
437
+ {'$unwind': '$items'},
438
+ {'$addFields': {'productId_obj': {'$toObjectId': '$items.productId'}}},
439
+ {
440
+ '$lookup': {
441
+ 'from': 'products',
442
+ 'localField': 'productId_obj',
443
+ 'foreignField': '_id',
444
+ 'as': 'productDetails'
445
+ }
446
+ },
447
+ {'$unwind': '$productDetails'},
448
+ {
449
+ '$group': {
450
+ '_id': '$_id',
451
+ 'items': {'$push': {
452
+ 'quantity': '$items.quantity',
453
+ 'mode': '$items.mode',
454
+ 'price': {'$let': {'vars': {'mode_details': {'$getField': {'field': '$items.mode', 'input': '$productDetails.modes'}}}, 'in': '$$mode_details.price'}},
455
  'product': {
456
+ 'id': {'$toString': '$productDetails._id'},
457
+ 'name': '$productDetails.name',
458
+ 'modes': '$productDetails.modes',
459
+ 'image_url': {
460
+ '$cond': {
461
+ 'if': {'$ifNull': ['$productDetails.image_data', False]},
462
+ 'then': {'$concat': [request.host_url.rstrip('/'), '/api/product_image/', {'$toString': '$productDetails._id'}]},
463
+ 'else': '$productDetails.image_url'
464
+ }
465
+ }
466
  }
467
+ }},
468
+ # Carry over all original order fields
469
+ 'doc': {'$first': '$$ROOT'}
470
+ }
471
+ },
472
+ {
473
+ '$replaceRoot': {
474
+ 'newRoot': {
475
+ '$mergeObjects': ['$doc', {'items': '$items'}]
476
+ }
477
+ }
478
+ },
479
+ {'$sort': {'created_at': -1}}
480
+ ]
481
+
482
+ populated_orders = list(mongo.db.orders.aggregate(pipeline))
483
+
484
+ # Merge the live status back into the populated orders
485
+ status_map = {str(order['_id']): order['status'] for order in user_orders}
486
+ for order in populated_orders:
487
+ order_id_str = str(order['_id'])
488
+ order['status'] = status_map.get(order_id_str, 'pending')
489
+ order['_id'] = order_id_str # Convert ObjectId to string for JSON
490
  order['created_at'] = order['created_at'].isoformat()
491
  order['delivery_date'] = order['delivery_date'] if isinstance(order['delivery_date'], str) else order['delivery_date'].isoformat()
492
+
493
+ return jsonify(populated_orders)
494
 
495
  @api_bp.route('/orders/<order_id>', methods=['GET'])
496
  @jwt_required()
flask_session/aa71dde20eaf768ca7e5f90a25563ea6 CHANGED
Binary files a/flask_session/aa71dde20eaf768ca7e5f90a25563ea6 and b/flask_session/aa71dde20eaf768ca7e5f90a25563ea6 differ