Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Depends, Request, HTTPException, status | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from contextlib import asynccontextmanager | |
| import uvicorn | |
| import os | |
| import sys | |
| import logging | |
| from dotenv import load_dotenv | |
| from fastapi.responses import JSONResponse, PlainTextResponse | |
| from fastapi.staticfiles import StaticFiles | |
| import time | |
| import uuid | |
| import traceback | |
| # Cấu hình logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
| handlers=[ | |
| logging.StreamHandler(sys.stdout), | |
| ] | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Load environment variables | |
| load_dotenv() | |
| DEBUG = os.getenv("DEBUG", "False").lower() in ("true", "1", "t") | |
| # Kiểm tra các biến môi trường bắt buộc | |
| required_env_vars = [ | |
| "AIVEN_DB_URL", | |
| "MONGODB_URL", | |
| "PINECONE_API_KEY", | |
| "PINECONE_INDEX_NAME", | |
| "GOOGLE_API_KEY" | |
| ] | |
| missing_vars = [var for var in required_env_vars if not os.getenv(var)] | |
| if missing_vars: | |
| logger.error(f"Missing required environment variables: {', '.join(missing_vars)}") | |
| if not DEBUG: # Chỉ thoát nếu không ở chế độ debug | |
| sys.exit(1) | |
| # Database health checks | |
| def check_database_connections(): | |
| """Kiểm tra kết nối các database khi khởi động""" | |
| from app.database.postgresql import check_db_connection as check_postgresql | |
| from app.database.mongodb import check_db_connection as check_mongodb | |
| from app.database.pinecone import check_db_connection as check_pinecone | |
| db_status = { | |
| "postgresql": check_postgresql(), | |
| "mongodb": check_mongodb(), | |
| "pinecone": check_pinecone() | |
| } | |
| all_ok = all(db_status.values()) | |
| if not all_ok: | |
| failed_dbs = [name for name, status in db_status.items() if not status] | |
| logger.error(f"Failed to connect to databases: {', '.join(failed_dbs)}") | |
| if not DEBUG: # Chỉ thoát nếu không ở chế độ debug | |
| sys.exit(1) | |
| return db_status | |
| # Khởi tạo lifespan để kiểm tra kết nối database khi khởi động | |
| async def lifespan(app: FastAPI): | |
| # Startup: kiểm tra kết nối các database | |
| logger.info("Starting application...") | |
| db_status = check_database_connections() | |
| # Khởi tạo bảng trong cơ sở dữ liệu (nếu chưa tồn tại) | |
| if DEBUG and all(db_status.values()): # Chỉ khởi tạo bảng trong chế độ debug và khi tất cả kết nối DB thành công | |
| from app.database.postgresql import create_tables | |
| if create_tables(): | |
| logger.info("Database tables created or already exist") | |
| yield | |
| # Shutdown | |
| logger.info("Shutting down application...") | |
| # Import routers | |
| try: | |
| from app.api.mongodb_routes import router as mongodb_router | |
| from app.api.postgresql_routes import router as postgresql_router | |
| from app.api.rag_routes import router as rag_router | |
| from app.api.websocket_routes import router as websocket_router | |
| from app.api.pdf_routes import router as pdf_router | |
| from app.api.pdf_websocket import router as pdf_websocket_router | |
| # Import middlewares | |
| from app.utils.middleware import RequestLoggingMiddleware, ErrorHandlingMiddleware, DatabaseCheckMiddleware | |
| # Import debug utilities | |
| from app.utils.debug_utils import debug_view, DebugInfo, error_tracker, performance_monitor | |
| # Import cache | |
| from app.utils.cache import get_cache | |
| logger.info("Successfully imported all routers and modules") | |
| except ImportError as e: | |
| logger.error(f"Error importing routes or middlewares: {e}") | |
| raise | |
| # Create FastAPI app | |
| app = FastAPI( | |
| title="PIX Project Backend API", | |
| description="Backend API for PIX Project with MongoDB, PostgreSQL and RAG integration", | |
| version="1.0.0", | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| debug=DEBUG, | |
| lifespan=lifespan, | |
| ) | |
| # Configure CORS | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Thêm middlewares | |
| app.add_middleware(ErrorHandlingMiddleware) | |
| app.add_middleware(RequestLoggingMiddleware) | |
| if not DEBUG: # Chỉ thêm middleware kiểm tra database trong production | |
| app.add_middleware(DatabaseCheckMiddleware) | |
| # Include routers | |
| app.include_router(mongodb_router) | |
| app.include_router(postgresql_router) | |
| app.include_router(rag_router) | |
| app.include_router(websocket_router) | |
| app.include_router(pdf_router) | |
| app.include_router(pdf_websocket_router) | |
| # Log all registered routes | |
| logger.info("Registered API routes:") | |
| for route in app.routes: | |
| if hasattr(route, "path") and hasattr(route, "methods"): | |
| methods = ",".join(route.methods) | |
| logger.info(f" {methods:<10} {route.path}") | |
| # Root endpoint | |
| def read_root(): | |
| return { | |
| "message": "Welcome to PIX Project Backend API", | |
| "documentation": "/docs", | |
| } | |
| # Health check endpoint | |
| def health_check(): | |
| # Kiểm tra kết nối database | |
| db_status = check_database_connections() | |
| all_db_ok = all(db_status.values()) | |
| return { | |
| "status": "healthy" if all_db_ok else "degraded", | |
| "version": "1.0.0", | |
| "environment": os.environ.get("ENVIRONMENT", "production"), | |
| "databases": db_status | |
| } | |
| async def ping(): | |
| return {"status": "pong"} | |
| # Cache stats endpoint | |
| def cache_stats(): | |
| """Trả về thống kê về cache""" | |
| cache = get_cache() | |
| return cache.stats() | |
| # Cache clear endpoint | |
| def cache_clear(): | |
| """Xóa tất cả dữ liệu trong cache""" | |
| cache = get_cache() | |
| cache.clear() | |
| return {"message": "Cache cleared successfully"} | |
| # Debug endpoints (chỉ có trong chế độ debug) | |
| if DEBUG: | |
| def debug_config(): | |
| """Hiển thị thông tin cấu hình (chỉ trong chế độ debug)""" | |
| config = { | |
| "environment": os.environ.get("ENVIRONMENT", "production"), | |
| "debug": DEBUG, | |
| "db_connection_mode": os.environ.get("DB_CONNECTION_MODE", "aiven"), | |
| "databases": { | |
| "postgresql": os.environ.get("AIVEN_DB_URL", "").split("@")[1].split("/")[0] if "@" in os.environ.get("AIVEN_DB_URL", "") else "N/A", | |
| "mongodb": os.environ.get("MONGODB_URL", "").split("@")[1].split("/?")[0] if "@" in os.environ.get("MONGODB_URL", "") else "N/A", | |
| "pinecone": os.environ.get("PINECONE_INDEX_NAME", "N/A"), | |
| } | |
| } | |
| return config | |
| def debug_system(): | |
| """Hiển thị thông tin hệ thống (chỉ trong chế độ debug)""" | |
| return DebugInfo.get_system_info() | |
| def debug_database(): | |
| """Hiển thị trạng thái database (chỉ trong chế độ debug)""" | |
| return DebugInfo.get_database_status() | |
| def debug_errors(limit: int = 10): | |
| """Hiển thị các lỗi gần đây (chỉ trong chế độ debug)""" | |
| return error_tracker.get_errors(limit=limit) | |
| def debug_performance(): | |
| """Hiển thị thông tin hiệu suất (chỉ trong chế độ debug)""" | |
| return performance_monitor.get_report() | |
| def debug_full_report(request: Request): | |
| """Hiển thị báo cáo debug đầy đủ (chỉ trong chế độ debug)""" | |
| return debug_view(request) | |
| def debug_cache(): | |
| """Hiển thị thông tin chi tiết về cache (chỉ trong chế độ debug)""" | |
| cache = get_cache() | |
| cache_stats = cache.stats() | |
| # Thêm thông tin chi tiết về các key trong cache | |
| cache_keys = list(cache.cache.keys()) | |
| history_users = list(cache.user_history_queues.keys()) | |
| return { | |
| "stats": cache_stats, | |
| "keys": cache_keys, | |
| "history_users": history_users, | |
| "config": { | |
| "ttl": cache.ttl, | |
| "cleanup_interval": cache.cleanup_interval, | |
| "max_size": cache.max_size, | |
| "history_queue_size": os.getenv("HISTORY_QUEUE_SIZE", "10"), | |
| "history_cache_ttl": os.getenv("HISTORY_CACHE_TTL", "3600"), | |
| } | |
| } | |
| def debug_websocket_routes(): | |
| """Hiển thị thông tin về các WebSocket route (chỉ trong chế độ debug)""" | |
| ws_routes = [] | |
| for route in app.routes: | |
| if "websocket" in str(route.__class__).lower(): | |
| ws_routes.append({ | |
| "path": route.path, | |
| "name": route.name, | |
| "endpoint": str(route.endpoint) | |
| }) | |
| return { | |
| "websocket_routes": ws_routes, | |
| "total_count": len(ws_routes) | |
| } | |
| def debug_mock_status(): | |
| """Display current mock mode settings""" | |
| # Import was: from app.api.pdf_routes import USE_MOCK_MODE | |
| # We've disabled mock mode | |
| return { | |
| "mock_mode": False, # Disabled - using real database | |
| "mock_env_variable": os.getenv("USE_MOCK_MODE", "false"), | |
| "debug_mode": DEBUG | |
| } | |
| # Run the app with uvicorn when executed directly | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("PORT", 7860)) | |
| uvicorn.run("app:app", host="0.0.0.0", port=port, reload=DEBUG) | |