LogicGoInfotechSpaces commited on
Commit
fb2a74d
·
verified ·
1 Parent(s): 251c9b0

Update app/smart_recommendation.py

Browse files
Files changed (1) hide show
  1. app/smart_recommendation.py +78 -19
app/smart_recommendation.py CHANGED
@@ -69,17 +69,22 @@ class SmartBudgetRecommender:
69
  avg_expense = data["average_monthly"]
70
  confidence = self._calculate_confidence(data)
71
 
72
- # 1) Try OpenAI first (primary source of recommendation)
73
  ai_result = self._get_ai_recommendation(category, data, avg_expense)
74
- if ai_result:
75
  recommended_budget = ai_result.get("recommended_budget")
76
- reason = ai_result.get("reason")
77
  action = ai_result.get("action")
 
78
  else:
79
- # 2) Fallback to rule-based recommendation
80
  recommended_budget = self._calculate_recommended_budget(avg_expense, data)
81
  reason = self._generate_reason(category, avg_expense, recommended_budget)
82
  action = None
 
 
 
 
83
 
84
  recommendations.append(BudgetRecommendation(
85
  category=category,
@@ -266,32 +271,85 @@ class SmartBudgetRecommender:
266
  We treat each budget document (e.g. \"Office Maintenance\", \"LOGICGO\")
267
  as a spending category and derive an \"average\" from its amounts.
268
  """
269
- # createdBy is stored as ObjectId in WalletSync, while user_id is a string.
270
- # Try to cast to ObjectId; if it fails, fall back to matching the raw string.
271
- query: Dict = {"status": "OPEN"}
 
272
  try:
273
- query["createdBy"] = ObjectId(user_id)
 
 
 
274
  except Exception:
275
- query["createdBy"] = user_id
276
-
277
- budgets = list(self.db.budgets.find(query))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
  if not budgets:
 
280
  return {}
281
 
 
 
282
  result: Dict[str, Dict] = {}
283
  for b in budgets:
284
- # Use budget \"name\" as category label
285
  category = b.get("name", "Uncategorized")
 
 
 
286
 
287
  # Derive a base amount from WalletSync fields
288
- max_amount = float(b.get("maxAmount", 0) or 0)
289
- spend_amount = float(b.get("spendAmount", 0) or 0)
290
-
291
- # If there is recorded spend, use that as \"average\"; otherwise maxAmount
292
- base_amount = spend_amount if spend_amount > 0 else max_amount
293
- if base_amount <= 0:
294
- continue
 
 
 
 
 
 
 
295
 
296
  if category not in result:
297
  result[category] = {
@@ -312,6 +370,7 @@ class SmartBudgetRecommender:
312
  )
313
  result[category]["monthly_values"].append(base_amount)
314
 
 
315
  return result
316
 
317
  def _get_ai_recommendation(self, category: str, data: Dict, avg_expense: float):
 
69
  avg_expense = data["average_monthly"]
70
  confidence = self._calculate_confidence(data)
71
 
72
+ # Always try OpenAI first (primary source of recommendation)
73
  ai_result = self._get_ai_recommendation(category, data, avg_expense)
74
+ if ai_result and ai_result.get("recommended_budget"):
75
  recommended_budget = ai_result.get("recommended_budget")
76
+ reason = ai_result.get("reason", f"AI recommendation for {category}")
77
  action = ai_result.get("action")
78
+ print(f"OpenAI recommendation for {category}: {recommended_budget}")
79
  else:
80
+ # Fallback to rule-based recommendation if OpenAI fails
81
  recommended_budget = self._calculate_recommended_budget(avg_expense, data)
82
  reason = self._generate_reason(category, avg_expense, recommended_budget)
83
  action = None
84
+ if not ai_result:
85
+ print(f"OpenAI unavailable, using rule-based for {category}: {recommended_budget}")
86
+ else:
87
+ print(f"OpenAI returned invalid data, using rule-based for {category}: {recommended_budget}")
88
 
89
  recommendations.append(BudgetRecommendation(
90
  category=category,
 
271
  We treat each budget document (e.g. \"Office Maintenance\", \"LOGICGO\")
272
  as a spending category and derive an \"average\" from its amounts.
273
  """
274
+ budgets = []
275
+
276
+ # Try multiple query patterns to find budgets
277
+ # Pattern 1: Try with ObjectId (most common in WalletSync)
278
  try:
279
+ query_objid = {"status": "OPEN", "createdBy": ObjectId(user_id)}
280
+ budgets_objid = list(self.db.budgets.find(query_objid))
281
+ if budgets_objid:
282
+ budgets.extend(budgets_objid)
283
  except Exception:
284
+ pass
285
+
286
+ # Pattern 2: Try with string user_id
287
+ try:
288
+ query_str = {"status": "OPEN", "createdBy": user_id}
289
+ budgets_str = list(self.db.budgets.find(query_str))
290
+ if budgets_str:
291
+ budgets.extend(budgets_str)
292
+ except Exception:
293
+ pass
294
+
295
+ # Pattern 3: Try with user_id field (alternative field name)
296
+ try:
297
+ query_userid = {"status": "OPEN", "user_id": user_id}
298
+ budgets_userid = list(self.db.budgets.find(query_userid))
299
+ if budgets_userid:
300
+ budgets.extend(budgets_userid)
301
+ except Exception:
302
+ pass
303
+
304
+ # Pattern 4: Try ObjectId with user_id field
305
+ try:
306
+ query_objid_userid = {"status": "OPEN", "user_id": ObjectId(user_id)}
307
+ budgets_objid_userid = list(self.db.budgets.find(query_objid_userid))
308
+ if budgets_objid_userid:
309
+ budgets.extend(budgets_objid_userid)
310
+ except Exception:
311
+ pass
312
+
313
+ # Remove duplicates based on _id
314
+ seen_ids = set()
315
+ unique_budgets = []
316
+ for b in budgets:
317
+ budget_id = str(b.get("_id", ""))
318
+ if budget_id not in seen_ids:
319
+ seen_ids.add(budget_id)
320
+ unique_budgets.append(b)
321
+
322
+ budgets = unique_budgets
323
 
324
  if not budgets:
325
+ print(f"No budgets found for user_id: {user_id}")
326
  return {}
327
 
328
+ print(f"Found {len(budgets)} budgets for user_id: {user_id}")
329
+
330
  result: Dict[str, Dict] = {}
331
  for b in budgets:
332
+ # Use budget "name" as category label
333
  category = b.get("name", "Uncategorized")
334
+ if not category or category == "Uncategorized":
335
+ # Try alternative field names
336
+ category = b.get("category") or b.get("title") or "Uncategorized"
337
 
338
  # Derive a base amount from WalletSync fields
339
+ # Try multiple field name variations
340
+ max_amount = float(b.get("maxAmount", 0) or b.get("max_amount", 0) or b.get("amount", 0) or 0)
341
+ spend_amount = float(b.get("spendAmount", 0) or b.get("spend_amount", 0) or b.get("spent", 0) or 0)
342
+ budget_amount = float(b.get("budget", 0) or b.get("budgetAmount", 0) or 0)
343
+
344
+ # Priority: spendAmount > maxAmount > budgetAmount > budget
345
+ if spend_amount > 0:
346
+ base_amount = spend_amount
347
+ elif max_amount > 0:
348
+ base_amount = max_amount
349
+ elif budget_amount > 0:
350
+ base_amount = budget_amount
351
+ else:
352
+ continue # Skip if no valid amount found
353
 
354
  if category not in result:
355
  result[category] = {
 
370
  )
371
  result[category]["monthly_values"].append(base_amount)
372
 
373
+ print(f"Processed {len(result)} budget categories for recommendations")
374
  return result
375
 
376
  def _get_ai_recommendation(self, category: str, data: Dict, avg_expense: float):