CineDev commited on
Commit
a7b5683
·
1 Parent(s): 472581f

Refactor mobile money asset positioning and sync backend engines

Browse files
ai_assistant/views.py CHANGED
@@ -31,14 +31,14 @@ class ChatbotView(APIView):
31
 
32
  context_prompt = f"""You are Aureon's premium AI Financial Assistant. You give concise, professional, and helpful financial advice.
33
  User Profile:
34
- - Available Cash: ${cash_available}
35
- - Net Worth: ${net_worth}
36
  Active Budgets:
37
  {budget_context if budget_context else "No active budgets."}
38
  Recent Transactions:
39
  {tx_context if tx_context else "No recent transactions."}
40
 
41
- Based strictly on this data, answer the user's question. Do not make up data not present here.
42
  User Question: "{user_message}"
43
  """
44
 
@@ -101,8 +101,8 @@ class AIInsightsView(APIView):
101
 
102
  context_prompt = f"""You are Aureon's premium AI Financial Assistant. Based on the user's financial profile, generate exactly three helpful financial insights.
103
  User Profile:
104
- - Available Cash: ${cash_available}
105
- - Net Worth: ${net_worth}
106
  Active Budgets:
107
  {budget_context if budget_context else "No active budgets."}
108
  Recent Transactions:
@@ -113,14 +113,14 @@ Provide the output strictly as a JSON array of three objects. Do not include mar
113
  - "type": one of "success", "warning", "suggestion", "pattern"
114
  - "title": a very short title
115
  - "message": a helpful one-sentence message
116
- - "savings": optional, an integer number of potential savings in dollars (e.g. 42)
117
  - "detail": a short secondary detail string (e.g. "Keep it up!")
118
  - "options": optional array of 2 strings if type is "suggestion"
119
 
120
  Example:
121
  [
122
  {{"id": 1, "type": "success", "title": "Great news!", "message": "You spent 15% less this week on food.", "savings": 25, "detail": "Keep it up!"}},
123
- {{"id": 2, "type": "warning", "title": "Watch out!", "message": "Your subscriptions total $45 this month.", "detail": "Consider cancelling unused ones."}},
124
  {{"id": 3, "type": "suggestion", "title": "Smart Suggestion", "message": "You have extra cash.", "options": ["Invest it", "Add to goal"]}}
125
  ]
126
  """
 
31
 
32
  context_prompt = f"""You are Aureon's premium AI Financial Assistant. You give concise, professional, and helpful financial advice.
33
  User Profile:
34
+ - Available Cash: {cash_available}
35
+ - Net Worth: {net_worth}
36
  Active Budgets:
37
  {budget_context if budget_context else "No active budgets."}
38
  Recent Transactions:
39
  {tx_context if tx_context else "No recent transactions."}
40
 
41
+ Based strictly on this data, answer the user's question in rupees (₹). Do not make up data not present here.
42
  User Question: "{user_message}"
43
  """
44
 
 
101
 
102
  context_prompt = f"""You are Aureon's premium AI Financial Assistant. Based on the user's financial profile, generate exactly three helpful financial insights.
103
  User Profile:
104
+ - Available Cash: {cash_available}
105
+ - Net Worth: {net_worth}
106
  Active Budgets:
107
  {budget_context if budget_context else "No active budgets."}
108
  Recent Transactions:
 
113
  - "type": one of "success", "warning", "suggestion", "pattern"
114
  - "title": a very short title
115
  - "message": a helpful one-sentence message
116
+ - "savings": optional, an integer number of potential savings in rupees (e.g. 42)
117
  - "detail": a short secondary detail string (e.g. "Keep it up!")
118
  - "options": optional array of 2 strings if type is "suggestion"
119
 
120
  Example:
121
  [
122
  {{"id": 1, "type": "success", "title": "Great news!", "message": "You spent 15% less this week on food.", "savings": 25, "detail": "Keep it up!"}},
123
+ {{"id": 2, "type": "warning", "title": "Watch out!", "message": "Your subscriptions total 45 this month.", "detail": "Consider cancelling unused ones."}},
124
  {{"id": 3, "type": "suggestion", "title": "Smart Suggestion", "message": "You have extra cash.", "options": ["Invest it", "Add to goal"]}}
125
  ]
126
  """
aureon_backend/__pycache__/settings.cpython-314.pyc CHANGED
Binary files a/aureon_backend/__pycache__/settings.cpython-314.pyc and b/aureon_backend/__pycache__/settings.cpython-314.pyc differ
 
