|
|
import time |
|
|
from typing import Any |
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException |
|
|
from fastapi.responses import JSONResponse |
|
|
|
|
|
from app.dependencies import get_api_logger, get_category_service |
|
|
from app.schemas.categories import CategorizeRequest, CategorizeResponse |
|
|
from app.services.autocategorizer import AutoCategoryService |
|
|
from app.services.api_logger import ApiLogger |
|
|
|
|
|
router = APIRouter() |
|
|
|
|
|
|
|
|
@router.post("/categorize", response_model=CategorizeResponse, summary="Categorize a transaction note") |
|
|
async def categorize_transaction( |
|
|
payload: CategorizeRequest, |
|
|
service: AutoCategoryService = Depends(get_category_service), |
|
|
api_logger: ApiLogger = Depends(get_api_logger), |
|
|
) -> CategorizeResponse | JSONResponse: |
|
|
started_at = time.monotonic() |
|
|
try: |
|
|
result = await service.categorize(payload.notes, payload.user_id) |
|
|
await api_logger.log_categorization( |
|
|
name="Auto Expense Categorization", |
|
|
status="success", |
|
|
response_time=time.monotonic() - started_at, |
|
|
user_id=payload.user_id, |
|
|
) |
|
|
return CategorizeResponse(status="success", data=result, message="Categorization logged in database.") |
|
|
except HTTPException as exc: |
|
|
await api_logger.log_categorization( |
|
|
name="Auto Expense Categorization", |
|
|
status="fail", |
|
|
response_time=time.monotonic() - started_at, |
|
|
user_id=payload.user_id, |
|
|
error_message=_normalize_error_detail(exc.detail), |
|
|
) |
|
|
return JSONResponse( |
|
|
status_code=exc.status_code, |
|
|
content={"status": "fail", "message": _normalize_error_detail(exc.detail)}, |
|
|
) |
|
|
except Exception as exc: |
|
|
error_message = str(exc) |
|
|
error_type = type(exc).__name__ |
|
|
await api_logger.log_categorization( |
|
|
name="Auto Expense Categorization", |
|
|
status="fail", |
|
|
response_time=time.monotonic() - started_at, |
|
|
user_id=payload.user_id, |
|
|
error_message=f"{error_type}: {error_message}", |
|
|
) |
|
|
|
|
|
return JSONResponse( |
|
|
status_code=500, |
|
|
content={ |
|
|
"status": "fail", |
|
|
"message": f"Internal server error: {error_type} - {error_message}", |
|
|
}, |
|
|
) |
|
|
|
|
|
|
|
|
def _normalize_error_detail(detail: Any) -> str: |
|
|
if isinstance(detail, str): |
|
|
return detail |
|
|
return str(detail) |
|
|
|