Ali2206 commited on
Commit
bee386a
·
verified ·
1 Parent(s): 39d0c6d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -148
app.py CHANGED
@@ -1,93 +1,68 @@
1
- from fastapi import FastAPI, Request, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from fastapi.responses import RedirectResponse
4
- from pydantic import BaseModel
5
  import gradio as gr
6
- import aiohttp
7
- import asyncio
8
  import logging
9
  import time
10
- import os
 
11
  from typing import Optional
12
- from fastapi import APIRouter
13
 
14
  # Configure logging
15
- logging.basicConfig(
16
- level=logging.DEBUG,
17
- format="%(asctime)s - %(levelname)s - %(name)s - %(message)s"
18
- )
19
  logger = logging.getLogger(__name__)
20
  logger.debug("Initializing application")
21
 
22
- # FastAPI app
23
  app = FastAPI()
24
 
25
- # CORS Configuration (broadened for Hugging Face Spaces)
26
  app.add_middleware(
27
  CORSMiddleware,
28
- allow_origins=["http://localhost:7860", "https://*.hf.space"],
29
  allow_credentials=True,
30
  allow_methods=["*"],
31
  allow_headers=["*"],
32
  )
33
 
34
- # API Router (placeholder; replace with actual api.py content)
35
- api_router = APIRouter()
36
 
37
- # Constants (load from environment variables)
38
- BACKEND_URL = os.getenv("BACKEND_URL", "https://rocketfarmstudios-cps-api.hf.space")
39
- ADMIN_EMAIL = os.getenv("ADMIN_EMAIL", "yakdhanali97@gmail.com")
40
- ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "123456")
41
  MAX_TOKEN_RETRIES = 3
42
  TOKEN_RETRY_DELAY = 2 # seconds
43
- TOKEN_EXPIRY = 3600 # 1 hour default expiry
44
-
45
- # Pydantic models
46
- class LoginPayload(BaseModel):
47
- username: str
48
- password: str
49
-
50
- class DoctorPayload(BaseModel):
51
- full_name: str
52
- email: str
53
- license_number: str
54
- password: str
55
- specialty: str
56
 
57
  class TokenManager:
58
  def __init__(self):
59
  self.token = None
60
  self.last_refresh = 0
61
- self.expires_in = TOKEN_EXPIRY
62
  self.lock = asyncio.Lock()
63
 
64
  async def _make_login_request(self) -> Optional[str]:
65
  try:
66
  async with aiohttp.ClientSession() as session:
67
- payload = LoginPayload(username=ADMIN_EMAIL, password=ADMIN_PASSWORD)
68
- login_url = f"{BACKEND_URL.rstrip('/')}/auth/login"
69
- logger.debug(f"Sending login request to {login_url} with payload: {payload.dict()}")
70
  async with session.post(
71
- login_url,
72
- json=payload.dict(),
73
- timeout=15,
74
- headers={"Content-Type": "application/json"}
 
 
 
75
  ) as response:
76
- logger.debug(f"Login response status: {response.status}, URL: {response.url}")
77
  if response.status == 200:
78
  data = await response.json()
79
- token = data.get("access_token")
80
- if not token:
81
- logger.error("No access_token in response")
82
- return None
83
- logger.info(f"Received token: {token[:10]}...")
84
- return token
85
  else:
86
  error = await response.text()
87
- logger.error(f"Login failed: {response.status} - {error}, URL: {response.url}")
88
  return None
89
- except aiohttp.ClientError as e:
90
- logger.error(f"Login request error: {str(e)}, URL: {login_url}")
91
  return None
92
 
93
  async def refresh_token(self) -> str:
@@ -100,11 +75,11 @@ class TokenManager:
100
  logger.info("Successfully refreshed admin token")
101
  return token
102
 
103
- wait_time = min(5, (attempt + 1) * TOKEN_RETRY_DELAY)
104
  logger.warning(f"Attempt {attempt + 1} failed, retrying in {wait_time}s...")
105
  await asyncio.sleep(wait_time)
106
 
107
- raise HTTPException(status_code=500, detail="Failed to obtain admin token after multiple attempts")
108
 
109
  async def get_token(self) -> str:
110
  if not self.token or (time.time() - self.last_refresh) > (self.expires_in - 60):
@@ -113,9 +88,6 @@ class TokenManager:
113
 
114
  token_manager = TokenManager()
115
 
116
- # Include API router
117
- app.include_router(api_router)
118
-
119
  @app.get("/")
120
  def root():
121
  logger.debug("Root endpoint accessed")
@@ -123,111 +95,65 @@ def root():
123
 
124
  @app.post("/login")
