from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from app.services.rag_service import RAGService from app.services.bot_service import BotService from app.utils.schedule_manager import ScheduleManager from app.models import ChatRequest, ChatResponse, BookInfo, UploadResponse, ScheduleInfo, ScheduleRequest import os import json from typing import List # Initialize services qdrant_service = QdrantService(os.getenv("QDRANT_URL", "http://qdrant:6333")) rag_service = RAGService(qdrant_service, model_name=os.getenv("GPT4ALL_MODEL", "llama-3.2-3b-instruct-q4_0.gguf")) bot_service = BotService(os.getenv("TELEGRAM_BOT_TOKEN", ""), os.getenv("TELEGRAM_CHAT_ID", "")) schedule_manager = ScheduleManager(os.getenv("SCHEDULES_PATH", "/app/schedules.json")) app = FastAPI(title="Espiritismo RAG API") # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Mount static files app.mount("/static", StaticFiles(directory="../frontend/static"), name="static") # Load existing schedules from file def load_schedules(): if os.path.exists("/app/schedules.json"): with open("/app/schedules.json", "r") as f: return json.load(f) return [] @app.get("/", response_class=HTMLResponse) async def index(): """Serve the index page.""" with open("../backend/templates/index.html", "r") as f: return f.read() @app.get("/api/books", response_model=List[BookInfo]) async def get_books(): """Get list of books in the collection.""" books = qdrant_service.get_books() return [{"title": book, "source": book} for book in books] @app.post("/api/chat", response_model=ChatResponse) async def chat(request: ChatRequest): """Query the RAG system.""" try: result = rag_service.query(request.message, request.top_k) return result except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.post("/api/upload", response_model=UploadResponse) async def upload_pdf(file: UploadFile = File(...)): """Upload a new PDF file.""" upload_dir = "/app/uploads" if not file.filename.endswith('.pdf'): raise HTTPException(status_code=400, detail="Only PDF files are allowed") file_path = os.path.join(upload_dir, file.filename) try: with open(file_path, "wb") as f: content = await file.read() f.write(content) return UploadResponse(message="File uploaded successfully", filename=file.filename) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/api/schedules", response_model=List[ScheduleInfo]) async def get_schedules(): """Get all schedules.""" schedules = load_schedules() return [ScheduleInfo(**s) for s in schedules] @app.post("/api/schedules", response_model=ScheduleInfo) async def create_schedule(request: ScheduleRequest): """Create a new schedule.""" schedules = load_schedules() new_schedule = { "id": len(schedules) + 1, "time": request.time, "book": request.book, "enabled": request.enabled, } schedules.append(new_schedule) with open("/app/schedules.json", "w") as f: json.dump(schedules, f, indent=2) # Start celery beat if needed try: bot_service.add_schedule(new_schedule) except Exception as e: print(f"Warning: Could not add schedule to bot: {e}") return ScheduleInfo(**new_schedule) @app.put("/api/schedules/{schedule_id}", response_model=ScheduleInfo) async def update_schedule(schedule_id: int, request: ScheduleRequest): """Update an existing schedule.""" schedules = load_schedules() for i, s in enumerate(schedules): if s["id"] == schedule_id: schedules[i] = { "id": schedule_id, "time": request.time, "book": request.book, "enabled": request.enabled, } with open("/app/schedules.json", "w") as f: json.dump(schedules, f, indent=2) try: bot_service.update_schedule(schedules[i]) except Exception as e: print(f"Warning: Could not update schedule in bot: {e}") return ScheduleInfo(**schedules[i]) raise HTTPException(status_code=404, detail="Schedule not found") @app.delete("/api/schedules/{schedule_id}") async def delete_schedule(schedule_id: int): """Delete a schedule.""" schedules = load_schedules() for i, s in enumerate(schedules): if s["id"] == schedule_id: deleted = schedules.pop(i) with open("/app/schedules.json", "w") as f: json.dump(schedules, f, indent=2) try: bot_service.remove_schedule(deleted) except Exception as e: print(f"Warning: Could not remove schedule from bot: {e}") return {"message": "Schedule deleted"} raise HTTPException(status_code=404, detail="Schedule not found")