feat: Implement core application structure, AI extraction, persistence, and Telegram bot modules with updated configuration and dependencies.

This commit is contained in:
Marco Gallegos
2025-12-18 12:15:04 -06:00
parent 7276e480b0
commit 899482580e
45 changed files with 1157 additions and 225 deletions

80
app/schema/base.py Normal file
View File

@@ -0,0 +1,80 @@
from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime, date
from enum import Enum
class ExpenseStatus(str, Enum):
"""
Defines the explicit states an expense can be in throughout its lifecycle.
"""
RECEIVED = "RECEIVED"
ANALYZED = "ANALYZED"
AWAITING_CONFIRMATION = "AWAITING_CONFIRMATION"
CONFIRMED = "CONFIRMED"
CORRECTED = "CORRECTED"
STORED = "STORED"
class RawInput(BaseModel):
"""
Represents the raw data received from the input source (e.g., n8n).
"""
user_id: str
input_type: str = Field(..., alias="type", description="The type of input, e.g., 'text', 'voice', 'image', 'pdf'")
data: str
class ExtractedExpense(BaseModel):
"""
Represents an expense after initial data extraction (e.g., from OCR or transcription).
Fields are mostly optional as extraction may not be perfect.
"""
provider_name: Optional[str] = None
amount: Optional[float] = None
currency: Optional[str] = "MXN"
expense_date: Optional[date] = None
description: Optional[str] = None
raw_text: str
class ProvisionalExpense(BaseModel):
"""
Represents a fully processed but unconfirmed expense.
This is the state before the user validates the data.
"""
user_id: str
extracted_data: ExtractedExpense
# Classified fields
category: Optional[str] = "Por Determinar"
subcategory: Optional[str] = None
expense_type: Optional[str] = Field(None, alias="tipo_gasto_default", description="e.g., 'personal' or 'negocio'")
# Metadata
confidence_score: float
processing_method: str = Field(..., description="How the expense was classified, e.g., 'provider_match', 'keyword_match', 'ai_inference'")
validation_notes: List[str] = []
status: ExpenseStatus = ExpenseStatus.AWAITING_CONFIRMATION
timestamp: datetime = Field(default_factory=datetime.now)
class FinalExpense(BaseModel):
"""
Represents a final, user-confirmed expense record.
This is the data that will be stored permanently.
"""
user_id: str
provider_name: str
amount: float
currency: str
expense_date: date
description: Optional[str] = None
category: str
subcategory: Optional[str] = None
expense_type: str
# Audit trail
initial_processing_method: str
confirmed_by: str
confirmed_at: datetime = Field(default_factory=datetime.now)
audit_log: List[str] = []
status: ExpenseStatus = ExpenseStatus.CONFIRMED