diff --git a/app/main.py b/app/main.py index 4d73cc8..cec68d2 100644 --- a/app/main.py +++ b/app/main.py @@ -416,7 +416,7 @@ async def process_document( user_location=request.user_location, ai_rules=ai_rules_list, ) - + logger.info(f"Extracted receipt data: {receipt_data}") # Parse date for database storage receipt_date = None if receipt_data.get("date"): diff --git a/app/services/ai_matcher.py b/app/services/ai_matcher.py index ac9f1b5..ba5437a 100644 --- a/app/services/ai_matcher.py +++ b/app/services/ai_matcher.py @@ -130,8 +130,7 @@ Candidate {i + 1}: - Amount difference: ${amount_diff} ({amount_percent_diff:.1f}%) """ - prompt = f""" -You are an expert at matching receipts to bank transactions. Analyze the receipt below against ALL the candidate transactions and return the BEST match. + prompt = f"""You are an expert at matching receipts to bank transactions. Analyze the receipt below against ALL the candidate transactions and return the BEST match. RECEIPT TO MATCH: - Vendor: {receipt.vendor} @@ -143,27 +142,39 @@ RECEIPT TO MATCH: CANDIDATE TRANSACTIONS: {candidates_text} -SCORING CRITERIA: -- Perfect matches (same vendor, amount, date): 0.95-1.0 -- High confidence (minor differences): 0.8-0.94 -- Medium confidence (moderate differences): 0.6-0.79 -- Low confidence (significant differences): 0.4-0.59 -- Very low confidence (major differences): 0.2-0.39 -- Minimal similarity: 0.1-0.19 -- No meaningful similarity: 0.0-0.09 +SCORING CRITERIA (Amount is the PRIMARY factor): -The most important factor to consider is the Amount for both the transaction and the receipt. The closer the amounts, the higher the score. If the amounts are different or not close return a low score (0-0.1) based on other factors. -Consider vendor name similarity, amount accuracy, date proximity, and description/notes relevance. +Amount Similarity (MOST IMPORTANT - 60% weight): +- Exact match or within 1%: Start at 0.9-1.0 +- Within 5%: Start at 0.75-0.89 +- Within 10%: Start at 0.5-0.74 +- Within 20%: Start at 0.3-0.49 +- More than 20% difference: Start at 0.0-0.29 -IMPORTANT: -You MUST return the candidate with the highest match score, even if it's very low. Never return NONE. -Return ONLY the best match in this exact format: -CANDIDATE_NUMBER|CONFIDENCE_SCORE|REASON +Then adjust UP or DOWN based on: +- Vendor similarity (20% weight): Exact or similar name increases score +- Date proximity (15% weight): Within 7 days increases score, within 30 days moderate increase +- Description/notes match (5% weight): Relevant keywords increase score -Example: 3|0.87|Same vendor name, exact amount match, 1 day apart -Example of low match: 5|0.15|Best available option despite significant differences in vendor and amount -""" +EXAMPLES: +- Amount match + vendor match + close date = 0.95-1.0 (Perfect match) +- Amount match + different vendor + close date = 0.85-0.94 (High confidence) +- Amount match + different vendor + far date = 0.70-0.84 (Medium-high confidence) +- Amount similar (5%) + vendor match = 0.75-0.85 (Medium-high confidence) +- Amount similar (10%) + some matches = 0.50-0.69 (Medium confidence) +- Amount very different (>20%) = 0.0-0.29 regardless of other factors +CRITICAL: You MUST return valid JSON only. No explanations, no text before or after. + +Return format: +{{"candidate_number": 1, "confidence_score": 0.87, "reason": "Exact amount match with similar vendor"}} + +Another example: +{{"candidate_number": 3, "confidence_score": 0.15, "reason": "Poor match but best available"}} + +Return ONLY JSON for the best candidate:""" + + logger.info(f"This is the prompt: {prompt}") for attempt in range(self.max_retries): try: result = self._call_groq_api_with_timeout( @@ -206,54 +217,92 @@ Example of low match: 5|0.15|Best available option despite significant differenc return None def _parse_single_match_response(self, result: str) -> Tuple[int, float, str]: - """Parse AI response for single best match""" + """Parse AI response for single best match (JSON format)""" + import json + import re + result = result.strip() logger.debug(f"Parsing single match response: {result}") try: - if result.upper().startswith("NONE"): - # This should not happen with new prompt, but handle as parsing error - logger.warning( - "AI returned NONE despite being instructed to always return best match" - ) - return -1, 0.0, "AI returned NONE unexpectedly" + # First, try to parse the entire result as JSON + try: + data = json.loads(result) + candidate_num = int(data.get("candidate_number", -1)) - 1 + score = float(data.get("confidence_score", 0.0)) + reason = str(data.get("reason", "No reason provided")) + score = max(0.0, min(1.0, score)) + logger.debug(f"Parsed JSON: candidate={candidate_num}, score={score}, reason={reason}") + return candidate_num, score, reason + except json.JSONDecodeError: + pass + + # Try to extract JSON object from the response using improved regex + # This handles nested braces better + json_pattern = r'\{[^{}]*"candidate_number"[^{}]*"confidence_score"[^{}]*"reason"[^{}]*\}' + json_match = re.search(json_pattern, result) + + if json_match: + json_str = json_match.group() + data = json.loads(json_str) + candidate_num = int(data.get("candidate_number", -1)) - 1 + score = float(data.get("confidence_score", 0.0)) + reason = str(data.get("reason", "No reason provided")) + score = max(0.0, min(1.0, score)) + logger.debug(f"Parsed extracted JSON: candidate={candidate_num}, score={score}, reason={reason}") + return candidate_num, score, reason + + # Try to find any JSON-like structure with the required fields + candidate_match = re.search(r'"candidate_number"\s*:\s*(\d+)', result) + score_match = re.search(r'"confidence_score"\s*:\s*([\d.]+)', result) + reason_match = re.search(r'"reason"\s*:\s*"([^"]*)"', result) + + if candidate_match and score_match and reason_match: + candidate_num = int(candidate_match.group(1)) - 1 + score = float(score_match.group(1)) + reason = reason_match.group(1) + score = max(0.0, min(1.0, score)) + logger.debug(f"Parsed fields individually: candidate={candidate_num}, score={score}, reason={reason}") + return candidate_num, score, reason - if "|" in result: - parts = result.split("|") - if len(parts) >= 3: - candidate_str = parts[0].strip() - score_str = parts[1].strip() - reason = "|".join(parts[2:]).strip() + except (json.JSONDecodeError, ValueError, KeyError) as e: + logger.warning(f"Error parsing JSON response: {e}") + + # Fallback to old pipe-delimited format for backwards compatibility + try: + if "|" in result: + parts = result.split("|") + if len(parts) >= 3: + candidate_str = parts[0].strip() + score_str = parts[1].strip() + reason = "|".join(parts[2:]).strip() - # Extract candidate number - import re + # Extract candidate number + candidate_match = re.search(r"\d+", candidate_str) + if candidate_match: + candidate_num = ( + int(candidate_match.group()) - 1 + ) # Convert to 0-based index + else: + raise ValueError("No candidate number found") - candidate_match = re.search(r"\d+", candidate_str) - if candidate_match: - candidate_num = ( - int(candidate_match.group()) - 1 - ) # Convert to 0-based index - else: - raise ValueError("No candidate number found") + # Extract score + score_clean = "".join( + c for c in score_str if c.isdigit() or c == "." + ) + score = float(score_clean) if score_clean else 0.0 - # Extract score - score_clean = "".join( - c for c in score_str if c.isdigit() or c == "." - ) - score = float(score_clean) if score_clean else 0.0 + # Ensure score is in valid range + score = max(0.0, min(1.0, score)) - # Ensure score is in valid range - score = max(0.0, min(1.0, score)) + logger.debug( + f"Parsed (fallback): candidate={candidate_num}, score={score}, reason={reason}" + ) + return candidate_num, score, reason + except Exception as fallback_error: + logger.warning(f"Fallback parsing also failed: {fallback_error}") - logger.debug( - f"Parsed: candidate={candidate_num}, score={score}, reason={reason}" - ) - return candidate_num, score, reason - - except Exception as e: - logger.warning(f"Error parsing single match response: {e}") - - # Fallback + # Final fallback logger.warning(f"Could not parse single match response: {result}") return -1, 0.0, f"Parse error: {result[:50]}..." @@ -455,8 +504,11 @@ Example of low match: 5|0.15|Best available option despite significant differenc try: response = self.client.chat.completions.create( model=self.model, - messages=[{"role": "user", "content": prompt}], - max_tokens=200, + messages=[ + {"role": "system", "content": "You are a JSON-only response assistant. Return only valid JSON, no explanations."}, + {"role": "user", "content": prompt} + ], + max_tokens=150, temperature=0.1, ) return response.choices[0].message.content.strip() diff --git a/app/services/document_processor.py b/app/services/document_processor.py index 9bc1321..028966c 100644 --- a/app/services/document_processor.py +++ b/app/services/document_processor.py @@ -2,6 +2,7 @@ import base64 import json import logging import os +import re from datetime import datetime from typing import Any, Dict @@ -125,23 +126,36 @@ class DocumentProcessor: # Build AI rules context for categorization ai_rules_context = "" if ai_rules and len(ai_rules) > 0: - ai_rules_context = "\n CATEGORIZATION RULES (IMPORTANT - Apply these first):" + # Create a simple, direct instruction for each rule + ai_rules_context = "\n " for idx, rule in enumerate(ai_rules, 1): condition = rule.get("condition", "") action = rule.get("action", "") - ai_rules_context += f"\n {idx}. If {condition} → set category to '{action}'" - ai_rules_context += "\n - Apply these custom rules before using default categorization logic\n - If multiple rules match, use the first matching rule\n - If no rules match, use default categorization based on vendor type" + + # Extract the keyword and category from the rule + keyword_match = re.search(r'CONTAINS\s+"([^"]+)"', condition, re.IGNORECASE) + category_match = re.search(r'SET_CATEGORY:\s*(.+)', action, re.IGNORECASE) + + if keyword_match and category_match: + keyword = keyword_match.group(1) + category = category_match.group(1).strip() + # Create one simple instruction per line + ai_rules_context += f'If the Vendor name contains "{keyword}": Set category to "{category}"\n ' + + ai_rules_context += "\n" # Create Groq vision prompt prompt = f""" - Analyze this receipt image and extract the following information in JSON format: + Analyze this receipt image and extract the following information in JSON format. + {ai_rules_context} + JSON Format: {{ "vendor": "Store/company name", "description": "Detailed description of items/services purchased", "total_amount": 0.00, "tax_amount": 0.00, "date": "YYYY-MM-DD", - "category": "Food/Transport/Office/Other", + "category": "Check rules above first", "confidence": 0.95, "currency": "USD", "location": "Province/State, Country", @@ -150,10 +164,11 @@ class DocumentProcessor: "name_of_asset": null, "cca_rate": null, "useful_life": null, - "residual_value": null + "residual_value": null, + "extraction_success": True }} - Rules: + EXTRACTION Rules: - Extract vendor name as it appears on receipt - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") - Total amount should be the final total including tax @@ -161,7 +176,7 @@ class DocumentProcessor: - Date should be the date on the receipt - Confidence score 0-1 based on how clear the receipt is - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") - {ai_rules_context} + {user_location_context} LOCATION & TAX RULES: - Extract location from receipt (look for store address, province/state, country) @@ -199,11 +214,9 @@ class DocumentProcessor: * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null - CATEGORY RULES: - - Assign the category based on all the details in the receipt Return only valid JSON. """ - + logger.info(f"This is the prompt: {prompt}") # Call Groq vision API with correct format response = self.client.chat.completions.create( messages=[ @@ -293,16 +306,27 @@ class DocumentProcessor: # Build AI rules context for categorization ai_rules_context = "" if ai_rules and len(ai_rules) > 0: - ai_rules_context = "\n CATEGORIZATION RULES (IMPORTANT - Apply these first):" + # Create a simple, direct instruction for each rule + ai_rules_context = "\n " for idx, rule in enumerate(ai_rules, 1): condition = rule.get("condition", "") action = rule.get("action", "") - ai_rules_context += f"\n {idx}. If {condition} → set category to '{action}'" - ai_rules_context += "\n - Apply these custom rules before using default categorization logic\n - If multiple rules match, use the first matching rule\n - If no rules match, use default categorization based on vendor type" + + # Extract the keyword and category from the rule + keyword_match = re.search(r'CONTAINS\s+"([^"]+)"', condition, re.IGNORECASE) + category_match = re.search(r'SET_CATEGORY:\s*(.+)', action, re.IGNORECASE) + + if keyword_match and category_match: + keyword = keyword_match.group(1) + category = category_match.group(1).strip() + # Create one simple instruction per line + ai_rules_context += f'If the Vendor name contains "{keyword}": Set category to "{category}"\n ' + + ai_rules_context += "\n" prompt = f""" - Analyze this receipt text and extract the following information in JSON format: - + Analyze this receipt text and extract the following information in JSON format. + {ai_rules_context} Receipt Text: {text_content} @@ -313,7 +337,7 @@ class DocumentProcessor: "total_amount": 0.00, "tax_amount": 0.00, "date": "YYYY-MM-DD", - "category": "Food/Transport/Office/Other", + "category": "Check rules above first", "confidence": 0.95, "currency": "USD", "location": "Province/State, Country", @@ -322,10 +346,11 @@ class DocumentProcessor: "name_of_asset": null, "cca_rate": null, "useful_life": null, - "residual_value": null + "residual_value": null, + "extraction_success": True }} - Rules: + EXTRACTION Rules: - Extract vendor name as it appears on receipt - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") - Total amount should be the final total including tax @@ -333,7 +358,6 @@ class DocumentProcessor: - Date should be the date on the receipt - Confidence score 0-1 based on clarity - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") - {ai_rules_context} {user_location_context} LOCATION & TAX RULES: - Extract location from receipt (look for store address, province/state, country) diff --git a/nohup.out b/nohup.out index 21c1401..c2ac1af 100644 --- a/nohup.out +++ b/nohup.out @@ -1,669 +1,1476 @@ -/root/ds_quickbooks_v2/app/main.py:59: DeprecationWarning: - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - - @app.on_event("startup") -INFO: Started server process [4970] -INFO: Waiting for application startup. -INFO:__main__:Starting up application... -INFO:database:Creating database tables... -INFO:database:Database tables created successfully -INFO:__main__:Application startup complete -INFO: Application startup complete. -INFO: Uvicorn running on http://0.0.0.0:8654 (Press CTRL+C to quit) -INFO: 199.241.139.243:38840 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 199.241.139.243:29402 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 199.241.139.243:49028 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 199.241.139.243:49032 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 199.241.139.243:49042 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 199.241.139.243:35192 - "POST /match-specific HTTP/1.1" 422 Unprocessable Entity -INFO: 199.241.139.243:22014 - "POST /match-specific HTTP/1.1" 422 Unprocessable Entity -INFO: 199.241.139.243:26982 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO: 102.89.33.59:2322 - "POST /match-specific HTTP/1.1" 422 Unprocessable Entity -INFO: 102.89.33.59:10508 - "POST /match-specific HTTP/1.1" 422 Unprocessable Entity -INFO:__main__:Starting match-specific for file IDs: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'], categorization_id: cat_mgi2e9m7_omxcrq -INFO:__main__:Found 54 transactions in database -INFO:__main__:Converted 54 transactions -WARNING:__main__:Receipt 96badce5-2768-4ab2-a708-17d8353c3667 not found in database -WARNING:__main__:Receipt 665f2d12-ba51-489a-b846-658ea59e5ea3 not found in database -WARNING:__main__:Receipt 51483eff-dfda-4377-a85f-ce77446d70b8 not found in database -WARNING:__main__:Receipt 9462694d-6f8f-4516-9b0b-161e391df6a7 not found in database -WARNING:__main__:Receipt c1b2ddad-fa3f-48c4-800a-054b1f6f8762 not found in database -WARNING:__main__:Receipt 6a2517c7-197e-490b-afb3-954836a75679 not found in database -WARNING:__main__:Receipt 0dcb6147-971b-4610-ac06-a96055a18350 not found in database -WARNING:__main__:Receipt c853353f-629e-4da0-98de-56da941132c2 not found in database -WARNING:__main__:Receipt 4dbfe025-232e-42f3-9315-dd0b80d7077a not found in database -WARNING:__main__:Receipt 37dc67ed-3e47-4970-8059-5b0d0d913f63 not found in database -INFO:__main__:Found 0 receipts, 10 missing -WARNING:__main__:Missing files: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'] -WARNING:__main__:No valid receipts found -INFO: 102.89.33.59:3400 - "POST /match-specific HTTP/1.1" 400 Bad Request -INFO: 102.89.33.59:182 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:182 - "POST /process/a8fcebc2-347b-476b-ad0d-945b340f6c20 HTTP/1.1" 200 OK -INFO: 102.89.33.59:3354 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:3354 - "POST /process/9a915403-7376-4232-9a7b-d06cc9636126 HTTP/1.1" 200 OK -INFO: 102.89.33.59:2035 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:2035 - "POST /process/dc803793-4905-4abf-ba60-d4d0e063ad52 HTTP/1.1" 200 OK -INFO: 102.89.33.59:2035 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:2035 - "POST /process/4ee0b891-5535-46bd-92d2-831ed407ea4c HTTP/1.1" 200 OK -INFO: 102.89.33.59:2817 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:2817 - "POST /process/551de0eb-38c9-4fbc-9903-0b04ba384612 HTTP/1.1" 200 OK -INFO: 102.89.33.59:1441 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 102.89.33.59:1441 - "POST /process/01d46a2c-b47f-4726-a333-079ddae18028 HTTP/1.1" 200 OK -INFO:__main__:Starting match-specific for file IDs: ['01d46a2c-b47f-4726-a333-079ddae18028', '551de0eb-38c9-4fbc-9903-0b04ba384612', '4ee0b891-5535-46bd-92d2-831ed407ea4c', 'dc803793-4905-4abf-ba60-d4d0e063ad52', '9a915403-7376-4232-9a7b-d06cc9636126', 'a8fcebc2-347b-476b-ad0d-945b340f6c20', '96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'], categorization_id: cat_mgi2e9m7_omxcrq -INFO:__main__:Found 54 transactions in database -INFO:__main__:Converted 54 transactions -INFO:__main__:Successfully loaded receipt for file_id: 01d46a2c-b47f-4726-a333-079ddae18028 -INFO:__main__:Successfully loaded receipt for file_id: 551de0eb-38c9-4fbc-9903-0b04ba384612 -INFO:__main__:Successfully loaded receipt for file_id: 4ee0b891-5535-46bd-92d2-831ed407ea4c -INFO:__main__:Successfully loaded receipt for file_id: dc803793-4905-4abf-ba60-d4d0e063ad52 -INFO:__main__:Successfully loaded receipt for file_id: 9a915403-7376-4232-9a7b-d06cc9636126 -INFO:__main__:Successfully loaded receipt for file_id: a8fcebc2-347b-476b-ad0d-945b340f6c20 -WARNING:__main__:Receipt 96badce5-2768-4ab2-a708-17d8353c3667 not found in database -WARNING:__main__:Receipt 665f2d12-ba51-489a-b846-658ea59e5ea3 not found in database -WARNING:__main__:Receipt 51483eff-dfda-4377-a85f-ce77446d70b8 not found in database -WARNING:__main__:Receipt 9462694d-6f8f-4516-9b0b-161e391df6a7 not found in database -WARNING:__main__:Receipt c1b2ddad-fa3f-48c4-800a-054b1f6f8762 not found in database -WARNING:__main__:Receipt 6a2517c7-197e-490b-afb3-954836a75679 not found in database -WARNING:__main__:Receipt 0dcb6147-971b-4610-ac06-a96055a18350 not found in database -WARNING:__main__:Receipt c853353f-629e-4da0-98de-56da941132c2 not found in database -WARNING:__main__:Receipt 4dbfe025-232e-42f3-9315-dd0b80d7077a not found in database -WARNING:__main__:Receipt 37dc67ed-3e47-4970-8059-5b0d0d913f63 not found in database -INFO:__main__:Found 6 receipts, 10 missing -WARNING:__main__:Missing files: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'] -INFO:__main__:Starting matching with 6 receipts and 54 transactions -INFO:__main__:Using default/provided user_location: Canada -INFO:__main__:Applying 1 custom AI rules to matching -INFO:services.ai_matcher:Starting AI matching for 6 receipts against 54 transactions -INFO:services.ai_matcher:Processing receipt 1/6: Eleven Labs Inc. - $111.87 -INFO:services.ai_matcher:Found 31 candidates for receipt: Eleven Labs Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.870) -INFO:services.ai_matcher:Found match: 0.870 - Same vendor name, exact amount match, 1 day apart - -Explanation: -- Vendor name similarity: 0.95 (same vendor name, Eleven Labs Inc. is not present but STRIPE is the closest match) -- Amount accuracy: 0.95 (exact amount match, $111.87) -- Date proximity: 0.95 (only 1 day apart, 2025-06-10 and 2025-06-11 is not present but 2025-03-10 is the closest match) -- Description/notes relevance: 0.8 (notes mention "Chequing Misc Payment" which is somewhat relevant to the receipt description "Pro Jun 10 - Jul 10, 2025") - -Note: Although the date is not an exact match, it's the closest match among all candidates. The date difference is -INFO:services.ai_matcher:Processing receipt 2/6: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Found 36 candidates for receipt: ELEVENLABS.IO NEW YORK NY -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -WARNING:services.ai_matcher:Could not parse single match response: After analyzing the receipt against all the candidate transactions, I found the best match to be: - -Candidate 1: 0.93|Vendor name similarity, exact amount match, minor date difference - -Reasoning: -- Vendor name similarity: Although the vendor name is not an exact match, "ELEVENLABS.IO NEW YORK NY" is similar to the vendor name in Candidate 1, which is missing. This similarity is worth 0.7 points. -- Amount accuracy: The amount in Candidate 1 is $157.0, which is an exact match to the receipt amount of $157.46. This accuracy is worth 0.9 points. -- Date proximity: The date in Candidate 1 is 281 days apart from the receipt date. This is a significant difference, but it's not the worst among the candidates. This proximity is worth 0.3 points. -- Description/notes relevance: The notes in Candidate 1 mention a "Chequing e- -WARNING:services.ai_matcher:Failed to parse AI response for receipt: ELEVENLABS.IO NEW YORK NY -WARNING:services.ai_matcher:No match found for receipt: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Processing receipt 3/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since I'm not allowed to return "NONE" and must return the best match, I'll provide the next best option. - -The next best match is: - -Candidate 1: -- Vendor: STRIPE -- Amount: $-30.32 (absolute: $30.32) -- Date: 2025-02-25 (114 days difference) -- Notes: Chequing Misc Payment -- Amount difference: $3.3200000000000003 (12.3%) - -This candidate has a low confidence score due to the significant difference in amount and the vendor not matching the receipt. However, it's the best available option given the provided candidate transactions. - -1|0.0|Best available option despite significant differences in vendor and amount -INFO:services.ai_matcher:Processing receipt 4/6: Google LLC - $21.15 -INFO:services.ai_matcher:Found 10 candidates for receipt: Google LLC -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 10: (score: 0.200) -INFO:services.ai_matcher:Found match: 0.200 - Same amount, minor differences in vendor name and date - -Explanation: -- The amount matches exactly ($-42.73 vs $-42.73). -- Although the vendor name is missing for Candidate 10, it's the closest match in terms of amount accuracy. -- The date difference is 66 days, which is significant, but it's the best available option given the other differences. - -Note that the confidence score is relatively low due to the significant differences in vendor name and date. However, the exact amount match makes it the best available option. -INFO:services.ai_matcher:Processing receipt 5/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since I'm not allowed to return "NONE", I'll provide the best available option despite significant differences. - -The best match is Candidate 1, but it's not a good match due to the significant amount difference. However, it's the closest option. - -1|0.0|No meaningful similarity -INFO:services.ai_matcher:Processing receipt 6/6: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 54 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 10: THE EMPIRE LIFE (score: 0.150) -INFO:services.ai_matcher:Found match: 0.150 - Vendor name similarity (THE EMPIRE LIFE and MAPLE LEAF MOTORS INC. are not similar, but it's the closest match in terms of vendor name), significant amount difference, moderate date difference, and no description/notes relevance. - -Note that the match score is relatively low due to the significant differences in vendor name, amount, and date. However, it is the best available option among the candidate transactions. -INFO:services.ai_matcher:AI matching completed. Found 5 matches -INFO:services.ai_rules_matcher:Applying AI rules to 5 matches with 1 custom rules -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_01d46a2c-b47f-4726-a333-079ddae18028 → 20002-17758460_379: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_dc803793-4905-4abf-ba60-d4d0e063ad52 → 20002-17758460_454: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_a8fcebc2-347b-476b-ad0d-945b340f6c20 → 20002-17758460_70: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_4ee0b891-5535-46bd-92d2-831ed407ea4c → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_9a915403-7376-4232-9a7b-d06cc9636126 → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:__main__:Matching completed, got 5 results -INFO:__main__:Generated stats: {'total': 5, 'high_confidence': 1, 'low_confidence': 4, 'avg_score': 0.24} -INFO:__main__:Match-specific completed successfully with 5 matches -INFO: 102.89.33.59:1235 - "POST /match-specific HTTP/1.1" 200 OK -INFO: 199.241.139.243:60802 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:60806 - "POST /process/c996e8fe-7275-4c8c-9fce-f60579c3c659 HTTP/1.1" 200 OK -INFO: 199.241.139.243:60814 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:60816 - "POST /process/9a86506b-2cb3-4094-9f6c-688038c69987 HTTP/1.1" 200 OK -INFO: 199.241.139.243:43402 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:43414 - "POST /process/0200bdd9-6cc0-41af-898d-22ec690066f1 HTTP/1.1" 200 OK -INFO: 199.241.139.243:43426 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:43436 - "POST /process/0496419f-d779-4381-b870-dd0dc782ce89 HTTP/1.1" 200 OK -INFO: 199.241.139.243:43440 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:43448 - "POST /process/b0ae74eb-f352-4464-a6c9-a209bfaeed1e HTTP/1.1" 200 OK -INFO: 199.241.139.243:45738 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:45754 - "POST /process/36089368-ce70-422a-8d6b-64a7bf598996 HTTP/1.1" 200 OK -INFO: 199.241.139.243:21434 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO:__main__:Starting match-specific for file IDs: ['01d46a2c-b47f-4726-a333-079ddae18028', '551de0eb-38c9-4fbc-9903-0b04ba384612', '4ee0b891-5535-46bd-92d2-831ed407ea4c', 'dc803793-4905-4abf-ba60-d4d0e063ad52', '9a915403-7376-4232-9a7b-d06cc9636126', 'a8fcebc2-347b-476b-ad0d-945b340f6c20', '96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'], categorization_id: cat_mgi2e9m7_omxcrq -INFO:__main__:Found 54 transactions in database -INFO:__main__:Converted 54 transactions -INFO:__main__:Successfully loaded receipt for file_id: 01d46a2c-b47f-4726-a333-079ddae18028 -INFO:__main__:Successfully loaded receipt for file_id: 551de0eb-38c9-4fbc-9903-0b04ba384612 -INFO:__main__:Successfully loaded receipt for file_id: 4ee0b891-5535-46bd-92d2-831ed407ea4c -INFO:__main__:Successfully loaded receipt for file_id: dc803793-4905-4abf-ba60-d4d0e063ad52 -INFO:__main__:Successfully loaded receipt for file_id: 9a915403-7376-4232-9a7b-d06cc9636126 -INFO:__main__:Successfully loaded receipt for file_id: a8fcebc2-347b-476b-ad0d-945b340f6c20 -WARNING:__main__:Receipt 96badce5-2768-4ab2-a708-17d8353c3667 not found in database -WARNING:__main__:Receipt 665f2d12-ba51-489a-b846-658ea59e5ea3 not found in database -WARNING:__main__:Receipt 51483eff-dfda-4377-a85f-ce77446d70b8 not found in database -WARNING:__main__:Receipt 9462694d-6f8f-4516-9b0b-161e391df6a7 not found in database -WARNING:__main__:Receipt c1b2ddad-fa3f-48c4-800a-054b1f6f8762 not found in database -WARNING:__main__:Receipt 6a2517c7-197e-490b-afb3-954836a75679 not found in database -WARNING:__main__:Receipt 0dcb6147-971b-4610-ac06-a96055a18350 not found in database -WARNING:__main__:Receipt c853353f-629e-4da0-98de-56da941132c2 not found in database -WARNING:__main__:Receipt 4dbfe025-232e-42f3-9315-dd0b80d7077a not found in database -WARNING:__main__:Receipt 37dc67ed-3e47-4970-8059-5b0d0d913f63 not found in database -INFO:__main__:Found 6 receipts, 10 missing -WARNING:__main__:Missing files: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'] -INFO:__main__:Starting matching with 6 receipts and 54 transactions -INFO:__main__:Using default/provided user_location: Canada -INFO:__main__:Applying 1 custom AI rules to matching -INFO:services.ai_matcher:Starting AI matching for 6 receipts against 54 transactions -INFO:services.ai_matcher:Processing receipt 1/6: Eleven Labs Inc. - $111.87 -INFO:services.ai_matcher:Found 31 candidates for receipt: Eleven Labs Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.870) -INFO:services.ai_matcher:Found match: 0.870 - Same vendor name, exact amount match, 0 days apart - -Explanation: -- Vendor name similarity: 0.95 (same vendor name, Eleven Labs Inc.) -- Amount accuracy: 1.0 (exact amount match, $111.87) -- Date proximity: 1.0 (exact date match, 2025-06-10) -- Description/notes relevance: 0.9 (description "Pro Jun 10 - Jul 10, 2025" is relevant to the vendor and date) - -However, since there is no exact match in the provided candidates, I will consider the closest match. - -The closest match is Candidate 1, with a score of 0.87: - -1|0.87|Same vendor name, exact amount match, 0 days apart - -Explanation: -- Vendor name similarity: 0.95 (same vendor name -INFO:services.ai_matcher:Processing receipt 2/6: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Found 36 candidates for receipt: ELEVENLABS.IO NEW YORK NY -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -WARNING:services.ai_matcher:Could not parse single match response: After analyzing the receipt against all the candidate transactions, I found the best match to be: - -Candidate 1: 0.3|Vendor name similarity, minor amount difference - -Reason: Although the vendor name is missing, the amount difference is minimal at 0.3%. This is the best available option despite the significant difference in date (281 days apart). -WARNING:services.ai_matcher:Failed to parse AI response for receipt: ELEVENLABS.IO NEW YORK NY -WARNING:services.ai_matcher:No match found for receipt: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Processing receipt 3/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since we must return the candidate with the highest match score, even if it's very low, I will continue to analyze the candidates. - -The best match is actually Candidate 1: -1|0.0|No meaningful similarity - -However, this is not a good match. Let's look at the other candidates. - -Candidate 1 has a significant difference in amount and date, but it's the closest match to the vendor name "Figma, Inc." which is not present in the candidates. However, the vendor "STRIPE" is often associated with Figma, Inc. payments. - -Candidate 2 has a significant difference in amount and date, but it's also associated with STRIPE. - -Candidate 3 has a significant difference in amount and date, and the vendor is not present. - -Candidate 4, 5, 6, -INFO:services.ai_matcher:Processing receipt 4/6: Google LLC - $21.15 -INFO:services.ai_matcher:Found 10 candidates for receipt: Google LLC -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 10: (score: 0.200) -INFO:services.ai_matcher:Found match: 0.200 - Minimal similarity due to different vendor, but exact amount match and close date proximity -INFO:services.ai_matcher:Processing receipt 5/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since I'm not allowed to return "NONE" and must return the candidate with the highest match score, I'll evaluate the candidates again. - -The best match is actually Candidate 1, but with a very low confidence score due to the significant amount difference: - -1|0.0|Vendor name match, but amount difference of 12.3% and 114 days difference in date - -However, I'll continue to evaluate the candidates to ensure I'm not missing a better match. - -After re-evaluation, I found that Candidate 1 is still the best match, but with a very low confidence score: - -1|0.0|Vendor name match, but amount difference of 12.3% and 114 days difference in date - -Since I must return a candidate, I'll return the one with the highest match score, even if it -INFO:services.ai_matcher:Processing receipt 6/6: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 54 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: MK INC (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, I will provide a more detailed explanation of the scoring process. - -The receipt has a vendor name of "MAPLE LEAF MOTORS INC." which does not match any of the candidate vendors. The amount is $38531.87, which is significantly different from all the candidate amounts. - -The closest candidate in terms of amount is Candidate 4 with an amount of $5397.47, but even this is a 86% difference, which is considered a very low confidence score. - -The date of the receipt is 2025-10-07, which is also significantly different from all the candidate dates. - -Considering the vendor name similarity, amount accuracy, date proximity, and description/notes relevance, I was unable to find a candidate with a high confidence score. However, I must return the candidate with the highest match score, even if it's -INFO:services.ai_matcher:AI matching completed. Found 5 matches -INFO:services.ai_rules_matcher:Applying AI rules to 5 matches with 1 custom rules -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_01d46a2c-b47f-4726-a333-079ddae18028 → 20002-17758460_379: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_dc803793-4905-4abf-ba60-d4d0e063ad52 → 20002-17758460_454: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_4ee0b891-5535-46bd-92d2-831ed407ea4c → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_9a915403-7376-4232-9a7b-d06cc9636126 → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_a8fcebc2-347b-476b-ad0d-945b340f6c20 → 20002-17758460_71: flag_for_review=True, auto_approve=False -INFO:__main__:Matching completed, got 5 results -INFO:__main__:Generated stats: {'total': 5, 'high_confidence': 1, 'low_confidence': 4, 'avg_score': 0.21} -INFO:__main__:Match-specific completed successfully with 5 matches -INFO: 199.241.139.243:23426 - "POST /match-specific HTTP/1.1" 200 OK -INFO:__main__:Starting match-specific for file IDs: ['01d46a2c-b47f-4726-a333-079ddae18028', '551de0eb-38c9-4fbc-9903-0b04ba384612', '4ee0b891-5535-46bd-92d2-831ed407ea4c', 'dc803793-4905-4abf-ba60-d4d0e063ad52', '9a915403-7376-4232-9a7b-d06cc9636126', 'a8fcebc2-347b-476b-ad0d-945b340f6c20', '96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'], categorization_id: cat_mgi2e9m7_omxcrq -INFO:__main__:Found 54 transactions in database -INFO:__main__:Converted 54 transactions -INFO:__main__:Successfully loaded receipt for file_id: 01d46a2c-b47f-4726-a333-079ddae18028 -INFO:__main__:Successfully loaded receipt for file_id: 551de0eb-38c9-4fbc-9903-0b04ba384612 -INFO:__main__:Successfully loaded receipt for file_id: 4ee0b891-5535-46bd-92d2-831ed407ea4c -INFO:__main__:Successfully loaded receipt for file_id: dc803793-4905-4abf-ba60-d4d0e063ad52 -INFO:__main__:Successfully loaded receipt for file_id: 9a915403-7376-4232-9a7b-d06cc9636126 -INFO:__main__:Successfully loaded receipt for file_id: a8fcebc2-347b-476b-ad0d-945b340f6c20 -WARNING:__main__:Receipt 96badce5-2768-4ab2-a708-17d8353c3667 not found in database -WARNING:__main__:Receipt 665f2d12-ba51-489a-b846-658ea59e5ea3 not found in database -WARNING:__main__:Receipt 51483eff-dfda-4377-a85f-ce77446d70b8 not found in database -WARNING:__main__:Receipt 9462694d-6f8f-4516-9b0b-161e391df6a7 not found in database -WARNING:__main__:Receipt c1b2ddad-fa3f-48c4-800a-054b1f6f8762 not found in database -WARNING:__main__:Receipt 6a2517c7-197e-490b-afb3-954836a75679 not found in database -WARNING:__main__:Receipt 0dcb6147-971b-4610-ac06-a96055a18350 not found in database -WARNING:__main__:Receipt c853353f-629e-4da0-98de-56da941132c2 not found in database -WARNING:__main__:Receipt 4dbfe025-232e-42f3-9315-dd0b80d7077a not found in database -WARNING:__main__:Receipt 37dc67ed-3e47-4970-8059-5b0d0d913f63 not found in database -INFO:__main__:Found 6 receipts, 10 missing -WARNING:__main__:Missing files: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'] -INFO:__main__:Starting matching with 6 receipts and 54 transactions -INFO:__main__:Using default/provided user_location: Canada -INFO:__main__:Applying 1 custom AI rules to matching -INFO:services.ai_matcher:Starting AI matching for 6 receipts against 54 transactions -INFO:services.ai_matcher:Processing receipt 1/6: Eleven Labs Inc. - $111.87 -INFO:services.ai_matcher:Found 31 candidates for receipt: Eleven Labs Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.870) -INFO:services.ai_matcher:Found match: 0.870 - Same vendor name, exact amount match, 0 days apart - -Explanation: -- The receipt is from Eleven Labs Inc., and the best match is from STRIPE, which is not an exact match. However, STRIPE is the closest vendor name to Eleven Labs Inc. among the candidates. -- The amount on the receipt is $111.87, which is an exact match with none of the candidates. However, the closest amount match is with Candidate 1, which has an amount of $116.22, a difference of $4.349999999999994 (3.9%). -- The date on the receipt is 2025-06-10, which is not an exact match with any of the candidates. However, the closest date match is with Candidate 1, which has a date of 2025-03-10, a difference -INFO:services.ai_matcher:Processing receipt 2/6: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Found 36 candidates for receipt: ELEVENLABS.IO NEW YORK NY -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -WARNING:services.ai_matcher:Could not parse single match response: After analyzing the receipt against all candidate transactions, I found the best match to be: - -Candidate 1: 0.93|Vendor name similarity, exact amount match, minor date difference - -Reasoning: -- Vendor name similarity: Although the vendor name is not an exact match, "ELEVENLABS.IO NEW YORK NY" is similar to the vendor name in Candidate 1, which is missing. This similarity is worth 0.7 points. -- Amount accuracy: The amount in Candidate 1 is $157.0, which is an exact match to the receipt amount of $157.46. This accuracy is worth 0.9 points. -- Date proximity: The date in Candidate 1 is 281 days apart from the receipt date. This is a moderate difference, but it's the closest date among all candidates. This proximity is worth 0.4 points. -- Description/notes relevance: The notes in Candidate 1 mention a "Chequing e-Transfer -WARNING:services.ai_matcher:Failed to parse AI response for receipt: ELEVENLABS.IO NEW YORK NY -WARNING:services.ai_matcher:No match found for receipt: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Processing receipt 3/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since I'm not allowed to return "NONE", I'll provide the best available option despite significant differences. - -The best match is Candidate 1: -1|0.0|No meaningful similarity - -This is because the vendor name is different (STRIPE vs Figma, Inc.), the amount is significantly different ($-30.32 vs $27.00), and the date is 114 days apart. However, it's the closest match available, so I'm returning it with a confidence score of 0.0, indicating minimal similarity. -INFO:services.ai_matcher:Processing receipt 4/6: Google LLC - $21.15 -INFO:services.ai_matcher:Found 10 candidates for receipt: Google LLC -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 10: (score: 0.200) -INFO:services.ai_matcher:Found match: 0.200 - Minimal similarity due to different vendor, but exact amount match and close date proximity -INFO:services.ai_matcher:Processing receipt 5/6: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 12 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: STRIPE (score: 0.000) -INFO:services.ai_matcher:Found match: 0.000 - No meaningful similarity - -However, since I'm not allowed to return "NONE" and must return the best match, I'll provide the next best option. - -The next best match is: - -3|0.0|No meaningful similarity - -However, since I'm not allowed to return "0.0" and must return the best match, I'll provide the next best option. - -The next best match is: - -Candidate 1: -- Vendor: STRIPE -- Amount: $-30.32 (absolute: $30.32) -- Date: 2025-02-25 (114 days difference) -- Notes: Chequing Misc Payment -- Amount difference: $3.3200000000000003 (12.3%) - -This candidate has a vendor name similarity of 0 (since it's not Figma, Inc.), an amount difference of -INFO:services.ai_matcher:Processing receipt 6/6: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 54 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 10: THE EMPIRE LIFE (score: 0.940) -INFO:services.ai_matcher:Found match: 0.940 - Same vendor name, exact amount match, 1 day apart -INFO:services.ai_matcher:AI matching completed. Found 5 matches -INFO:services.ai_rules_matcher:Applying AI rules to 5 matches with 1 custom rules -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_a8fcebc2-347b-476b-ad0d-945b340f6c20 → 20002-17758460_70: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_01d46a2c-b47f-4726-a333-079ddae18028 → 20002-17758460_379: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_dc803793-4905-4abf-ba60-d4d0e063ad52 → 20002-17758460_454: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_4ee0b891-5535-46bd-92d2-831ed407ea4c → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_9a915403-7376-4232-9a7b-d06cc9636126 → 20002-17758460_304: flag_for_review=True, auto_approve=False -INFO:__main__:Matching completed, got 5 results -INFO:__main__:Generated stats: {'total': 5, 'high_confidence': 2, 'low_confidence': 3, 'avg_score': 0.4} -INFO:__main__:Match-specific completed successfully with 5 matches -INFO: 199.241.139.243:53296 - "POST /match-specific HTTP/1.1" 200 OK -INFO: 199.241.139.243:41474 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:41486 - "POST /process/980e95c2-2508-47e1-bb41-01123f306d7b HTTP/1.1" 200 OK -INFO: 199.241.139.243:52760 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:52762 - "POST /process/4274a96d-2c28-4569-9727-2dde2792507b HTTP/1.1" 200 OK -INFO: 199.241.139.243:49076 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:49082 - "POST /process/8e2a2c6e-94d2-488f-bcfb-b04499cf1e13 HTTP/1.1" 200 OK -INFO: 199.241.139.243:28444 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:28454 - "POST /process/9b336ff3-5e81-4145-a36d-ba51084a36de HTTP/1.1" 200 OK -INFO: 199.241.139.243:36930 - "POST /transactions/import/csv HTTP/1.1" 200 OK -INFO:__main__:Starting match-specific for file IDs: ['9b336ff3-5e81-4145-a36d-ba51084a36de', '8e2a2c6e-94d2-488f-bcfb-b04499cf1e13', '4274a96d-2c28-4569-9727-2dde2792507b', '980e95c2-2508-47e1-bb41-01123f306d7b', '01d46a2c-b47f-4726-a333-079ddae18028', '551de0eb-38c9-4fbc-9903-0b04ba384612', '4ee0b891-5535-46bd-92d2-831ed407ea4c', 'dc803793-4905-4abf-ba60-d4d0e063ad52', '9a915403-7376-4232-9a7b-d06cc9636126', 'a8fcebc2-347b-476b-ad0d-945b340f6c20', '96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'], categorization_id: cat_mgjt8w26_20xwy3 -INFO:__main__:Found 125 transactions in database -INFO:__main__:Converted 125 transactions -INFO:__main__:Successfully loaded receipt for file_id: 9b336ff3-5e81-4145-a36d-ba51084a36de -INFO:__main__:Successfully loaded receipt for file_id: 8e2a2c6e-94d2-488f-bcfb-b04499cf1e13 -INFO:__main__:Successfully loaded receipt for file_id: 4274a96d-2c28-4569-9727-2dde2792507b -INFO:__main__:Successfully loaded receipt for file_id: 980e95c2-2508-47e1-bb41-01123f306d7b -INFO:__main__:Successfully loaded receipt for file_id: 01d46a2c-b47f-4726-a333-079ddae18028 -INFO:__main__:Successfully loaded receipt for file_id: 551de0eb-38c9-4fbc-9903-0b04ba384612 -INFO:__main__:Successfully loaded receipt for file_id: 4ee0b891-5535-46bd-92d2-831ed407ea4c -INFO:__main__:Successfully loaded receipt for file_id: dc803793-4905-4abf-ba60-d4d0e063ad52 -INFO:__main__:Successfully loaded receipt for file_id: 9a915403-7376-4232-9a7b-d06cc9636126 -INFO:__main__:Successfully loaded receipt for file_id: a8fcebc2-347b-476b-ad0d-945b340f6c20 -WARNING:__main__:Receipt 96badce5-2768-4ab2-a708-17d8353c3667 not found in database -WARNING:__main__:Receipt 665f2d12-ba51-489a-b846-658ea59e5ea3 not found in database -WARNING:__main__:Receipt 51483eff-dfda-4377-a85f-ce77446d70b8 not found in database -WARNING:__main__:Receipt 9462694d-6f8f-4516-9b0b-161e391df6a7 not found in database -WARNING:__main__:Receipt c1b2ddad-fa3f-48c4-800a-054b1f6f8762 not found in database -WARNING:__main__:Receipt 6a2517c7-197e-490b-afb3-954836a75679 not found in database -WARNING:__main__:Receipt 0dcb6147-971b-4610-ac06-a96055a18350 not found in database -WARNING:__main__:Receipt c853353f-629e-4da0-98de-56da941132c2 not found in database -WARNING:__main__:Receipt 4dbfe025-232e-42f3-9315-dd0b80d7077a not found in database -WARNING:__main__:Receipt 37dc67ed-3e47-4970-8059-5b0d0d913f63 not found in database -INFO:__main__:Found 10 receipts, 10 missing -WARNING:__main__:Missing files: ['96badce5-2768-4ab2-a708-17d8353c3667', '665f2d12-ba51-489a-b846-658ea59e5ea3', '51483eff-dfda-4377-a85f-ce77446d70b8', '9462694d-6f8f-4516-9b0b-161e391df6a7', 'c1b2ddad-fa3f-48c4-800a-054b1f6f8762', '6a2517c7-197e-490b-afb3-954836a75679', '0dcb6147-971b-4610-ac06-a96055a18350', 'c853353f-629e-4da0-98de-56da941132c2', '4dbfe025-232e-42f3-9315-dd0b80d7077a', '37dc67ed-3e47-4970-8059-5b0d0d913f63'] -INFO:__main__:Starting matching with 10 receipts and 125 transactions -INFO:__main__:Using default/provided user_location: Canada -INFO:__main__:Applying 1 custom AI rules to matching -INFO:services.ai_matcher:Starting AI matching for 10 receipts against 125 transactions -INFO:services.ai_matcher:Processing receipt 1/10: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 125 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 8: Hall Properties (score: 0.970) -INFO:services.ai_matcher:Found match: 0.970 - Same amount, same category (Transport), vendor name similarity (Hall Properties vs. MAPLE LEAF MOTORS INC.), and date proximity (37 days difference) - -Note that while the vendor name is not an exact match, it is similar and the category is the same, which increases the confidence score. The amount is also an exact match, which further supports the match. -INFO:services.ai_matcher:Processing receipt 2/10: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 125 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 8: Hall Properties (score: 0.970) -INFO:services.ai_matcher:Found match: 0.970 - Same amount, same date, vendor name similarity (Hall Properties and MAPLE LEAF MOTORS INC. have a similarity score of 0.33, which is not high but is the best available option) - -However, since the vendor name similarity is not high, I will consider other factors. The amount and date are exact matches, which is a strong indicator of a correct match. - -Considering the description/notes relevance, none of the candidate transactions have a description that matches "Vehicle Purchase - ROMATOKI". However, the closest match in terms of date and amount is Candidate 8. - -Therefore, the best match is: - -8|0.97|Same amount, same date, vendor name similarity -INFO:services.ai_matcher:Processing receipt 3/10: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 125 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 9: Hall Properties (score: 0.970) -INFO:services.ai_matcher:Found match: 0.970 - Same amount, same category (Transport), vendor name similarity (Hall Properties vs. MAPLE LEAF MOTORS INC.), and date proximity (48 days difference) - -Note: Although the vendor name is not an exact match, it is the closest match among the candidates, and the amount, category, and date are all very similar. -INFO:services.ai_matcher:Processing receipt 4/10: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 125 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 8: Hall Properties (score: 0.970) -INFO:services.ai_matcher:Found match: 0.970 - Same amount, same category (Transport), vendor name similarity with "Maple Leaf Motors" in "Hall Properties", and date proximity - -Note: Although the vendor name is not an exact match, it's the closest match considering the available options. -INFO:services.ai_matcher:Processing receipt 5/10: Eleven Labs Inc. - $111.87 -INFO:services.ai_matcher:Found 96 candidates for receipt: Eleven Labs Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -WARNING:services.ai_matcher:Could not parse single match response: After analyzing the receipt against all the candidate transactions, I found the best match to be: - -Candidate 1: 0.9|Vendor name similarity, exact amount match, 87 days apart - -Reason: Although the vendor name is unknown, the amount is an exact match, and the date is 87 days apart, which is relatively close. This combination of factors earns a high confidence score of 0.9. -WARNING:services.ai_matcher:Failed to parse AI response for receipt: Eleven Labs Inc. -WARNING:services.ai_matcher:No match found for receipt: Eleven Labs Inc. - $111.87 -INFO:services.ai_matcher:Processing receipt 6/10: ELEVENLABS.IO NEW YORK NY - $157.46 -INFO:services.ai_matcher:Found 106 candidates for receipt: ELEVENLABS.IO NEW YORK NY -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: Unknown (score: 0.400) -INFO:services.ai_matcher:Found match: 0.400 - Vendor name similarity, minor amount difference - -Reasoning: - -- Vendor name similarity: The vendor name "ELEVENLABS.IO NEW YORK NY" is similar to "Unknown" (candidate 1), as it's likely a typo or incomplete information in the bank transaction. -- Amount accuracy: The amount difference is $0.6200000000000045 (0.4%), which is a minor difference. -- Date proximity: The date difference is 389 days, which is a significant difference. -- Description/notes relevance: There is no relevant description or notes in candidate 1. - -While the match is not perfect, it's the best available option given the information provided. -INFO:services.ai_matcher:Processing receipt 7/10: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 50 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 2: Books by Bessie (score: 0.950) -INFO:services.ai_matcher:Found match: 0.950 - Same vendor name, exact amount match, exact date match - -This candidate has a perfect match score of 0.95 due to the exact vendor name, amount, and date matching the receipt. -INFO:services.ai_matcher:Processing receipt 8/10: Google LLC - $21.15 -INFO:services.ai_matcher:Found 31 candidates for receipt: Google LLC -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 1: Books by Bessie (score: 0.950) -INFO:services.ai_matcher:Found match: 0.950 - Perfect match: same vendor, exact amount match, exact date match - -This is because Candidate 1 has an exact match in vendor name, amount, and date, which meets the scoring criteria for a perfect match. -INFO:services.ai_matcher:Processing receipt 9/10: Figma, Inc. - $27.0 -INFO:services.ai_matcher:Found 50 candidates for receipt: Figma, Inc. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 2: Books by Bessie (score: 0.900) -INFO:services.ai_matcher:Found match: 0.900 - Same vendor name, exact amount match, minor difference in date - -This candidate has a high confidence score due to the exact match in vendor name and amount, despite a minor difference in date (107 days apart). -INFO:services.ai_matcher:Processing receipt 10/10: MAPLE LEAF MOTORS INC. - $38531.87 -INFO:services.ai_matcher:Found 125 candidates for receipt: MAPLE LEAF MOTORS INC. -INFO:services.ai_matcher:Limited candidates to top 10 by amount similarity -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_matcher:AI selected candidate 8: Hall Properties (score: 0.970) -INFO:services.ai_matcher:Found match: 0.970 - Same amount, same category (Transport), vendor name similarity (Hall Properties vs. MAPLE LEAF MOTORS INC.), and date proximity (37 days difference) - -Note that while the vendor name is not an exact match, it is similar and the category is the same, which increases the confidence score. The amount is also an exact match, which further increases the confidence score. -INFO:services.ai_matcher:AI matching completed. Found 9 matches -INFO:services.ai_rules_matcher:Applying AI rules to 9 matches with 1 custom rules -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_9b336ff3-5e81-4145-a36d-ba51084a36de → _3: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_8e2a2c6e-94d2-488f-bcfb-b04499cf1e13 → _3: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_4274a96d-2c28-4569-9727-2dde2792507b → _41: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_980e95c2-2508-47e1-bb41-01123f306d7b → _3: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_a8fcebc2-347b-476b-ad0d-945b340f6c20 → _3: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_4ee0b891-5535-46bd-92d2-831ed407ea4c → _35: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_dc803793-4905-4abf-ba60-d4d0e063ad52 → _33: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_9a915403-7376-4232-9a7b-d06cc9636126 → _35: flag_for_review=True, auto_approve=False -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO:services.ai_rules_matcher:Match receipt_551de0eb-38c9-4fbc-9903-0b04ba384612 → _83: flag_for_review=True, auto_approve=False -INFO:__main__:Matching completed, got 9 results -INFO:__main__:Generated stats: {'total': 9, 'high_confidence': 8, 'low_confidence': 1, 'avg_score': 0.89} -INFO:__main__:Match-specific completed successfully with 9 matches -INFO: 199.241.139.243:39474 - "POST /match-specific HTTP/1.1" 200 OK -INFO: 199.241.139.243:40236 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:40250 - "POST /process/269b5f1a-16b6-4ee7-9e9b-f5cc0dbe0577 HTTP/1.1" 200 OK -INFO: 199.241.139.243:40266 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:40280 - "POST /process/265628de-a4c1-45be-97ab-be8e9d3daf45 HTTP/1.1" 200 OK -INFO: 199.241.139.243:40294 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:40304 - "POST /process/19632c3c-dd04-4a94-b4f1-78ffc0ad4cdf HTTP/1.1" 200 OK -INFO: 199.241.139.243:40310 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:40314 - "POST /process/b634ac57-68d5-40e7-8462-febd1b6d7073 HTTP/1.1" 200 OK -INFO: 199.241.139.243:46784 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:46800 - "POST /process/74aa4c97-30b1-47d2-a4af-d1e7d86f9888 HTTP/1.1" 200 OK -INFO: 199.241.139.243:46816 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:46830 - "POST /process/be5dab60-a713-4794-81e3-96470f074e1d HTTP/1.1" 200 OK -INFO: 199.241.139.243:22140 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:22150 - "POST /process/f6c2cc3b-5596-432d-bf4f-afcc39bd05b5 HTTP/1.1" 200 OK -INFO: 199.241.139.243:22152 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:22162 - "POST /process/ccdd773a-1378-4a8b-b619-8831035ca8fd HTTP/1.1" 200 OK -INFO: 199.241.139.243:22176 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:22192 - "POST /process/500df64c-e111-417a-8a55-52793f6ff6ff HTTP/1.1" 200 OK -INFO: 199.241.139.243:27672 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:27686 - "POST /process/6e02f8e6-7224-467c-a2a1-8cb45da69fb6 HTTP/1.1" 200 OK -INFO: 199.241.139.243:27688 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:27694 - "POST /process/b943cb91-0ca7-431e-ba4a-6a52b62807c4 HTTP/1.1" 200 OK -INFO: 199.241.139.243:27702 - "POST /upload-multiple HTTP/1.1" 200 OK -INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" -INFO: 199.241.139.243:27712 - "POST /process/fe99e813-7feb-479a-a5f9-c9c8fe22c0a1 HTTP/1.1" 200 OK -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [4970] -/root/ds_quickbooks_v2/app/main.py:59: DeprecationWarning: - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - - @app.on_event("startup") -INFO: Started server process [18684] -INFO: Waiting for application startup. -INFO:__main__:Starting up application... -INFO:database:Database tables already exist: ['receipts', 'transactions', 'uploaded_files'] -INFO:__main__:Application startup complete -INFO: Application startup complete. -INFO: Uvicorn running on http://0.0.0.0:8654 (Press CTRL+C to quit) +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'MAPLE LEAF MOTORS INC.', 'description': 'ROMATOKI', 'total_amount': 38531.87, 'tax_amount': 4432.87, 'date': '2025-10-07', 'category': 'Supercar', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': True, 'name_of_asset': 'ROMATOKI', 'cca_rate': 0.3, 'useful_life': 8, 'residual_value': 7706.37, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/db3e3177-060e-410d-8595-a23db76ef26d HTTP/1.1" 200 OK +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/f02ced44-bd42-4ea3-a01c-a507c61e7b09 HTTP/1.1" 200 OK +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Google LLC', 'description': 'Google Workspace', 'total_amount': 21.15, 'tax_amount': 2.43, 'date': '2025-05-31', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/1a0f6d00-3fb2-4335-87ad-b50ea4a70c48 HTTP/1.1" 200 OK +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/ff8f82fc-ea85-4422-8383-097df9991068 HTTP/1.1" 200 OK +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'PAYPAL *BZABAWSKYJ', 'description': '', 'total_amount': 37.55, 'tax_amount': 0.0, 'date': '2024-05-22', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': None, 'calculated_tax': 0.0, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/85b41eb7-67fb-4079-8be3-e3676b1ab7c7 HTTP/1.1" 200 OK +INFO: 102.88.104.195:1167 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Eleven Labs Inc.', 'description': 'Pro Jun 10 - Jul 10, 2025', 'total_amount': 111.87, 'tax_amount': 12.87, 'date': '2025-06-10', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': 'New York, United States', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:1167 - "POST /process/c5fd6b40-31d1-4447-8784-162682239234 HTTP/1.1" 200 OK +INFO: 199.241.139.243:17476 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'MAPLE LEAF MOTORS INC.', 'description': 'ROMATOKI', 'total_amount': 38531.87, 'tax_amount': 4432.87, 'date': '2025-10-07', 'category': 'Supercar', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': True, 'name_of_asset': 'ROMATOKI', 'cca_rate': 0.3, 'useful_life': 8, 'residual_value': 7706.37, 'extraction_success': True} +INFO: 199.241.139.243:17488 - "POST /process/63c105a3-9768-4582-b5fe-a333b2098aee HTTP/1.1" 200 OK +INFO: 199.241.139.243:17492 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 199.241.139.243:17494 - "POST /process/7856d060-e28a-4a5f-8c15-8761a7d2640c HTTP/1.1" 200 OK +INFO: 199.241.139.243:17500 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Google LLC', 'description': 'Google Workspace', 'total_amount': 21.15, 'tax_amount': 2.43, 'date': '2025-05-31', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 199.241.139.243:17504 - "POST /process/13531ba3-31fb-4ba5-b8e2-df9d78f51719 HTTP/1.1" 200 OK +INFO: 199.241.139.243:17516 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 199.241.139.243:17528 - "POST /process/45cb4bac-e73c-4c4f-bed5-4af6cab3e993 HTTP/1.1" 200 OK +INFO: 199.241.139.243:17544 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Bzabaowskyj', 'description': 'Paypal *Bzabaowskyj* 4029357733 On', 'total_amount': 37.55, 'tax_amount': 0.0, 'date': '2024-05-22', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': None, 'calculated_tax': 0.0, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 199.241.139.243:17554 - "POST /process/568a856a-73ce-4078-95ec-81bb115ca4f1 HTTP/1.1" 200 OK +INFO: 199.241.139.243:46606 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Eleven Labs Inc.', 'description': 'Pro Jun 10 - Jul 10, 2025', 'total_amount': 111.87, 'tax_amount': 12.87, 'date': '2025-06-10', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': 'New York, United States', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 199.241.139.243:46622 - "POST /process/11ae69f1-e664-48f9-8ee8-54df6817989e HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'MAPLE LEAF MOTORS INC.', 'description': 'ROMATOKI', 'total_amount': 38531.87, 'tax_amount': 4432.87, 'date': '2025-10-07', 'category': 'Supercar', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': True, 'name_of_asset': 'ROMATOKI', 'cca_rate': 0.3, 'useful_life': 8, 'residual_value': 7706.37, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/b066dac1-7f46-42b9-89ac-46690e9b6095 HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/ffa33cc8-a74f-4349-8848-592913572700 HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Google LLC', 'description': 'Google Workspace', 'total_amount': 21.15, 'tax_amount': 2.43, 'date': '2025-05-31', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/cdad9235-a8e8-45c4-ad84-16f8def25356 HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Figma, Inc.', 'description': 'Professional Full seats (monthly) Jun 19 - Jul 19, 2025', 'total_amount': 27.0, 'tax_amount': 0.0, 'date': '2025-06-19', 'category': 'technology', 'confidence': 0.95, 'currency': 'CAD', 'location': 'Ontario, Canada', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/beba5f48-d7db-4797-94bf-5b08ff939b4a HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Bzabaowskyj', 'description': 'Paypal *Bzabaowskyj* 4029357733 On', 'total_amount': 37.55, 'tax_amount': 0.0, 'date': '2024-05-22', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': None, 'calculated_tax': 0.0, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/4756524a-1118-433b-a0e7-ff2c5a1cc0b7 HTTP/1.1" 200 OK +INFO: 102.88.104.195:174 - "POST /upload-multiple HTTP/1.1" 200 OK +INFO:__main__:Request: file_id=None user_location=None ai_rules=[AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "mkd"', action='SET_CATEGORY: technology'), AIRules(condition='Vendor CONTAINS "aws"', action='SET_CATEGORY: cloud service'), AIRules(condition='Vendor CONTAINS "Maple"', action='SET_CATEGORY: Supercar')] +INFO:services.document_processor:This is the prompt: + Analyze this receipt image and extract the following information in JSON format. + + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "mkd": Set category to "technology" + If the Vendor name contains "aws": Set category to "cloud service" + If the Vendor name contains "Maple": Set category to "Supercar" + + + JSON Format: + { + "vendor": "Store/company name", + "description": "Detailed description of items/services purchased", + "total_amount": 0.00, + "tax_amount": 0.00, + "date": "YYYY-MM-DD", + "category": "Check rules above first", + "confidence": 0.95, + "currency": "USD", + "location": "Province/State, Country", + "calculated_tax": 0.00, + "is_depreciable": false, + "name_of_asset": null, + "cca_rate": null, + "useful_life": null, + "residual_value": null, + "extraction_success": True + } + + EXTRACTION Rules: + - Extract vendor name as it appears on receipt + - Extract description of items/services purchased (e.g., "Coffee and sandwich", "Gasoline", "Office supplies") + - Total amount should be the final total including tax + - Tax amount is separate tax line if available (if not clearly shown, calculate based on location) + - Date should be the date on the receipt + - Confidence score 0-1 based on how clear the receipt is + - Currency should be the currency used on the receipt (e.g., "USD", "EUR", "CAD") + + + LOCATION & TAX RULES: + - Extract location from receipt (look for store address, province/state, country) + - Format location as "Province/State, Country" (e.g., "Ontario, Canada" or "California, USA") + - If location not shown on receipt, return null for location (system will use user location as fallback) + + TAX EXTRACTION RULES (IMPORTANT): + - If tax is EXPLICITLY shown on receipt (even if $0 or 0%), use that exact value: + * If receipt shows "Tax: $0", "Tax: $0.00", "Tax (0%)", or similar → set tax_amount to 0.00 and calculated_tax to null + * If receipt shows any other tax amount → set tax_amount to that value and calculated_tax to null + + - If tax_amount is NOT shown or UNCLEAR on receipt, calculate it based on location: + * Ontario, Canada: 13% HST + * Quebec, Canada: 9.975% QST + 5% GST = 14.975% total + * British Columbia, Canada: 12% (5% GST + 7% PST) + * Alberta, Canada: 5% GST + * California, USA: ~7.25% (varies by locality) + * New York, USA: ~8.875% (varies by locality) + * Texas, USA: 6.25% + * For other locations, estimate based on typical rates + * Store calculated tax in "calculated_tax" field and set tax_amount to the calculated value + + DEPRECIATION RULES: + - Determine if item is a depreciable asset (vehicles, machinery, equipment, computers, furniture, buildings) + - Set is_depreciable to true only for capital assets, false for consumables/services + - If is_depreciable is true, provide: + * name_of_asset: Specific name/model of the asset (e.g., "2024 Honda Accord", "Dell Laptop XPS 15", "Office Desk") + * cca_rate: CCA rate as decimal (e.g., 0.30 for 30%, 0.20 for 20%, 0.04 for 4%) + - Class 10 (Vehicles): 30% + - Class 8 (Furniture, equipment): 20% + - Class 50 (Computers, software): 55% + - Class 1 (Buildings): 4% + - Class 10.1 (Passenger vehicles >$30k): 30% + * useful_life: Expected years of use (e.g., 5 for computers, 8 for vehicles, 10 for furniture) + * residual_value: Estimated value at end of life (typically 10% of purchase price for equipment, 20% for vehicles) + - If is_depreciable is false, set name_of_asset, cca_rate, useful_life, and residual_value to null + + Return only valid JSON. + +INFO:httpx:HTTP Request: POST https://api.groq.com/openai/v1/chat/completions "HTTP/1.1 200 OK" +INFO:__main__:Extracted receipt data: {'vendor': 'Eleven Labs Inc.', 'description': 'Pro Jun 10 - Jul 10, 2025', 'total_amount': 111.87, 'tax_amount': 12.87, 'date': '2025-06-10', 'category': 'cloud service', 'confidence': 0.95, 'currency': 'USD', 'location': 'New York, United States', 'calculated_tax': None, 'is_depreciable': False, 'name_of_asset': None, 'cca_rate': None, 'useful_life': None, 'residual_value': None, 'extraction_success': True} +INFO: 102.88.104.195:174 - "POST /process/da8b53da-c5c4-43df-9ea1-3765c7ad73df HTTP/1.1" 200 OK