LogicGoInfotechSpaces commited on
Commit
e95b2a4
·
1 Parent(s): 57331b8

Add budget_amount parameter to recommendations/check endpoint to generate recommendations based on provided budget

Browse files
Smart_Budget_Recommendation_API.postman_collection.json CHANGED
@@ -169,7 +169,7 @@
169
  ],
170
  "body": {
171
  "mode": "raw",
172
- "raw": "{\n \"user_id\": \"68a834c3f4694b11efedacd2\",\n \"category_id\": \"688c80ca990b63f0e945ecf1\"\n}"
173
  },
174
  "url": {
175
  "raw": "{{base_url}}/recommendations/check?month=1&year=2026",
 
169
  ],
170
  "body": {
171
  "mode": "raw",
172
+ "raw": "{\n \"user_id\": \"6741abd38d30ab5b7176397f\",\n \"category_id\": \"677f6c117ca4500f15dbf108\",\n \"budget_amount\": 10000.0\n}"
173
  },
174
  "url": {
175
  "raw": "{{base_url}}/recommendations/check?month=1&year=2026",
app/main.py CHANGED
@@ -207,13 +207,15 @@ async def check_and_get_recommendations(request: RecommendationRequest, month: O
207
  # Check if user has previous data for this category
208
  has_data = recommender.check_user_has_category_data(request.user_id, request.category_id)
209
 
210
- if has_data:
211
  # Get recommendations for this specific category
 
212
  recommendations = recommender.get_recommendation_for_category(
213
  request.user_id,
214
  request.category_id,
215
  month,
216
- year
 
217
  )
218
 
219
  if recommendations:
@@ -230,11 +232,28 @@ async def check_and_get_recommendations(request: RecommendationRequest, month: O
230
  message="User has previous data but no recommendations could be generated for this category."
231
  )
232
  else:
233
- # User doesn't have previous data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  return RecommendationResponse(
235
  has_previous_data=False,
236
  recommendations=None,
237
- message=f"User does not have previous data for category_id: {request.category_id}. Please create a budget or add expenses for this category first."
238
  )
239
 
240
  @app.get("/recommendations/{user_id}", response_model=List[BudgetRecommendation])
 
207
  # Check if user has previous data for this category
208
  has_data = recommender.check_user_has_category_data(request.user_id, request.category_id)
209
 
210
+ if has_data or request.budget_amount:
211
  # Get recommendations for this specific category
212
+ # Pass budget_amount if provided
213
  recommendations = recommender.get_recommendation_for_category(
214
  request.user_id,
215
  request.category_id,
216
  month,
217
+ year,
218
+ request.budget_amount
219
  )
220
 
221
  if recommendations:
 
232
  message="User has previous data but no recommendations could be generated for this category."
233
  )
234
  else:
235
+ # User doesn't have previous data, but if budget_amount is provided, generate recommendation anyway
236
+ if request.budget_amount and request.budget_amount > 0:
237
+ recommendations = recommender.get_recommendation_for_category(
238
+ request.user_id,
239
+ request.category_id,
240
+ month,
241
+ year,
242
+ request.budget_amount
243
+ )
244
+
245
+ if recommendations:
246
+ return RecommendationResponse(
247
+ has_previous_data=False,
248
+ recommendations=recommendations,
249
+ message=f"Recommendation generated based on provided budget amount. User does not have previous data for this category."
250
+ )
251
+
252
+ # User doesn't have previous data and no budget_amount provided
253
  return RecommendationResponse(
254
  has_previous_data=False,
255
  recommendations=None,
256
+ message=f"User does not have previous data for category_id: {request.category_id}. Please provide a budget_amount or create a budget/expenses for this category first."
257
  )
258
 
259
  @app.get("/recommendations/{user_id}", response_model=List[BudgetRecommendation])
app/models.py CHANGED
@@ -44,6 +44,7 @@ class CategoryExpense(BaseModel):
44
  class RecommendationRequest(BaseModel):
45
  user_id: str = Field(..., description="User identifier")
46
  category_id: str = Field(..., description="Category ID to check for previous data")
 
47
 
48
  class RecommendationResponse(BaseModel):
49
  has_previous_data: bool
 
44
  class RecommendationRequest(BaseModel):
45
  user_id: str = Field(..., description="User identifier")
46
  category_id: str = Field(..., description="Category ID to check for previous data")
47
+ budget_amount: Optional[float] = Field(None, description="Current budget amount for this category (optional)")
48
 
49
  class RecommendationResponse(BaseModel):
50
  has_previous_data: bool
app/smart_recommendation.py CHANGED
@@ -3,7 +3,7 @@ import math
3
  import os
4
  from collections import defaultdict
