rairo commited on
Commit
ce82bf0
·
verified ·
1 Parent(s): f16d3d1

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +166 -3
main.py CHANGED
@@ -102,6 +102,153 @@ If the text below does not specify a year or date, reasonable assume {current_da
102
  {FINANCIAL_DOC_PROMPT}
103
  """
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # -------------------------------------------------------------------------
106
  # HELPER FUNCTIONS
107
  # -------------------------------------------------------------------------
@@ -149,11 +296,27 @@ def call_gemini_with_retry(model, content, prompt, retries=2):
149
  response = model.generate_content([prompt, content])
150
 
151
  try:
152
- return extract_json_from_response(response.text)
 
 
 
 
 
 
 
 
153
  except ValueError as ve:
154
  # Value error here contains the broken JSON string
155
  broken_json = str(ve)
156
- return repair_json_with_gemini(model, broken_json)
 
 
 
 
 
 
 
 
157
 
158
  except Exception as e:
159
  if "429" in str(e) or "ResourceExhausted" in str(e):
@@ -414,7 +577,7 @@ def health_check():
414
  return jsonify({
415
  'status': 'healthy',
416
  'timestamp': datetime.now().isoformat(),
417
- 'version': '2.1.0',
418
  'vision_support': PDF_IMAGE_SUPPORT
419
  })
420
 
 
102
  {FINANCIAL_DOC_PROMPT}
103
  """
104
 
105
+ # -------------------------------------------------------------------------
106
+ # CATEGORIZATION LOGIC - TYPE-BASED (FIX FOR THE BUG)
107
+ # -------------------------------------------------------------------------
108
+
109
+ def categorize_transaction(transaction):
110
+ """
111
+ Categorizes a transaction based strictly on its Type field.
112
+ This prevents keyword-based misclassification.
113
+
114
+ Args:
115
+ transaction: dict with keys including 'Type', 'Description', 'Destination_of_funds'
116
+
117
+ Returns:
118
+ dict with added 'Account_Category' field
119
+ """
120
+ tx_type = transaction.get('Type', '').lower()
121
+ description = transaction.get('Description', '').lower()
122
+ destination = transaction.get('Destination_of_funds', '').lower()
123
+
124
+ # Add the categorized account field
125
+ account_category = "Uncategorized"
126
+
127
+ # ========== INCOME TYPE ==========
128
+ if tx_type == 'income':
129
+ # All income should map to revenue accounts, NOT expenses
130
+ if any(keyword in description for keyword in ['sales', 'service', 'revenue', 'invoice']):
131
+ account_category = "Sales Revenue"
132
+ elif any(keyword in description for keyword in ['interest', 'dividend']):
133
+ account_category = "Interest Income"
134
+ elif any(keyword in description for keyword in ['transfer', 'deposit', 'payment']):
135
+ # This fixes the "Income Trap" - transfers FROM others are income
136
+ account_category = "Other Income"
137
+ else:
138
+ account_category = "Other Income"
139
+
140
+ # ========== EXPENSE TYPE ==========
141
+ elif tx_type == 'expense':
142
+ # Map based on Destination_of_funds or description keywords
143
+ # This is TYPE-FIRST, so "cash" in description won't make it an asset
144
+
145
+ # Specific expense categories based on your system
146
+ if 'salaries' in destination or 'wages' in destination or 'salary' in description:
147
+ account_category = "Salaries and Wages"
148
+ elif 'water' in destination or 'electricity' in destination:
149
+ account_category = "Water and Electricity"
150
+ elif 'fuel' in destination or 'petrol' in description:
151
+ account_category = "Fuel"
152
+ elif 'rental' in destination or 'rent' in description:
153
+ account_category = "Rentals"
154
+ elif 'marketing' in destination or 'advertising' in destination:
155
+ account_category = "Advertising & Marketing"
156
+ elif 'repair' in destination or 'maintenance' in destination:
157
+ account_category = "Repairs & Maintenance"
158
+ elif 'vehicle' in destination or 'motor' in destination:
159
+ account_category = "Motor Vehicle Expenses"
160
+ elif 'hardware' in destination:
161
+ account_category = "Hardware Expenses"
162
+ elif 'accounting' in destination:
163
+ account_category = "Accounting Fees"
164
+ elif 'insurance' in destination:
165
+ account_category = "Insurance"
166
+ elif 'bank' in destination and 'charge' in destination:
167
+ account_category = "Bank Charges"
168
+ elif 'loan' in destination and 'interest' in destination:
169
+ account_category = "Loan Interest"
170
+ elif 'subscription' in destination:
171
+ account_category = "Subscriptions"
172
+ elif 'internet' in destination or 'telephone' in destination:
173
+ account_category = "Computer Internet and Telephone"
174
+ elif 'training' in destination:
175
+ account_category = "Staff Training"
176
+ elif 'travel' in destination or 'accommodation' in destination:
177
+ account_category = "Travel and Accommodation"
178
+ elif 'depreciation' in destination:
179
+ account_category = "Depreciation"
180
+
181
+ # Special cases based on description (but still respecting expense type)
182
+ elif 'atm' in description and 'cash' in description:
183
+ # This fixes the "Cash Trap" - ATM withdrawals are drawings, not assets
184
+ account_category = "Owner's Drawings"
185
+ elif 'payment to' in description:
186
+ # Payment to suppliers/vendors
187
+ if any(word in description for word in ['fabric', 'printing', 'material']):
188
+ account_category = "Cost of Sales"
189
+ else:
190
+ account_category = "Miscellaneous Expense"
191
+ else:
192
+ account_category = "Miscellaneous Expense"
193
+
194
+ # ========== ASSET TYPE ==========
195
+ elif tx_type == 'asset':
196
+ if 'equipment' in destination or 'equipment' in description:
197
+ account_category = "Equipment"
198
+ elif 'vehicle' in destination or 'vehicle' in description:
199
+ account_category = "Vehicles"
200
+ elif 'property' in destination or 'property' in description:
201
+ account_category = "Property"
202
+ elif 'technology' in destination or 'computer' in description:
203
+ account_category = "Technology"
204
+ elif 'furniture' in destination:
205
+ account_category = "Furniture"
206
+ else:
207
+ account_category = "Other Assets"
208
+
209
+ # ========== LIABILITY TYPE ==========
210
+ elif tx_type == 'liability':
211
+ if 'bank loan' in destination or 'loan' in description:
212
+ account_category = "Bank Loan"
213
+ elif 'credit' in destination:
214
+ account_category = "Credit Facility"
215
+ else:
216
+ account_category = "Other Liabilities"
217
+
218
+ # ========== EQUITY TYPE ==========
219
+ elif tx_type == 'equity':
220
+ if 'owner' in destination or 'capital' in description:
221
+ account_category = "Owner Investment"
222
+ elif 'retained' in destination:
223
+ account_category = "Retained Earnings"
224
+ else:
225
+ account_category = "Other Equity"
226
+
227
+ # ========== TRANSFER TYPE ==========
228
+ elif tx_type == 'transfer':
229
+ account_category = "Internal Transfer"
230
+
231
+ # ========== INVESTMENT TYPE ==========
232
+ elif tx_type == 'investment':
233
+ if 'securities' in destination or 'stock' in description:
234
+ account_category = "Securities"
235
+ elif 'mutual' in destination:
236
+ account_category = "Mutual Funds"
237
+ else:
238
+ account_category = "Other Investments"
239
+
240
+ # ========== LOAN REPAYMENT TYPE ==========
241
+ elif tx_type == 'loan_repayment':
242
+ account_category = "Loan Repayment"
243
+
244
+ # ========== CAPITAL INJECTION TYPE ==========
245
+ elif tx_type == 'capital_injection':
246
+ account_category = "Capital Injection"
247
+
248
+ # Add the category to the transaction
249
+ transaction['Account_Category'] = account_category
250
+ return transaction
251
+
252
  # -------------------------------------------------------------------------
253
  # HELPER FUNCTIONS
254
  # -------------------------------------------------------------------------
 
296
  response = model.generate_content([prompt, content])
297
 
298
  try:
299
+ result = extract_json_from_response(response.text)
300
+
301
+ # POST-PROCESSING: Categorize each transaction based on Type
302
+ if 'transactions' in result:
303
+ result['transactions'] = [
304
+ categorize_transaction(tx) for tx in result['transactions']
305
+ ]
306
+
307
+ return result
308
  except ValueError as ve:
309
  # Value error here contains the broken JSON string
310
  broken_json = str(ve)
311
+ repaired = repair_json_with_gemini(model, broken_json)
312
+
313
+ # Categorize repaired transactions too
314
+ if 'transactions' in repaired:
315
+ repaired['transactions'] = [
316
+ categorize_transaction(tx) for tx in repaired['transactions']
317
+ ]
318
+
319
+ return repaired
320
 
321
  except Exception as e:
322
  if "429" in str(e) or "ResourceExhausted" in str(e):
 
577
  return jsonify({
578
  'status': 'healthy',
579
  'timestamp': datetime.now().isoformat(),
580
+ 'version': '2.2.0',
581
  'vision_support': PDF_IMAGE_SUPPORT
582
  })
583