Add AI rules support for document processing and matching; enhance tax analysis with flag_for_review and auto_approve fields

This commit is contained in:
bolade
2025-10-08 00:12:09 +01:00
parent f582110674
commit 2e020437a8
5 changed files with 394 additions and 49 deletions
+37 -9
View File
@@ -18,7 +18,11 @@ class DocumentProcessor:
self.model = "meta-llama/llama-4-scout-17b-16e-instruct" # Vision model
async def process_file(
self, file_path: str, file_type: str, user_location: str = None
self,
file_path: str,
file_type: str,
user_location: str = None,
ai_rules: list = None,
) -> Dict[str, Any]:
"""Process uploaded file and extract receipt data
@@ -26,25 +30,27 @@ class DocumentProcessor:
file_path: Path to the file to process
file_type: Type of file (jpg, pdf, etc.)
user_location: User's location string in format "State/Province, Country" (e.g., "Ontario, Canada")
ai_rules: List of AI rules for categorization (e.g., [{"condition": "vendor is Starbucks", "action": "Food"}])
"""
try:
if file_type.lower() in ["jpg", "jpeg", "png", "gif", "bmp"]:
return await self._process_image(file_path, user_location)
return await self._process_image(file_path, user_location, ai_rules)
elif file_type.lower() == "pdf":
return await self._process_pdf(file_path, user_location)
return await self._process_pdf(file_path, user_location, ai_rules)
else:
raise ValueError(f"Unsupported file type: {file_type}")
except Exception as e:
return {"error": str(e)}
async def _process_image(
self, image_path: str, user_location: str = None
self, image_path: str, user_location: str = None, ai_rules: list = None
) -> Dict[str, Any]:
"""Extract data from image using Groq vision
Args:
image_path: Path to the image file
user_location: User's location string in format "State/Province, Country" (e.g., "Ontario, Canada")
ai_rules: List of AI rules for categorization
"""
try:
# Encode image to base64
@@ -62,6 +68,16 @@ class DocumentProcessor:
- Apply depreciation rules based on the user's location.
"""
# 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):"
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"
# Create Groq vision prompt
prompt = f"""
Analyze this receipt image and extract the following information in JSON format:
@@ -89,9 +105,9 @@ class DocumentProcessor:
- 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
- Categorize based on vendor type (Starbucks=Food, Shell=Transport, etc.)
- 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)
@@ -166,18 +182,19 @@ class DocumentProcessor:
return base64.b64encode(image_file.read()).decode("utf-8")
async def _process_pdf(
self, pdf_path: str, user_location: str = None
self, pdf_path: str, user_location: str = None, ai_rules: list = None
) -> Dict[str, Any]:
"""Extract data from PDF by converting to image first
Args:
pdf_path: Path to the PDF file
user_location: User's location string in format "State/Province, Country" (e.g., "Ontario, Canada")
ai_rules: List of AI rules for categorization
"""
try:
# For now, extract text from PDF and process as text
text_content = self._extract_text_from_pdf(pdf_path)
return self._process_text_content(text_content, user_location)
return self._process_text_content(text_content, user_location, ai_rules)
except Exception as e:
return {"error": f"PDF processing error: {str(e)}"}
@@ -195,13 +212,14 @@ class DocumentProcessor:
return ""
def _process_text_content(
self, text_content: str, user_location: str = None
self, text_content: str, user_location: str = None, ai_rules: list = None
) -> Dict[str, Any]:
"""Process text content using Groq (fallback for PDFs)
Args:
text_content: Extracted text from PDF
user_location: User's location string in format "State/Province, Country" (e.g., "Ontario, Canada")
ai_rules: List of AI rules for categorization
"""
try:
# Build user location context
@@ -216,6 +234,16 @@ class DocumentProcessor:
- Apply depreciation rules based on the user's location.
"""
# 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):"
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"
prompt = f"""
Analyze this receipt text and extract the following information in JSON format:
@@ -247,9 +275,9 @@ class DocumentProcessor:
- 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
- Categorize based on vendor type
- 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)