from fastapi import FastAPI, Request, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse, JSONResponse from fastapi.exceptions import RequestValidationError from api import api_router import gradio as gr import requests import logging import os from datetime import datetime # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s', handlers=[ logging.StreamHandler(), logging.FileHandler('app.log') ] ) logger = logging.getLogger(__name__) app = FastAPI( title="Medical EHR System", description="Electronic Health Records Management API", version="1.0.0", docs_url="/docs", redoc_url="/redoc" ) # CORS Configuration app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"] ) # Include API routes app.include_router(api_router, prefix="/api/v1") @app.get("/") async def root(): logger.info("Root endpoint accessed") return {"message": "🚀 FastAPI with MongoDB + JWT is running", "status": "healthy"} @app.post("/login") async def redirect_login(request: Request): logger.info(f"Redirecting /login to /auth/login from {request.client.host}") return RedirectResponse(url="/auth/login", status_code=status.HTTP_307_TEMPORARY_REDIRECT) @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): logger.error(f"Validation error: {exc.errors()}") return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={"detail": exc.errors(), "body": exc.body}, ) @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): logger.error(f"HTTP error: {exc.detail}") return JSONResponse( status_code=exc.status_code, content={"detail": exc.detail}, headers=exc.headers ) @app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"detail": "Internal server error"}, ) # Gradio Interface Configuration BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:8000") def create_doctor(full_name: str, email: str, matricule: str, password: str, specialty: str): try: payload = { "full_name": full_name, "email": email, "license_number": matricule, "password": password, "specialty": specialty, } logger.info(f"Attempting to create doctor: {email}") response = requests.post( f"{BACKEND_URL}/auth/admin/doctors", json=payload, headers={"Content-Type": "application/json"}, timeout=10 ) if response.status_code == 201: logger.info(f"Successfully created doctor: {email}") return "✅ Doctor created successfully!" else: error_msg = response.json().get("detail", "Unknown error occurred") logger.error(f"Failed to create doctor {email}: {error_msg}") return f"❌ Error: {error_msg}" except requests.exceptions.RequestException as e: logger.error(f"Network error during doctor creation: {str(e)}") return f"❌ Network Error: {str(e)}" except Exception as e: logger.error(f"Unexpected error during doctor creation: {str(e)}") return f"❌ Unexpected Error: {str(e)}" def setup_gradio_interface(): with gr.Blocks( title="Doctor Management Portal", css=""" .gradio-container { max-width: 800px; margin: 0 auto; } .success { color: #4CAF50; } .error { color: #F44336; } """ ) as interface: gr.Markdown("# 👨‍⚕️ Doctor Account Management") with gr.Row(): with gr.Column(): full_name = gr.Textbox(label="Full Name", placeholder="Dr. John Smith") email = gr.Textbox(label="Email", placeholder="doctor@hospital.org") matricule = gr.Textbox(label="License Number", placeholder="MD-12345") specialty = gr.Dropdown( label="Specialty", choices=["Cardiology", "Neurology", "Pediatrics", "General Practice"], value="General Practice" ) password = gr.Textbox(label="Password", type="password") submit_btn = gr.Button("Create Doctor Account", variant="primary") with gr.Column(): output = gr.Textbox(label="Result", interactive=False) submit_btn.click( fn=create_doctor, inputs=[full_name, email, matricule, specialty, password], outputs=output ) return interface # Mount Gradio interface gradio_ui = setup_gradio_interface() app = gr.mount_gradio_app(app, gradio_ui, path="/admin") if __name__ == "__main__": import uvicorn uvicorn.run( app, host="0.0.0.0", port=int(os.getenv("PORT", 8000)), log_level="info", reload=True )