import logging from threading import Lock from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from pydantic import BaseModel from ingest import ingest_books from query import ask_question, clear_history app = FastAPI(title="MindBot API", version="1.0.0") logger = logging.getLogger(__name__) app.mount("/static", StaticFiles(directory="static"), name="static") _ingest_lock = Lock() _knowledge_ready = False class AskRequest(BaseModel): question: str @app.get("/") def index(): return FileResponse("static/index.html") def ensure_knowledge_ready() -> None: global _knowledge_ready if _knowledge_ready: return with _ingest_lock: if _knowledge_ready: return ingest_books("knowledge") _knowledge_ready = True @app.post("/ask") def ask(payload: AskRequest): question = payload.question.strip() if not question: raise HTTPException(status_code=400, detail="question is required") if question.lower() in {"/end", "/reset"}: clear_history() return { "answer": "Conversation history cleared.", "sources": [], } try: ensure_knowledge_ready() answer, docs = ask_question(question) except Exception: logger.exception("Failed to process ask request") raise HTTPException(status_code=500, detail="failed to process question") sources = [] seen = set() for doc in docs: book = doc.metadata.get("book") if hasattr(doc, "metadata") else None if book and book not in seen: seen.add(book) sources.append(book) return { "answer": answer, "sources": sources, }