import logging from fastapi import FastAPI, HTTPException, BackgroundTasks from pydantic import BaseModel from typing import List, Optional, Dict, Any import uvicorn import sys import os # Thêm thư mục gốc vào PYTHONPATH để tìm thấy các module chat, search, ingestion... sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from chat.rag_engine import RAGEngine from core.config import settings # Cấu hình Logging logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger("API") app = FastAPI( title="PoC SharePoint RAG API", description="Hệ thống hỏi đáp nội bộ dựa trên SharePoint và Distributed VLM", version="1.0.0" ) # Khởi tạo RAG Engine (Singleton) # Khi API khởi động, nó sẽ nạp sẵn Embedding Model vào RAM để phản hồi cực nhanh try: if settings.opensearch_host == "opensearch": settings.opensearch_host = "localhost" # Fallback cho Local Dev rag_engine = RAGEngine() except Exception as e: logger.error(f"Không thể khởi động RAG Engine: {e}") rag_engine = None # --- MODELS --- class ChatRequest(BaseModel): query: str history: Optional[List[Dict[str, str]]] = [] class ChatResponse(BaseModel): answer: str sources: List[Dict[str, Any]] = [] # --- ENDPOINTS --- @app.get("/health") def health_check(): """Kiểm tra sức khỏe hệ thống""" return { "status": "healthy", "llm_provider": settings.llm_provider, "opensearch_host": settings.opensearch_host } @app.post("/chat", response_model=ChatResponse) async def chat_endpoint(request: ChatRequest): """ Điểm cuối để thực hiện hỏi đáp (RAG). """ if not rag_engine: raise HTTPException(status_code=503, detail="RAG Engine chưa được khởi tạo thành công.") try: logger.info(f"Nhận câu hỏi: {request.query}") result = rag_engine.chat(request.query, history=request.history) return ChatResponse( answer=result["answer"], sources=result["sources"] ) except Exception as e: logger.error(f"Lỗi xử lý chat: {e}") raise HTTPException(status_code=500, detail=str(e)) @app.post("/ingest") async def start_ingestion(background_tasks: BackgroundTasks): """ Kích hoạt quá trình quét SharePoint và nạp dữ liệu vào OpenSearch. Chạy dưới dạng Background Task để không làm treo API. """ # TODO: Kết nối với script sync.py và quy trình extraction # Ở đây chúng ta sẽ gọi một function xử lý bất đồng bộ background_tasks.add_task(dummy_ingest_task) return {"message": "Quá trình đồng bộ dữ liệu đã bắt đầu chạy ngầm."} async def dummy_ingest_task(): logger.info("Bắt đầu Ingestion task...") # Sẽ tích hợp logic từ test_rag_pipeline.py vào đây pass if __name__ == "__main__": # Chạy server tại cổng 8000 uvicorn.run(app, host="0.0.0.0", port=8000)