from fastapi import FastAPI, Request, HTTPException, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse, HTMLResponse from api import api_router import gradio as gr import requests import logging import time import aiohttp import asyncio from typing import Optional # Configure logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) logger.debug("Initializing application") app = FastAPI() # CORS Configuration app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(api_router) # Constants BACKEND_URL = "https://rocketfarmstudios-cps-api.hf.space" ADMIN_EMAIL = "yakdhanali97@gmail.com" ADMIN_PASSWORD = "123456" MAX_TOKEN_RETRIES = 3 TOKEN_RETRY_DELAY = 2 # seconds class TokenManager: def __init__(self): self.token = None self.last_refresh = 0 self.expires_in = 3600 # 1 hour default expiry self.lock = asyncio.Lock() async def _make_login_request(self) -> Optional[str]: try: async with aiohttp.ClientSession() as session: async with session.post( f"{BACKEND_URL}/auth/login", json={ "username": ADMIN_EMAIL, "password": ADMIN_PASSWORD, "device_token": "admin-device-token" }, timeout=10 ) as response: if response.status == 200: data = await response.json() return data.get("access_token") else: error = await response.text() logger.error(f"Login failed: {response.status} - {error}") return None except Exception as e: logger.error(f"Login request error: {str(e)}") return None async def refresh_token(self) -> str: async with self.lock: for attempt in range(MAX_TOKEN_RETRIES): token = await self._make_login_request() if token: self.token = token self.last_refresh = time.time() logger.info("Successfully refreshed admin token") return token wait_time = min(5, (attempt + 1) * 2) # Exponential backoff with max 5s logger.warning(f"Attempt {attempt + 1} failed, retrying in {wait_time}s...") await asyncio.sleep(wait_time) raise Exception("Failed to obtain admin token after multiple attempts") async def get_token(self) -> str: if not self.token or (time.time() - self.last_refresh) > (self.expires_in - 60): return await self.refresh_token() return self.token token_manager = TokenManager() @app.get("/") def root(): logger.debug("Root endpoint accessed") return {"message": "🚀 FastAPI with MongoDB + JWT is running."} @app.post("/login") async def redirect_login(request: Request): logger.info("Redirecting /login to /auth/login") return RedirectResponse(url="/auth/login", status_code=307) def authenticate_admin(email: str = None, password: str = None): if email != ADMIN_EMAIL or password != ADMIN_PASSWORD: logger.warning(f"Failed admin login attempt with email: {email}") raise HTTPException(status_code=401, detail="Unauthorized: Invalid email or password") logger.info(f"Admin authenticated successfully: {email}") return True async def async_create_doctor(full_name, email, matricule, password, specialty): try: token = await token_manager.get_token() payload = { "full_name": full_name, "email": email, "license_number": matricule, "password": password, "specialty": specialty, } headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } async with aiohttp.ClientSession() as session: async with session.post( f"{BACKEND_URL}/auth/admin/doctors", json=payload, headers=headers, timeout=10 ) as response: if response.status == 201: return "✅ Doctor created successfully!" elif response.status == 401: # Token might be expired logger.warning("Token expired, attempting refresh...") token = await token_manager.refresh_token() headers["Authorization"] = f"Bearer {token}" async with session.post( f"{BACKEND_URL}/auth/admin/doctors", json=payload, headers=headers, timeout=10 ) as retry_response: if retry_response.status == 201: return "✅ Doctor created successfully!" error_detail = await response.text() return f"❌ Error: {error_detail} (Status: {response.status})" except Exception as e: logger.error(f"Doctor creation failed: {str(e)}") return f"❌ System Error: {str(e)}" def sync_create_doctor(*args): return asyncio.run(async_create_doctor(*args)) admin_ui = gr.Blocks( css=""" .gradio-container { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; } .input-group { margin-bottom: 1.5rem; } input, select { width: 100%; padding: 0.5rem; margin-bottom: 1rem; } button { background-color: #4a6fa5; color: white; padding: 0.75rem; border: none; border-radius: 4px; cursor: pointer; width: 100%; } """ ) with admin_ui: gr.Markdown("# Doctor Account Creator") with gr.Column(): full_name = gr.Textbox(label="Full Name") email = gr.Textbox(label="Email") matricule = gr.Textbox(label="License Number") specialty = gr.Dropdown( label="Specialty", choices=["General Practice", "Cardiology", "Neurology", "Pediatrics"] ) password = gr.Textbox(label="Password", type="password") submit_btn = gr.Button("Create Account") output = gr.Textbox(label="Status", interactive=False) submit_btn.click( fn=sync_create_doctor, inputs=[full_name, email, matricule, specialty, password], outputs=output ) app = gr.mount_gradio_app(app, admin_ui, path="/admin-auth") @app.get("/admin") async def admin_dashboard(email: str = None, password: str = None, response: Response = None): logger.debug("Admin dashboard accessed") try: authenticate_admin(email, password) return RedirectResponse(url="/admin-auth", status_code=307) except HTTPException as e: response.status_code = 401 return HTMLResponse(content="""

401 Unauthorized

Invalid admin credentials

""") @app.on_event("startup") async def startup_event(): """Initialize token but don't fail startup""" try: await token_manager.get_token() except Exception as e: logger.error(f"Initial token fetch failed: {str(e)}") if __name__ == "__main__": logger.info("Starting application") import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)