5
  from datetime import datetime, timedelta
6
- from typing import Dict, List
7
 
8
  import requests
9
  from dotenv import load_dotenv
@@ -180,7 +180,7 @@ class SmartBudgetRecommender:
180
  print(f"Error checking user category data: {e}")
181
  return False
182
 
183
- def get_recommendation_for_category(self, user_id: str, category_id: str, month: int, year: int) -> List[BudgetRecommendation]:
184
  """
185
  Get budget recommendations for a specific category for a user.
186
 
@@ -189,6 +189,7 @@ class SmartBudgetRecommender:
189
  category_id: Category ID to get recommendations for
190
  month: Target month (1-12)
191
  year: Target year
 
192
 
193
  Returns:
194
  List of budget recommendations for the specific category
@@ -202,6 +203,57 @@ class SmartBudgetRecommender:
202
  if rec.category_id == category_id or str(rec.category_id) == str(category_id)
203
  ]
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  return filtered_recommendations
206
 
207
  def _calculate_category_statistics(self, expenses: List[Dict], start_date: datetime, end_date: datetime) -> Dict:
 
3
  import os
4
  from collections import defaultdict
5
  from datetime import datetime, timedelta
6
+ from typing import Dict, List, Optional
7
 
8
  import requests
9
  from dotenv import load_dotenv
 
180
  print(f"Error checking user category data: {e}")
181
  return False
182
 
183
+ def get_recommendation_for_category(self, user_id: str, category_id: str, month: int, year: int, budget_amount: Optional[float] = None) -> List[BudgetRecommendation]:
184
  """
185
  Get budget recommendations for a specific category for a user.
186
 
 
189
  category_id: Category ID to get recommendations for
190
  month: Target month (1-12)
191
  year: Target year
192
+ budget_amount: Optional current budget amount to use for recommendations
193
 
194
  Returns:
195
  List of budget recommendations for the specific category
 
203
  if rec.category_id == category_id or str(rec.category_id) == str(category_id)
204
  ]
205
 
206
+ # If budget_amount is provided and we have a recommendation, use it to generate a new recommendation
207
+ if budget_amount and budget_amount > 0 and filtered_recommendations:
208
+ # Get the first recommendation (should be the one for this category)
209
+ original_rec = filtered_recommendations[0]
210
+
211
+ # Get category name
212
+ category_name = original_rec.category
213
+
214
+ # Use the provided budget_amount as average_expense for comparison
215
+ avg_expense = budget_amount
216
+
217
+ # Create data structure for recommendation calculation
218
+ data = {
219
+ "average_monthly": avg_expense,
220
+ "total": avg_expense,
221
+ "count": 1,
222
+ "months_analyzed": 1,
223
+ "std_dev": 0.0,
224
+ "monthly_values": [avg_expense],
225
+ }
226
+
227
+ confidence = self._calculate_confidence(data)
228
+
229
+ # Always try OpenAI first (primary source of recommendation)
230
+ ai_result = self._get_ai_recommendation(category_name, data, avg_expense)
231
+ if ai_result and ai_result.get("recommended_budget"):
232
+ recommended_budget = ai_result.get("recommended_budget")
233
+ reason = ai_result.get("reason", f"AI recommendation for {category_name} based on your budget of Rs.{budget_amount:,.2f}")
234
+ action = ai_result.get("action")
235
+ print(f"✅ OpenAI recommendation for {category_name} (budget: {budget_amount}): {recommended_budget} (action: {action})")
236
+ else:
237
+ # Fallback to rule-based recommendation if OpenAI fails
238
+ recommended_budget = self._calculate_recommended_budget(avg_expense, data)
239
+ reason = self._generate_reason(category_name, avg_expense, recommended_budget)
240
+ action = None
241
+ if not ai_result:
242
+ print(f"❌ OpenAI unavailable (no API key or error), using rule-based for {category_name} (budget: {budget_amount}): {recommended_budget}")
243
+ else:
244
+ print(f"⚠️ OpenAI returned invalid data, using rule-based for {category_name} (budget: {budget_amount}): {recommended_budget}")
245
+
246
+ # Create new recommendation based on provided budget_amount
247
+ filtered_recommendations = [BudgetRecommendation(
248
+ category=category_name,
249
+ category_id=category_id,
250
+ average_expense=round(avg_expense, 2),
251
+ recommended_budget=round(recommended_budget or 0, 2),
252
+ reason=reason,
253
+ confidence=confidence,
254
+ action=action
255
+ )]
256
+
257
  return filtered_recommendations
258
 
259
  def _calculate_category_statistics(self, expenses: List[Dict], start_date: datetime, end_date: datetime) -> Dict: