Files
telegram_expenses_controller/app/main.py

85 lines
2.9 KiB
Python

"""
Application entry point.
Initializes the FastAPI application, sets up logging, database,
and defines the main API endpoints.
"""
import logging
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
# It's crucial to set up the config before other imports
from app.config import config
# Now, set up logging based on the config
logging.basicConfig(level=config.LOG_LEVEL.upper())
logger = logging.getLogger(__name__)
# Import other components
from app.schema.base import RawInput
from app.router import process_expense_input
from app.persistence import repositories, db
# Create database tables on startup
# This is simple, but for production, you'd use migrations (e.g., Alembic)
repositories.create_tables()
# Initialize the FastAPI app
app = FastAPI(
title="Telegram Expenses Bot API",
description="Processes and manages expense data from various sources.",
version="1.0.0"
)
@app.on_event("startup")
async def startup_event():
logger.info("Application startup complete.")
logger.info(f"Log level is set to: {config.LOG_LEVEL.upper()}")
@app.get("/", tags=["Status"])
async def root():
"""Health check endpoint."""
return {"message": "Telegram Expenses Bot API is running."}
@app.post("/webhook/telegram", tags=["Webhooks"])
async def process_telegram_update(request: dict):
"""
This endpoint would receive updates directly from a Telegram webhook.
It needs to be implemented to parse the Telegram Update object and
convert it into our internal RawInput model.
"""
logger.info(f"Received Telegram update: {request}")
# TODO: Implement a parser for the Telegram Update object.
# For now, this is a placeholder.
return {"status": "received", "message": "Telegram webhook handler not fully implemented."}
@app.post("/process-expense", tags=["Processing"])
async def process_expense(raw_input: RawInput, db_session: Session = Depends(db.get_db)):
"""
Receives raw expense data, processes it through the full pipeline,
and returns the result.
"""
logger.info(f"Received raw input for processing: {raw_input.dict()}")
try:
result = process_expense_input(db=db_session, raw_input=raw_input)
if result:
return {"status": "success", "expense_id": result.id}
else:
# This could happen if confidence is low or an error occurred
raise HTTPException(
status_code=400,
detail="Failed to process expense. It may require manual review or had invalid data."
)
except ValueError as e:
logger.error(f"Validation error: {e}")
raise HTTPException(status_code=422, detail=str(e))
except Exception as e:
logger.critical(f"An unexpected error occurred in the processing pipeline: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="An internal server error occurred.")
# To run this app:
# uvicorn app.main:app --reload