125
  async def redirect_login(request: Request):
126
- logger.info("Redirecting /login to /admin-auth")
127
- return RedirectResponse(url="/admin-auth", status_code=307)
128
 
129
- # Handle local /auth/login requests
130
- @app.post("/auth/login")
131
- async def handle_local_auth_login(request: Request):
132
- try:
133
- body = await request.json()
134
- except:
135
- body = {}
136
- logger.warning(f"Local /auth/login endpoint called with body: {body}")
137
- raise HTTPException(
138
- status_code=400,
139
- detail=f"Local /auth/login called incorrectly. Use the external backend API: {BACKEND_URL}/auth/login"
140
- )
141
-
142
- # Test endpoint to verify backend connectivity
143
- @app.get("/test-backend")
144
- async def test_backend():
145
- try:
146
- async with aiohttp.ClientSession() as session:
147
- test_url = f"{BACKEND_URL.rstrip('/')}/"
148
- logger.debug(f"Testing backend connectivity to {test_url}")
149
- async with session.get(test_url, timeout=5) as response:
150
- logger.debug(f"Test backend response status: {response.status}, URL: {response.url}")
151
- return {"status": response.status, "url": str(response.url), "message": await response.text()}
152
- except aiohttp.ClientError as e:
153
- logger.error(f"Test backend error: {str(e)}")
154
- return {"status": "error", "message": str(e)}
155
 
156
- async def async_create_doctor(full_name: str, email: str, license_number: str, specialty: str, password: str):
157
  try:
158
- # Validate inputs
159
- if not all([full_name, email, license_number, specialty, password]):
160
- logger.error("Doctor creation failed: All fields are required")
161
- raise HTTPException(status_code=422, detail="All fields are required")
162
-
163
  token = await token_manager.get_token()
164
 
165
- payload = DoctorPayload(
166
- full_name=full_name,
167
- email=email,
168
- license_number=license_number,
169
- password=password,
170
- specialty=specialty
171
- )
172
  headers = {
173
  "Authorization": f"Bearer {token}",
174
  "Content-Type": "application/json"
175
  }
176
 
177
- doctor_url = f"{BACKEND_URL.rstrip('/')}/auth/admin/doctors"
178
- logger.debug(f"Sending doctor creation request to {doctor_url} with payload: {payload.dict()}")
179
  async with aiohttp.ClientSession() as session:
180
  async with session.post(
181
- doctor_url,
182
- json=payload.dict(),
183
  headers=headers,
184
- timeout=15
185
  ) as response:
186
- logger.debug(f"Doctor creation response status: {response.status}, URL: {response.url}")
187
  if response.status == 201:
188
  return "✅ Doctor created successfully!"
189
- elif response.status == 401:
190
  logger.warning("Token expired, attempting refresh...")
191
  token = await token_manager.refresh_token()
192
  headers["Authorization"] = f"Bearer {token}"
193
  async with session.post(
194
- doctor_url,
195
- json=payload.dict(),
196
  headers=headers,
197
- timeout=15
198
  ) as retry_response:
199
- logger.debug(f"Retry doctor creation response status: {retry_response.status}, URL: {retry_response.url}")
200
  if retry_response.status == 201:
201
  return "✅ Doctor created successfully!"
202
- error_detail = await retry_response.text()
203
- return f"❌ Error: {error_detail} (Status: {retry_response.status})"
204
 
205
  error_detail = await response.text()
206
  return f"❌ Error: {error_detail} (Status: {response.status})"
207
 
208
- except HTTPException as e:
209
- logger.error(f"Doctor creation failed: {str(e)}")
210
- return f"❌ Error: {str(e)}"
211
  except Exception as e:
212
  logger.error(f"Doctor creation failed: {str(e)}")
213
  return f"❌ System Error: {str(e)}"
214
 
215
- def sync_create_doctor(full_name: str, email: str, license_number: str, specialty: str, password: str):
216
- return asyncio.run(async_create_doctor(full_name, email, license_number, specialty, password))
217
-
218
- # New endpoint for public doctor creation
219
- @app.post("/create-doctor")
220
- async def create_doctor(payload: DoctorPayload):
221
- result = await async_create_doctor(
222
- full_name=payload.full_name,
223
- email=payload.email,
224
- license_number=payload.license_number,
225
- specialty=payload.specialty,
226
- password=payload.password
227
- )
228
- return {"result": result}
229
 