finance/category_engine.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+
4
+ CATEGORY_RULES = [
5
+ {
6
+ "key": "income",
7
+ "name": "Income",
8
+ "patterns": [
9
+ "salary",
10
+ "payroll",
11
+ "paycheck",
12
+ "credited",
13
+ "deposit",
14
+ "interest",
15
+ "refund",
16
+ ],
17
+ "positive_only": True,
18
+ },
19
+ {
20
+ "key": "dining",
21
+ "name": "Food & Dining",
22
+ "patterns": [
23
+ "zomato",
24
+ "swiggy",
25
+ "mcdonald",
26
+ "domino",
27
+ "pizza",
28
+ "restaurant",
29
+ "cafe",
30
+ "burger",
31
+ "kfc",
32
+ "subway",
33
+ "dining",
34
+ ],
35
+ },
36
+ {
37
+ "key": "coffee",
38
+ "name": "Coffee & Cafes",
39
+ "patterns": ["starbucks", "coffee", "ccd", "barista"],
40
+ },
41
+ {
42
+ "key": "groceries",
43
+ "name": "Groceries",
44
+ "patterns": [
45
+ "grocery",
46
+ "groceries",
47
+ "dmart",
48
+ "bigbasket",
49
+ "blinkit",
50
+ "zepto",
51
+ "walmart",
52
+ "target",
53
+ "whole foods",
54
+ "supermarket",
55
+ ],
56
+ },
57
+ {
58
+ "key": "transportation",
59
+ "name": "Transportation",
60
+ "patterns": [
61
+ "uber",
62
+ "ola",
63
+ "rapido",
64
+ "metro",
65
+ "fuel",
66
+ "petrol",
67
+ "gas",
68
+ "shell",
69
+ "parking",
70
+ "toll",
71
+ ],
72
+ },
73
+ {
74
+ "key": "entertainment",
75
+ "name": "Entertainment",
76
+ "patterns": [
77
+ "netflix",
78
+ "spotify",
79
+ "prime",
80
+ "hotstar",
81
+ "bookmyshow",
82
+ "cinema",
83
+ "movie",
84
+ "youtube",
85
+ ],
86
+ },
87
+ {
88
+ "key": "shopping",
89
+ "name": "Shopping",
90
+ "patterns": [
91
+ "amazon",
92
+ "flipkart",
93
+ "myntra",
94
+ "ajio",
95
+ "nykaa",
96
+ "shopping",
97
+ "store",
98
+ "mall",
99
+ ],
100
+ },
101
+ {
102
+ "key": "healthcare",
103
+ "name": "Healthcare",
104
+ "patterns": [
105
+ "pharmacy",
106
+ "medical",
107
+ "hospital",
108
+ "clinic",
109
+ "doctor",
110
+ "apollo",
111
+ "1mg",
112
+ "pharmeasy",
113
+ ],
114
+ },
115
+ {
116
+ "key": "education",
117
+ "name": "Education",
118
+ "patterns": [
119
+ "school",
120
+ "college",
121
+ "tuition",
122
+ "course",
123
+ "udemy",
124
+ "coursera",
125
+ "book",
126
+ "exam",
127
+ ],
128
+ },
129
+ {
130
+ "key": "housing",
131
+ "name": "Housing",
132
+ "patterns": [
133
+ "rent",
134
+ "maintenance",
135
+ "electricity",
136
+ "water bill",
137
+ "gas bill",
138
+ "mortgage",
139
+ "society",
140
+ ],
141
+ },
142
+ ]
143
+
144
+
145
+ FALLBACK_CATEGORY = {"key": "miscellaneous", "name": "Miscellaneous"}
146
+
147
+
148
+ def normalize_text(*values):
149
+ text = " ".join(str(value or "") for value in values).lower()
150
+ return re.sub(r"\s+", " ", text).strip()
151
+
152
+
153
+ def categorize_transaction(merchant, note="", amount=None):
154
+ text = normalize_text(merchant, note)
155
+ numeric_amount = None
156
+
157
+ try:
158
+ numeric_amount = float(amount) if amount is not None else None
159
+ except (TypeError, ValueError):
160
+ numeric_amount = None
161
+
162
+ for rule in CATEGORY_RULES:
163
+ if rule.get("positive_only") and numeric_amount is not None and numeric_amount <= 0:
164
+ continue
165
+
166
+ if any(pattern in text for pattern in rule["patterns"]):
167
+ return {
168
+ "category": rule["name"],
169
+ "category_key": rule["key"],
170
+ "confidence": "high",
171
+ "matched_rule": rule["key"],
172
+ }
173
+
174
+ if numeric_amount is not None and numeric_amount > 0:
175
+ return {
176
+ "category": "Income",
177
+ "category_key": "income",
178
+ "confidence": "medium",
179
+ "matched_rule": "positive_amount",
180
+ }
181
+
182
+ return {
183
+ "category": FALLBACK_CATEGORY["name"],
184
+ "category_key": FALLBACK_CATEGORY["key"],
185
+ "confidence": "low",
186
+ "matched_rule": None,
187
+ }
188
+
189
+
190
+ def should_auto_categorize(category=None, category_key=None):
191
+ generic_values = {"", None, "other", "misc", "miscellaneous", "uncategorized"}
192
+ normalized_category = category.lower() if isinstance(category, str) else category
193
+ normalized_key = category_key.lower() if isinstance(category_key, str) else category_key
194
+ return normalized_key in generic_values or normalized_category in generic_values
finance/serializers.py CHANGED
@@ -6,6 +6,10 @@ class TransactionSerializer(serializers.ModelSerializer):
6
  model = Transaction
