Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| import os | |
| import uuid | |
| from fastapi import FastAPI, Depends, Header, HTTPException, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.templating import Jinja2Templates | |
| from .config import get_database | |
| from .storage import BankingStorage, ChatHistoryStore | |
| from .vectorstore import VectorStore | |
| from chatbot.responder import GeminiChatResponder | |
| from chatbot.service import ChatbotService | |
| def create_app() -> FastAPI: | |
| base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) | |
| templates = os.path.join(base_dir, "templates") | |
| static_dir = os.path.join(base_dir, "static") | |
| app = FastAPI(title="Aurora Banking Chatbot") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| app.mount("/static", StaticFiles(directory=static_dir), name="static") | |
| template_engine = Jinja2Templates(directory=templates) | |
| database = get_database() | |
| storage = BankingStorage(database) | |
| history = ChatHistoryStore(storage.chat_sessions) | |
| vectors = VectorStore() | |
| vectors.bootstrap(storage.all_users()) | |
| responder = GeminiChatResponder() | |
| service = ChatbotService(storage, history, vectors, responder) | |
| sessions: dict[str, str] = {} | |
| def get_session(authorization: str = Header(None)) -> tuple[str, str]: | |
| if not authorization or not authorization.startswith("Bearer "): | |
| raise HTTPException(status_code=401, detail="Unauthorized") | |
| token = authorization.split(" ")[1] | |
| username = sessions.get(token) | |
| if not username: | |
| raise HTTPException(status_code=401, detail="Unauthorized") | |
| return username, token | |
| async def index(request: Request): | |
| return template_engine.TemplateResponse("index.html", {"request": request}) | |
| async def login(payload: dict): | |
| username = payload.get("username", "").lower() | |
| password = payload.get("password", "") | |
| user_record = storage.authenticate(username, password) | |
| if not user_record: | |
| raise HTTPException(status_code=401, detail="Invalid credentials") | |
| token = uuid.uuid4().hex | |
| sessions[token] = username | |
| history.reset(token, username) | |
| snapshot = service.load_snapshot(username) | |
| return {"token": token, "user": {"username": username}, "snapshot": snapshot} | |
| async def chat(payload: dict, session=Depends(get_session)): | |
| username, token = session | |
| message = (payload.get("message") or "").strip() | |
| if not message: | |
| raise HTTPException(status_code=400, detail="Message cannot be empty") | |
| reply, action_details, backend_data, updated_history, snapshot_after = service.run_agent( | |
| username, token, message | |
| ) | |
| return { | |
| "reply": reply, | |
| "history": updated_history, | |
| "action": action_details, | |
| "backend": backend_data, | |
| "snapshot": snapshot_after, | |
| } | |
| async def list_accounts(session=Depends(get_session)): | |
| username, _ = session | |
| return {"accounts": storage.list_accounts(username)} | |
| async def list_transactions(account_id: str | None = None, session=Depends(get_session)): | |
| username, _ = session | |
| return {"transactions": storage.list_transactions(username, account_id)} | |
| async def list_beneficiaries(session=Depends(get_session)): | |
| username, _ = session | |
| return {"beneficiaries": storage.list_beneficiaries(username)} | |
| async def add_beneficiary(payload: dict, session=Depends(get_session)): | |
| username, _ = session | |
| required = ["name", "account_number", "bank"] | |
| if not all(payload.get(field) for field in required): | |
| raise HTTPException(status_code=400, detail="Missing beneficiary details") | |
| result = storage.add_beneficiary(username, payload) | |
| vectors.rebuild_user(username, storage.get_user(username) or {}) | |
| return {"beneficiary": result} | |
| async def transfer_funds(payload: dict, session=Depends(get_session)): | |
| username, _ = session | |
| try: | |
| amount = float(payload.get("amount", 0)) | |
| except (TypeError, ValueError): | |
| raise HTTPException(status_code=400, detail="Amount must be numeric") | |
| if amount <= 0: | |
| raise HTTPException(status_code=400, detail="Transfer amount must be positive") | |
| for key in ["from_account_id", "beneficiary_id"]: | |
| if not payload.get(key): | |
| raise HTTPException(status_code=400, detail=f"Missing {key}") | |
| try: | |
| transaction, account = storage.transfer_funds( | |
| username, | |
| payload["from_account_id"], | |
| payload["beneficiary_id"], | |
| amount, | |
| payload.get("description", "Transfer to beneficiary"), | |
| ) | |
| except ValueError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) | |
| if not transaction: | |
| raise HTTPException(status_code=400, detail="Unable to complete transfer") | |
| vectors.rebuild_user(username, storage.get_user(username) or {}) | |
| return {"transaction": transaction, "account": account} | |
| async def transfer_between_accounts(payload: dict, session=Depends(get_session)): | |
| username, _ = session | |
| try: | |
| amount = float(payload.get("amount", 0)) | |
| except (TypeError, ValueError): | |
| raise HTTPException(status_code=400, detail="Amount must be numeric") | |
| if amount <= 0: | |
| raise HTTPException(status_code=400, detail="Transfer amount must be positive") | |
| for key in ["from_account_id", "to_account_id"]: | |
| if not payload.get(key): | |
| raise HTTPException(status_code=400, detail=f"Missing {key}") | |
| try: | |
| result = storage.transfer_between_accounts( | |
| username, | |
| payload["from_account_id"], | |
| payload["to_account_id"], | |
| amount, | |
| payload.get("description", "Transfer between accounts"), | |
| ) | |
| except ValueError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) | |
| if not result: | |
| raise HTTPException(status_code=400, detail="Unable to complete transfer") | |
| vectors.rebuild_user(username, storage.get_user(username) or {}) | |
| return result | |
| return app | |