230
- # Gradio UI
231
  admin_ui = gr.Blocks(
232
  css="""
233
  .gradio-container {
@@ -260,15 +186,14 @@ with admin_ui:
260
  gr.Markdown("# Doctor Account Creator")
261
 
262
  with gr.Column():
263
- full_name = gr.Textbox(label="Full Name", placeholder="e.g., Dr. John Doe")
264
- email = gr.Textbox(label="Email", placeholder="e.g., john.doe@example.com")
265
- matricule = gr.Textbox(label="License Number", placeholder="e.g., 12345")
266
  specialty = gr.Dropdown(
267
  label="Specialty",
268
- choices=["General Practice", "Cardiology", "Neurology", "Pediatrics"],
269
- value="General Practice"
270
  )
271
- password = gr.Textbox(label="Password", type="password", placeholder="Enter a secure password")
272
  submit_btn = gr.Button("Create Account")
273
  output = gr.Textbox(label="Status", interactive=False)
274
 
@@ -280,27 +205,24 @@ with admin_ui:
280
 
281
  app = gr.mount_gradio_app(app, admin_ui, path="/admin-auth")
282
 
283
- # Modified admin dashboard (no authentication)
284
  @app.get("/admin")
285
- async def admin_dashboard():
286
  logger.debug("Admin dashboard accessed")
287
- return RedirectResponse(url="/admin-auth", status_code=307)
288
-
289
- @app.get("/admin-auth/gradio_api/queue/data")
290
- async def gradio_queue_data(session_hash: str):
291
- logger.debug(f"Gradio queue data accessed with session_hash: {session_hash}")
292
- return {"status": "ok", "session_hash": session_hash}
293
-
294
- @app.get("/manifest.json")
295
- async def manifest():
296
- logger.debug("Manifest.json accessed")
297
- return {"name": "Doctor Account Creator", "short_name": "Doctor App", "start_url": "/admin-auth"}
298
 
299
  @app.on_event("startup")
300
  async def startup_event():
 
301
  try:
302
  await token_manager.get_token()
303
- logger.info("Initial token fetch successful")
304
  except Exception as e:
305
  logger.error(f"Initial token fetch failed: {str(e)}")
306
 
 
1
+ from fastapi import FastAPI, Request, HTTPException, Response
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import RedirectResponse, HTMLResponse
4
+ from api import api_router
5
  import gradio as gr
6
+ import requests
 
7
  import logging
8
  import time
9
+ import aiohttp
10
+ import asyncio
11
  from typing import Optional
 
12
 
13
  # Configure logging
14
+ logging.basicConfig(level=logging.DEBUG)
 
 
 
15
  logger = logging.getLogger(__name__)
16
  logger.debug("Initializing application")
17
 
 
18
  app = FastAPI()
19
 
20
+ # CORS Configuration
21
  app.add_middleware(
22
  CORSMiddleware,
23
+ allow_origins=["*"],
24
  allow_credentials=True,
25
  allow_methods=["*"],
26
  allow_headers=["*"],
27
  )
28
 
29
+ app.include_router(api_router)
 
30
 
31
+ # Constants
32
+ BACKEND_URL = "https://rocketfarmstudios-cps-api.hf.space"
33
+ ADMIN_EMAIL = "yakdhanali97@gmail.com"
34
+ ADMIN_PASSWORD = "123456"
35
  MAX_TOKEN_RETRIES = 3
36
  TOKEN_RETRY_DELAY = 2 # seconds
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  class TokenManager:
39
  def __init__(self):
40
  self.token = None
41
  self.last_refresh = 0
42
+ self.expires_in = 3600 # 1 hour default expiry
43
  self.lock = asyncio.Lock()
44
 
45
  async def _make_login_request(self) -> Optional[str]:
46
  try:
47
  async with aiohttp.ClientSession() as session:
 
 
 
48
  async with session.post(
49
+ f"{BACKEND_URL}/auth/login",
50
+ json={
51
+ "username": ADMIN_EMAIL,
52
+ "password": ADMIN_PASSWORD,
53
+ "device_token": "admin-device-token"
54
+ },
55
+ timeout=10
56
  ) as response:
 
57
  if response.status == 200:
58
  data = await response.json()
59
+ return data.get("access_token")
 
 
 
 
 
60
  else:
61
  error = await response.text()
62
+ logger.error(f"Login failed: {response.status} - {error}")
63
  return None
64
+ except Exception as e:
65
+ logger.error(f"Login request error: {str(e)}")
66
  return None
67
 
68
  async def refresh_token(self) -> str:
 
75
  logger.info("Successfully refreshed admin token")
76
  return token
77
 
78
+ wait_time = min(5, (attempt + 1) * 2) # Exponential backoff with max 5s
79
  logger.warning(f"Attempt {attempt + 1} failed, retrying in {wait_time}s...")
80
  await asyncio.sleep(wait_time)
81
 
82
+ raise Exception("Failed to obtain admin token after multiple attempts")
83
 
84
  async def get_token(self) -> str:
85
  if not self.token or (time.time() - self.last_refresh) > (self.expires_in - 60):
 
88
 
89
  token_manager = TokenManager()
90
 
 
 
 
91
  @app.get("/")
92
  def root():
93
  logger.debug("Root endpoint accessed")
 
95
 
96
  @app.post("/login")
97
  async def redirect_login(request: Request):
98
+ logger.info("Redirecting /login to /auth/login")
99
+ return RedirectResponse(url="/auth/login", status_code=307)
100
 
101
+ def authenticate_admin(email: str = None, password: str = None):
102
+ if email != ADMIN_EMAIL or password != ADMIN_PASSWORD:
103
+ logger.warning(f"Failed admin login attempt with email: {email}")
104
+ raise HTTPException(status_code=401, detail="Unauthorized: Invalid email or password")
105
+
106
+ logger.info(f"Admin authenticated successfully: {email}")
107
+ return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
+ async def async_create_doctor(full_name, email, matricule, password, specialty):
110
  try:
 
 
 
 
 
111
  token = await token_manager.get_token()
112
 
113
+ payload = {
114
+ "full_name": full_name,
115
+ "email": email,
116
+ "license_number": matricule,
117
+ "password": password,
118
+ "specialty": specialty,
119
+ }
120
  headers = {
121
  "Authorization": f"Bearer {token}",
122
  "Content-Type": "application/json"
123
  }
124
 
 
 
125
  async with aiohttp.ClientSession() as session:
126
  async with session.post(
127
+ f"{BACKEND_URL}/auth/admin/doctors",
128
+ json=payload,
129
  headers=headers,
130
+ timeout=10
131
  ) as response:
 
132
  if response.status == 201:
133
  return "✅ Doctor created successfully!"
134
+ elif response.status == 401: # Token might be expired
135
  logger.warning("Token expired, attempting refresh...")
136
  token = await token_manager.refresh_token()
137
  headers["Authorization"] = f"Bearer {token}"
138
  async with session.post(
139
+ f"{BACKEND_URL}/auth/admin/doctors",
140
+ json=payload,
141
  headers=headers,
142
+ timeout=10
143
  ) as retry_response:
 
144
  if retry_response.status == 201:
145
  return "✅ Doctor created successfully!"
 
 
146
 
147
  error_detail = await response.text()
148
  return f"❌ Error: {error_detail} (Status: {response.status})"
149
 
 
 
 
150
  except Exception as e:
151
  logger.error(f"Doctor creation failed: {str(e)}")
152
  return f"❌ System Error: {str(e)}"
153
 
154
+ def sync_create_doctor(*args):
155
+ return asyncio.run(async_create_doctor(*args))
 
 
 
 
 
 
 
 
 
 
 
 
156
 
 
157
  admin_ui = gr.Blocks(
158
  css="""
159
  .gradio-container {
 
186
  gr.Markdown("# Doctor Account Creator")
187
 
188
  with gr.Column():
189
+ full_name = gr.Textbox(label="Full Name")
190
+ email = gr.Textbox(label="Email")
191
+ matricule = gr.Textbox(label="License Number")
192
  specialty = gr.Dropdown(
193
  label="Specialty",
194
+ choices=["General Practice", "Cardiology", "Neurology", "Pediatrics"]
 
195
  )
196
+ password = gr.Textbox(label="Password", type="password")
197
  submit_btn = gr.Button("Create Account")
198
  output = gr.Textbox(label="Status", interactive=False)
199
 
 
205
 
206
  app = gr.mount_gradio_app(app, admin_ui, path="/admin-auth")
207
 
 
208
  @app.get("/admin")
209
+ async def admin_dashboard(email: str = None, password: str = None, response: Response = None):
210
  logger.debug("Admin dashboard accessed")
211
+ try:
212
+ authenticate_admin(email, password)
213
+ return RedirectResponse(url="/admin-auth", status_code=307)
214
+ except HTTPException as e:
215
+ response.status_code = 401
216
+ return HTMLResponse(content="""
217
+ <h1>401 Unauthorized</h1>
218
+ <p>Invalid admin credentials</p>
219
+ """)
 
 
220
 
221
  @app.on_event("startup")
222
  async def startup_event():
223
+ """Initialize token but don't fail startup"""
224
  try:
225
  await token_manager.get_token()
 
226
  except Exception as e:
227
  logger.error(f"Initial token fetch failed: {str(e)}")
228