7
  fields = '__all__'
8
  read_only_fields = ('user',)
 
 
 
 
9
 
10
  class BudgetSerializer(serializers.ModelSerializer):
11
  class Meta:
 
6
  model = Transaction
7
  fields = '__all__'
8
  read_only_fields = ('user',)
9
+ extra_kwargs = {
10
+ 'category': {'required': False, 'allow_blank': True},
11
+ 'category_key': {'required': False, 'allow_blank': True},
12
+ }
13
 
14
  class BudgetSerializer(serializers.ModelSerializer):
15
  class Meta:
finance/views.py CHANGED
@@ -4,6 +4,7 @@ from rest_framework.decorators import action
4
  from django.db.models import Sum
5
  from .models import Transaction, Budget, Goal, Subscription
6
  from .serializers import TransactionSerializer, BudgetSerializer, GoalSerializer, SubscriptionSerializer
 
7
 
8
  class TransactionViewSet(viewsets.ModelViewSet):
9
  serializer_class = TransactionSerializer
@@ -13,6 +14,22 @@ class TransactionViewSet(viewsets.ModelViewSet):
13
  return Transaction.objects.filter(user=self.request.user)
14
 
15
  def perform_create(self, serializer):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  serializer.save(user=self.request.user)
17
 
18
  class BudgetViewSet(viewsets.ModelViewSet):
@@ -59,4 +76,3 @@ class SubscriptionViewSet(viewsets.ModelViewSet):
59
 
60
  def perform_create(self, serializer):
61
  serializer.save(user=self.request.user)
62
-
 
4
  from django.db.models import Sum
5
  from .models import Transaction, Budget, Goal, Subscription
6
  from .serializers import TransactionSerializer, BudgetSerializer, GoalSerializer, SubscriptionSerializer
7
+ from .category_engine import categorize_transaction, should_auto_categorize
8
 
9
  class TransactionViewSet(viewsets.ModelViewSet):
10
  serializer_class = TransactionSerializer
 
14
  return Transaction.objects.filter(user=self.request.user)
15
 
16
  def perform_create(self, serializer):
17
+ category = serializer.validated_data.get('category')
18
+ category_key = serializer.validated_data.get('category_key')
19
+
20
+ if should_auto_categorize(category, category_key):
21
+ prediction = categorize_transaction(
22
+ serializer.validated_data.get('merchant'),
23
+ serializer.validated_data.get('note'),
24
+ serializer.validated_data.get('amount'),
25
+ )
26
+ serializer.save(
27
+ user=self.request.user,
28
+ category=prediction['category'],
29
+ category_key=prediction['category_key'],
30
+ )
31
+ return
32
+
33
  serializer.save(user=self.request.user)
34
 
35
  class BudgetViewSet(viewsets.ModelViewSet):
 
76
 
77
  def perform_create(self, serializer):
78
  serializer.save(user=self.request.user)
 
users/__pycache__/models.cpython-314.pyc CHANGED
Binary files a/users/__pycache__/models.cpython-314.pyc and b/users/__pycache__/models.cpython-314.pyc differ