Spaces:
Sleeping
Sleeping
Commit Β·
36e31bf
1
Parent(s): 695c7de
TEST ROUTES
Browse files- FIX_404_SUMMARY.md +170 -0
- app.py +20 -6
- services/ai-service/src/__pycache__/__main__.cpython-311.pyc +0 -0
- services/ai-service/src/__pycache__/config_settings.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/__pycache__/api_endpoints.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/__pycache__/app.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/__pycache__/database_audit.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/__pycache__/inference_service.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/api/__pycache__/routes_fastapi.cpython-311.pyc +0 -0
- services/ai-service/src/ai_med_extract/api/routes_fastapi.py +132 -92
- services/ai-service/src/ai_med_extract/app.py +9 -6
- services/ai-service/src/ai_med_extract/utils/__pycache__/file_utils.cpython-311.pyc +0 -0
- test_routes_local.py +109 -0
FIX_404_SUMMARY.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fix for 404 Error on `/generate_patient_summary` Endpoint
|
| 2 |
+
|
| 3 |
+
## Problem
|
| 4 |
+
The `/generate_patient_summary` endpoint was returning a 404 Not Found error when accessed on Hugging Face Spaces at:
|
| 5 |
+
```
|
| 6 |
+
https://salvinjose-hntai.hf.space/generate_patient_summary?stream=true
|
| 7 |
+
```
|
| 8 |
+
|
| 9 |
+
## Root Cause
|
| 10 |
+
1. **Route Registration Issue**: The `/generate_patient_summary` endpoint was defined INSIDE the `register_routes()` function, which meant it was being added to the router AFTER the router was already included in the app. While this should work in FastAPI, it's not best practice and can cause timing issues.
|
| 11 |
+
|
| 12 |
+
2. **Double Initialization**: The app was being initialized twice:
|
| 13 |
+
- Once in `create_app()` (which calls `initialize_agents` by default)
|
| 14 |
+
- Once again in the root `app.py` file
|
| 15 |
+
|
| 16 |
+
This double initialization could cause routes to be registered incorrectly or timing issues.
|
| 17 |
+
|
| 18 |
+
## Changes Made
|
| 19 |
+
|
| 20 |
+
### 1. Fixed Route Registration (`services/ai-service/src/ai_med_extract/api/routes_fastapi.py`)
|
| 21 |
+
|
| 22 |
+
**Before:**
|
| 23 |
+
```python
|
| 24 |
+
def register_routes(app, agents):
|
| 25 |
+
app.include_router(router)
|
| 26 |
+
|
| 27 |
+
# Routes defined INSIDE the function
|
| 28 |
+
@router.post("/generate_patient_summary")
|
| 29 |
+
async def generate_patient_summary(...):
|
| 30 |
+
...
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
**After:**
|
| 34 |
+
```python
|
| 35 |
+
# Define routes at MODULE LEVEL (outside register_routes)
|
| 36 |
+
@router.post("/generate_patient_summary")
|
| 37 |
+
async def generate_patient_summary(
|
| 38 |
+
request: Request,
|
| 39 |
+
background_tasks: BackgroundTasks,
|
| 40 |
+
stream: bool = False
|
| 41 |
+
):
|
| 42 |
+
"""Generate patient summary with optional streaming support."""
|
| 43 |
+
...
|
| 44 |
+
|
| 45 |
+
def register_routes(app, agents):
|
| 46 |
+
# Just include the router with already-defined routes
|
| 47 |
+
app.include_router(router)
|
| 48 |
+
...
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
### 2. Fixed Double Initialization (`app.py`)
|
| 52 |
+
|
| 53 |
+
**Before:**
|
| 54 |
+
```python
|
| 55 |
+
app = create_app() # This calls initialize_agents internally
|
| 56 |
+
initialize_agents(app, preload_small_models=False) # Called again!
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
**After:**
|
| 60 |
+
```python
|
| 61 |
+
app = create_app(initialize=False) # Don't initialize yet
|
| 62 |
+
initialize_agents(app, preload_small_models=False) # Initialize once
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
### 3. Added Comprehensive Logging
|
| 66 |
+
|
| 67 |
+
Added logging to show all registered routes on startup in both:
|
| 68 |
+
- `services/ai-service/src/ai_med_extract/app.py` (lines 781-786)
|
| 69 |
+
- `app.py` (lines 95-103)
|
| 70 |
+
|
| 71 |
+
This will help debug any remaining routing issues on HF Spaces.
|
| 72 |
+
|
| 73 |
+
### 4. Added Diagnostic Endpoint
|
| 74 |
+
|
| 75 |
+
Added a new `/api/info` endpoint that returns:
|
| 76 |
+
```json
|
| 77 |
+
{
|
| 78 |
+
"status": "ok",
|
| 79 |
+
"message": "Medical AI Service API",
|
| 80 |
+
"version": "1.0.0",
|
| 81 |
+
"endpoints": {
|
| 82 |
+
"generate_patient_summary": "/generate_patient_summary (POST)",
|
| 83 |
+
"upload": "/upload (POST)",
|
| 84 |
+
"transcribe": "/transcribe (POST)",
|
| 85 |
+
"health": "/health/* (GET)"
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
## Testing
|
| 91 |
+
|
| 92 |
+
### 1. Verify Routes are Registered
|
| 93 |
+
After deploying to HF Spaces, check the logs for:
|
| 94 |
+
```
|
| 95 |
+
============================================================
|
| 96 |
+
REGISTERED ROUTES:
|
| 97 |
+
['POST'] /generate_patient_summary
|
| 98 |
+
...
|
| 99 |
+
Total routes registered: X
|
| 100 |
+
============================================================
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
### 2. Test the Diagnostic Endpoint
|
| 104 |
+
Access: `https://salvinjose-hntai.hf.space/api/info`
|
| 105 |
+
|
| 106 |
+
Should return:
|
| 107 |
+
```json
|
| 108 |
+
{
|
| 109 |
+
"status": "ok",
|
| 110 |
+
"message": "Medical AI Service API",
|
| 111 |
+
...
|
| 112 |
+
}
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### 3. Test the Debug Endpoint
|
| 116 |
+
Access: `https://salvinjose-hntai.hf.space/debug/routes`
|
| 117 |
+
|
| 118 |
+
Should return a list of all registered routes:
|
| 119 |
+
```json
|
| 120 |
+
{
|
| 121 |
+
"routes": [
|
| 122 |
+
{"path": "/generate_patient_summary", "methods": ["POST"], "name": "generate_patient_summary"},
|
| 123 |
+
...
|
| 124 |
+
],
|
| 125 |
+
"total": X
|
| 126 |
+
}
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
### 4. Test the Target Endpoint
|
| 130 |
+
```bash
|
| 131 |
+
curl -X POST "https://salvinjose-hntai.hf.space/generate_patient_summary?stream=true" \
|
| 132 |
+
-H "Content-Type: application/json" \
|
| 133 |
+
-d '{
|
| 134 |
+
"patientid": "your-patient-id",
|
| 135 |
+
"token": "your-auth-token",
|
| 136 |
+
"key": "your-api-key"
|
| 137 |
+
}'
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
## Expected Outcome
|
| 141 |
+
|
| 142 |
+
The `/generate_patient_summary` endpoint should now:
|
| 143 |
+
1. Return a proper response instead of 404
|
| 144 |
+
2. Support both streaming (`stream=true`) and non-streaming modes
|
| 145 |
+
3. Be visible in the route listing at `/debug/routes`
|
| 146 |
+
|
| 147 |
+
## If Issues Persist
|
| 148 |
+
|
| 149 |
+
If the 404 error persists after these changes:
|
| 150 |
+
|
| 151 |
+
1. **Check the logs** - Look for the "REGISTERED ROUTES" section to verify the endpoint is registered
|
| 152 |
+
2. **Test the diagnostic endpoint** - Access `/api/info` to verify the API is accessible
|
| 153 |
+
3. **Check the debug endpoint** - Access `/debug/routes` to see all registered routes
|
| 154 |
+
4. **Verify the URL** - Ensure you're using the correct URL without double slashes
|
| 155 |
+
5. **Check for errors** - Look for any exceptions during route registration in the logs
|
| 156 |
+
|
| 157 |
+
## Next Steps
|
| 158 |
+
|
| 159 |
+
1. Commit these changes
|
| 160 |
+
2. Push to HF Spaces
|
| 161 |
+
3. Check the logs for route registration
|
| 162 |
+
4. Test the endpoints as described above
|
| 163 |
+
5. If issues persist, share the logs from HF Spaces
|
| 164 |
+
|
| 165 |
+
## Files Modified
|
| 166 |
+
|
| 167 |
+
- `app.py` (root level)
|
| 168 |
+
- `services/ai-service/src/ai_med_extract/app.py`
|
| 169 |
+
- `services/ai-service/src/ai_med_extract/api/routes_fastapi.py`
|
| 170 |
+
|
app.py
CHANGED
|
@@ -63,10 +63,10 @@ try:
|
|
| 63 |
from ai_med_extract.app import create_app, initialize_agents # type: ignore
|
| 64 |
logging.info("Successfully imported create_app and initialize_agents")
|
| 65 |
|
| 66 |
-
# Create the app instance
|
| 67 |
try:
|
| 68 |
-
app = create_app()
|
| 69 |
-
logging.info("App instance created successfully")
|
| 70 |
logging.info(f"App title: {app.title}")
|
| 71 |
logging.info(f"App version: {getattr(app, 'version', 'unknown')}")
|
| 72 |
except Exception as e:
|
|
@@ -87,13 +87,27 @@ try:
|
|
| 87 |
|
| 88 |
# Initialize agents with minimal preloading for Hugging Face Spaces
|
| 89 |
try:
|
|
|
|
| 90 |
initialize_agents(app, preload_small_models=False)
|
| 91 |
logging.info("Agents initialized successfully")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
except Exception as e:
|
| 93 |
-
logging.
|
| 94 |
-
|
|
|
|
|
|
|
| 95 |
# Add a basic health endpoint if agents fail
|
| 96 |
-
@app.get("/health")
|
| 97 |
async def basic_health():
|
| 98 |
return {"status": "degraded", "message": "Agents not initialized", "error": str(e)}
|
| 99 |
|
|
|
|
| 63 |
from ai_med_extract.app import create_app, initialize_agents # type: ignore
|
| 64 |
logging.info("Successfully imported create_app and initialize_agents")
|
| 65 |
|
| 66 |
+
# Create the app instance WITHOUT initializing agents yet
|
| 67 |
try:
|
| 68 |
+
app = create_app(initialize=False)
|
| 69 |
+
logging.info("App instance created successfully (without agents)")
|
| 70 |
logging.info(f"App title: {app.title}")
|
| 71 |
logging.info(f"App version: {getattr(app, 'version', 'unknown')}")
|
| 72 |
except Exception as e:
|
|
|
|
| 87 |
|
| 88 |
# Initialize agents with minimal preloading for Hugging Face Spaces
|
| 89 |
try:
|
| 90 |
+
logging.info("Initializing agents with preload_small_models=False...")
|
| 91 |
initialize_agents(app, preload_small_models=False)
|
| 92 |
logging.info("Agents initialized successfully")
|
| 93 |
+
|
| 94 |
+
# Log all registered routes after initialization
|
| 95 |
+
logging.info("=" * 60)
|
| 96 |
+
logging.info("FINAL REGISTERED ROUTES ON HF SPACES:")
|
| 97 |
+
route_count = 0
|
| 98 |
+
for route in app.routes:
|
| 99 |
+
if hasattr(route, "methods") and hasattr(route, "path"):
|
| 100 |
+
logging.info(f" {list(route.methods)} {route.path}")
|
| 101 |
+
route_count += 1
|
| 102 |
+
logging.info(f"Total routes registered: {route_count}")
|
| 103 |
+
logging.info("=" * 60)
|
| 104 |
except Exception as e:
|
| 105 |
+
logging.error(f"Agent initialization failed: {e}")
|
| 106 |
+
import traceback
|
| 107 |
+
logging.error(f"Agent initialization traceback: {traceback.format_exc()}")
|
| 108 |
+
logging.warning("App will start with basic functionality")
|
| 109 |
# Add a basic health endpoint if agents fail
|
| 110 |
+
@app.get("/health/status")
|
| 111 |
async def basic_health():
|
| 112 |
return {"status": "degraded", "message": "Agents not initialized", "error": str(e)}
|
| 113 |
|
services/ai-service/src/__pycache__/__main__.cpython-311.pyc
ADDED
|
Binary file (526 Bytes). View file
|
|
|
services/ai-service/src/__pycache__/config_settings.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/__pycache__/config_settings.cpython-311.pyc and b/services/ai-service/src/__pycache__/config_settings.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/__pycache__/api_endpoints.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/__pycache__/api_endpoints.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/__pycache__/api_endpoints.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/__pycache__/app.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/__pycache__/app.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/__pycache__/app.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/__pycache__/database_audit.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/__pycache__/database_audit.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/__pycache__/database_audit.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/__pycache__/inference_service.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/__pycache__/inference_service.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/__pycache__/inference_service.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/api/__pycache__/routes_fastapi.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/api/__pycache__/routes_fastapi.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/api/__pycache__/routes_fastapi.cpython-311.pyc differ
|
|
|
services/ai-service/src/ai_med_extract/api/routes_fastapi.py
CHANGED
|
@@ -947,9 +947,122 @@ async def process_patient_summary_sync(data):
|
|
| 947 |
except Exception as e:
|
| 948 |
raise HTTPException(status_code=500, detail=f"Summary generation failed: {str(e)}")
|
| 949 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 950 |
def register_routes(app, agents):
|
| 951 |
# Register the router with the FastAPI app
|
| 952 |
app.include_router(router)
|
|
|
|
|
|
|
| 953 |
# Ensure module-level agents reference is wired for route handlers
|
| 954 |
try:
|
| 955 |
globals()['agents'] = agents
|
|
@@ -959,105 +1072,32 @@ def register_routes(app, agents):
|
|
| 959 |
# Include additional API endpoints
|
| 960 |
from ..api_endpoints import router as api_router
|
| 961 |
app.include_router(api_router)
|
|
|
|
|
|
|
| 962 |
# Include model management FastAPI routes (non-breaking addition)
|
| 963 |
try:
|
| 964 |
from .model_management_fastapi import router as model_mgmt_router
|
| 965 |
app.include_router(model_mgmt_router)
|
|
|
|
| 966 |
except Exception as _e:
|
| 967 |
# Keep running even if this optional router fails
|
| 968 |
logging.warning(f"Model management router not loaded: {_e}")
|
| 969 |
-
|
| 970 |
-
#
|
| 971 |
-
@
|
| 972 |
-
async def
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
pass
|
| 986 |
-
return {
|
| 987 |
-
"app": settings.APP_NAME,
|
| 988 |
-
"version": settings.APP_VERSION,
|
| 989 |
-
"loaded_models": loaded,
|
| 990 |
-
}
|
| 991 |
-
except Exception:
|
| 992 |
-
return {"error": "Failed to get readiness status"}
|
| 993 |
-
|
| 994 |
-
@router.get("/metrics")
|
| 995 |
-
async def metrics():
|
| 996 |
-
return {"performance": PERFORMANCE_METRICS, "loaded_models": {}}
|
| 997 |
-
|
| 998 |
-
# Home route
|
| 999 |
-
@router.get("/")
|
| 1000 |
-
async def home():
|
| 1001 |
-
return "Medical Data Extraction API is running!"
|
| 1002 |
-
|
| 1003 |
-
# Performance metrics route
|
| 1004 |
-
@router.get("/api/performance_metrics")
|
| 1005 |
-
async def get_performance_metrics():
|
| 1006 |
-
return JSONResponse(content={
|
| 1007 |
-
"metrics": PERFORMANCE_METRICS,
|
| 1008 |
-
"timestamp": time.time()
|
| 1009 |
-
})
|
| 1010 |
-
|
| 1011 |
-
# Generate patient summary endpoint (migrated from Flask)
|
| 1012 |
-
@router.post("/generate_patient_summary")
|
| 1013 |
-
async def generate_patient_summary(
|
| 1014 |
-
request: Request,
|
| 1015 |
-
background_tasks: BackgroundTasks,
|
| 1016 |
-
stream: bool = False
|
| 1017 |
-
):
|
| 1018 |
-
"""
|
| 1019 |
-
Generate patient summary with optional streaming support.
|
| 1020 |
-
Migrated from Flask implementation with background processing.
|
| 1021 |
-
"""
|
| 1022 |
-
try:
|
| 1023 |
-
data = await request.json()
|
| 1024 |
-
patientid = data.get("patientid")
|
| 1025 |
-
token = data.get("token")
|
| 1026 |
-
key = data.get("key")
|
| 1027 |
-
|
| 1028 |
-
if not patientid or not token or not key:
|
| 1029 |
-
raise HTTPException(status_code=400, detail="Missing required fields: patientid, token, or key")
|
| 1030 |
-
|
| 1031 |
-
if stream:
|
| 1032 |
-
# Return streaming response for long-running tasks
|
| 1033 |
-
job_id = str(uuid.uuid4())
|
| 1034 |
-
update_job(job_id, 'queued', progress=0, data={'job_id': job_id, 'message': 'Job queued ...'})
|
| 1035 |
-
|
| 1036 |
-
# Start background task
|
| 1037 |
-
threading.Thread(target=process_patient_summary_background, args=(data, job_id), daemon=True).start()
|
| 1038 |
-
|
| 1039 |
-
return StreamingResponse(
|
| 1040 |
-
sse_generator(job_id),
|
| 1041 |
-
media_type="text/event-stream",
|
| 1042 |
-
headers={
|
| 1043 |
-
'Cache-Control': 'no-cache',
|
| 1044 |
-
'Connection': 'keep-alive',
|
| 1045 |
-
'X-Accel-Buffering': 'no'
|
| 1046 |
-
}
|
| 1047 |
-
)
|
| 1048 |
-
else:
|
| 1049 |
-
# Prefer deterministic rule-based mode on Spaces unless explicitly overridden
|
| 1050 |
-
try:
|
| 1051 |
-
is_spaces = os.environ.get('HF_SPACES', 'false').lower() == 'true'
|
| 1052 |
-
except Exception:
|
| 1053 |
-
is_spaces = False
|
| 1054 |
-
if is_spaces and not data.get('generation_mode'):
|
| 1055 |
-
data['generation_mode'] = 'rule'
|
| 1056 |
-
# Synchronous processing (for compatibility)
|
| 1057 |
-
return await process_patient_summary_sync(data)
|
| 1058 |
-
|
| 1059 |
-
except Exception as e:
|
| 1060 |
-
raise HTTPException(status_code=500, detail=f"Failed to start summary generation: {str(e)}")
|
| 1061 |
|
| 1062 |
# Upload file endpoint (migrated from Flask)
|
| 1063 |
@router.post("/upload")
|
|
|
|
| 947 |
except Exception as e:
|
| 948 |
raise HTTPException(status_code=500, detail=f"Summary generation failed: {str(e)}")
|
| 949 |
|
| 950 |
+
# ========== MODULE-LEVEL ROUTE DEFINITIONS ==========
|
| 951 |
+
# Define routes at module level so they're available immediately when router is included
|
| 952 |
+
|
| 953 |
+
# Health check routes
|
| 954 |
+
@router.get("/live")
|
| 955 |
+
async def live():
|
| 956 |
+
return {"status": "ok"}
|
| 957 |
+
|
| 958 |
+
@router.get("/ready")
|
| 959 |
+
async def ready():
|
| 960 |
+
try:
|
| 961 |
+
from config_settings import get_settings
|
| 962 |
+
settings = get_settings()
|
| 963 |
+
loaded = {}
|
| 964 |
+
try:
|
| 965 |
+
from ..utils.model_manager import model_manager
|
| 966 |
+
loaded = model_manager.list_loaded_models()
|
| 967 |
+
except Exception:
|
| 968 |
+
pass
|
| 969 |
+
return {
|
| 970 |
+
"app": settings.APP_NAME,
|
| 971 |
+
"version": settings.APP_VERSION,
|
| 972 |
+
"loaded_models": loaded,
|
| 973 |
+
}
|
| 974 |
+
except Exception:
|
| 975 |
+
return {"error": "Failed to get readiness status"}
|
| 976 |
+
|
| 977 |
+
@router.get("/metrics")
|
| 978 |
+
async def metrics():
|
| 979 |
+
return {"performance": PERFORMANCE_METRICS, "loaded_models": {}}
|
| 980 |
+
|
| 981 |
+
# Home route
|
| 982 |
+
@router.get("/")
|
| 983 |
+
async def home():
|
| 984 |
+
return "Medical Data Extraction API is running!"
|
| 985 |
+
|
| 986 |
+
# Simple diagnostic endpoint
|
| 987 |
+
@router.get("/api/info")
|
| 988 |
+
async def api_info():
|
| 989 |
+
"""Simple diagnostic endpoint to verify API is accessible"""
|
| 990 |
+
return JSONResponse(content={
|
| 991 |
+
"status": "ok",
|
| 992 |
+
"message": "Medical AI Service API",
|
| 993 |
+
"version": "1.0.0",
|
| 994 |
+
"endpoints": {
|
| 995 |
+
"generate_patient_summary": "/generate_patient_summary (POST)",
|
| 996 |
+
"upload": "/upload (POST)",
|
| 997 |
+
"transcribe": "/transcribe (POST)",
|
| 998 |
+
"health": "/health/* (GET)"
|
| 999 |
+
}
|
| 1000 |
+
})
|
| 1001 |
+
|
| 1002 |
+
# Performance metrics route
|
| 1003 |
+
@router.get("/api/performance_metrics")
|
| 1004 |
+
async def get_performance_metrics():
|
| 1005 |
+
return JSONResponse(content={
|
| 1006 |
+
"metrics": PERFORMANCE_METRICS,
|
| 1007 |
+
"timestamp": time.time()
|
| 1008 |
+
})
|
| 1009 |
+
|
| 1010 |
+
# Generate patient summary endpoint (migrated from Flask)
|
| 1011 |
+
@router.post("/generate_patient_summary")
|
| 1012 |
+
async def generate_patient_summary(
|
| 1013 |
+
request: Request,
|
| 1014 |
+
background_tasks: BackgroundTasks,
|
| 1015 |
+
stream: bool = False
|
| 1016 |
+
):
|
| 1017 |
+
"""
|
| 1018 |
+
Generate patient summary with optional streaming support.
|
| 1019 |
+
Migrated from Flask implementation with background processing.
|
| 1020 |
+
"""
|
| 1021 |
+
try:
|
| 1022 |
+
data = await request.json()
|
| 1023 |
+
patientid = data.get("patientid")
|
| 1024 |
+
token = data.get("token")
|
| 1025 |
+
key = data.get("key")
|
| 1026 |
+
|
| 1027 |
+
if not patientid or not token or not key:
|
| 1028 |
+
raise HTTPException(status_code=400, detail="Missing required fields: patientid, token, or key")
|
| 1029 |
+
|
| 1030 |
+
if stream:
|
| 1031 |
+
# Return streaming response for long-running tasks
|
| 1032 |
+
job_id = str(uuid.uuid4())
|
| 1033 |
+
update_job(job_id, 'queued', progress=0, data={'job_id': job_id, 'message': 'Job queued ...'})
|
| 1034 |
+
|
| 1035 |
+
# Start background task
|
| 1036 |
+
threading.Thread(target=process_patient_summary_background, args=(data, job_id), daemon=True).start()
|
| 1037 |
+
|
| 1038 |
+
return StreamingResponse(
|
| 1039 |
+
sse_generator(job_id),
|
| 1040 |
+
media_type="text/event-stream",
|
| 1041 |
+
headers={
|
| 1042 |
+
'Cache-Control': 'no-cache',
|
| 1043 |
+
'Connection': 'keep-alive',
|
| 1044 |
+
'X-Accel-Buffering': 'no'
|
| 1045 |
+
}
|
| 1046 |
+
)
|
| 1047 |
+
else:
|
| 1048 |
+
# Prefer deterministic rule-based mode on Spaces unless explicitly overridden
|
| 1049 |
+
try:
|
| 1050 |
+
is_spaces = os.environ.get('HF_SPACES', 'false').lower() == 'true'
|
| 1051 |
+
except Exception:
|
| 1052 |
+
is_spaces = False
|
| 1053 |
+
if is_spaces and not data.get('generation_mode'):
|
| 1054 |
+
data['generation_mode'] = 'rule'
|
| 1055 |
+
# Synchronous processing (for compatibility)
|
| 1056 |
+
return await process_patient_summary_sync(data)
|
| 1057 |
+
|
| 1058 |
+
except Exception as e:
|
| 1059 |
+
raise HTTPException(status_code=500, detail=f"Failed to start summary generation: {str(e)}")
|
| 1060 |
+
|
| 1061 |
def register_routes(app, agents):
|
| 1062 |
# Register the router with the FastAPI app
|
| 1063 |
app.include_router(router)
|
| 1064 |
+
logging.info("Main router registered with app")
|
| 1065 |
+
|
| 1066 |
# Ensure module-level agents reference is wired for route handlers
|
| 1067 |
try:
|
| 1068 |
globals()['agents'] = agents
|
|
|
|
| 1072 |
# Include additional API endpoints
|
| 1073 |
from ..api_endpoints import router as api_router
|
| 1074 |
app.include_router(api_router)
|
| 1075 |
+
logging.info("API router registered with app")
|
| 1076 |
+
|
| 1077 |
# Include model management FastAPI routes (non-breaking addition)
|
| 1078 |
try:
|
| 1079 |
from .model_management_fastapi import router as model_mgmt_router
|
| 1080 |
app.include_router(model_mgmt_router)
|
| 1081 |
+
logging.info("Model management router registered with app")
|
| 1082 |
except Exception as _e:
|
| 1083 |
# Keep running even if this optional router fails
|
| 1084 |
logging.warning(f"Model management router not loaded: {_e}")
|
| 1085 |
+
|
| 1086 |
+
# Debug route to list all available routes (needs app reference)
|
| 1087 |
+
@app.get("/debug/routes")
|
| 1088 |
+
async def list_routes():
|
| 1089 |
+
"""List all registered routes for debugging"""
|
| 1090 |
+
routes = []
|
| 1091 |
+
for route in app.routes:
|
| 1092 |
+
if hasattr(route, "methods"):
|
| 1093 |
+
routes.append({
|
| 1094 |
+
"path": route.path,
|
| 1095 |
+
"methods": list(route.methods),
|
| 1096 |
+
"name": route.name
|
| 1097 |
+
})
|
| 1098 |
+
return {"routes": routes, "total": len(routes)}
|
| 1099 |
+
|
| 1100 |
+
logging.info("All routes registered successfully")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1101 |
|
| 1102 |
# Upload file endpoint (migrated from Flask)
|
| 1103 |
@router.post("/upload")
|
services/ai-service/src/ai_med_extract/app.py
CHANGED
|
@@ -776,7 +776,14 @@ def initialize_agents(app: FastAPI, *, preload_small_models: bool = True):
|
|
| 776 |
register_routes(app, agents)
|
| 777 |
app.include_router(health_router, prefix="/health")
|
| 778 |
|
|
|
|
| 779 |
logging.info("Agents initialized and routes registered")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 780 |
except Exception as e:
|
| 781 |
logging.error(f"Failed to register routes: {e}")
|
| 782 |
import traceback
|
|
@@ -820,9 +827,5 @@ def run_dev(host: str = "0.0.0.0", port: int = 7860, debug: bool = False):
|
|
| 820 |
if __name__ == "__main__":
|
| 821 |
run_dev()
|
| 822 |
|
| 823 |
-
#
|
| 824 |
-
|
| 825 |
-
app = create_app()
|
| 826 |
-
except Exception:
|
| 827 |
-
# Defer errors to runtime logs rather than import-time crash on Spaces
|
| 828 |
-
app = FastAPI(title="Medical AI Service (degraded)")
|
|
|
|
| 776 |
register_routes(app, agents)
|
| 777 |
app.include_router(health_router, prefix="/health")
|
| 778 |
|
| 779 |
+
# Log all registered routes for debugging
|
| 780 |
logging.info("Agents initialized and routes registered")
|
| 781 |
+
logging.info("=" * 60)
|
| 782 |
+
logging.info("REGISTERED ROUTES:")
|
| 783 |
+
for route in app.routes:
|
| 784 |
+
if hasattr(route, "methods") and hasattr(route, "path"):
|
| 785 |
+
logging.info(f" {list(route.methods)} {route.path}")
|
| 786 |
+
logging.info("=" * 60)
|
| 787 |
except Exception as e:
|
| 788 |
logging.error(f"Failed to register routes: {e}")
|
| 789 |
import traceback
|
|
|
|
| 827 |
if __name__ == "__main__":
|
| 828 |
run_dev()
|
| 829 |
|
| 830 |
+
# Module-level app instance is now created in root app.py to avoid multiple initializations
|
| 831 |
+
# Do NOT create app here as it causes duplicate initialization
|
|
|
|
|
|
|
|
|
|
|
|
services/ai-service/src/ai_med_extract/utils/__pycache__/file_utils.cpython-311.pyc
CHANGED
|
Binary files a/services/ai-service/src/ai_med_extract/utils/__pycache__/file_utils.cpython-311.pyc and b/services/ai-service/src/ai_med_extract/utils/__pycache__/file_utils.cpython-311.pyc differ
|
|
|
test_routes_local.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Local test script to verify routes are properly registered.
|
| 3 |
+
Run this before deploying to HF Spaces.
|
| 4 |
+
|
| 5 |
+
Usage:
|
| 6 |
+
python test_routes_local.py
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import sys
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
# Add the source directory to the path
|
| 13 |
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 14 |
+
src_dir = os.path.join(current_dir, "services", "ai-service", "src")
|
| 15 |
+
sys.path.insert(0, src_dir)
|
| 16 |
+
|
| 17 |
+
# Set environment variables for testing
|
| 18 |
+
os.environ["HF_SPACES"] = "true"
|
| 19 |
+
os.environ["FAST_MODE"] = "true"
|
| 20 |
+
|
| 21 |
+
print("=" * 60)
|
| 22 |
+
print("Testing Route Registration")
|
| 23 |
+
print("=" * 60)
|
| 24 |
+
|
| 25 |
+
try:
|
| 26 |
+
from ai_med_extract.app import create_app, initialize_agents
|
| 27 |
+
print("β Successfully imported create_app and initialize_agents")
|
| 28 |
+
|
| 29 |
+
# Create app without initialization
|
| 30 |
+
print("\nCreating app...")
|
| 31 |
+
app = create_app(initialize=False)
|
| 32 |
+
print(f"β App created: {app.title}")
|
| 33 |
+
|
| 34 |
+
# Initialize agents
|
| 35 |
+
print("\nInitializing agents...")
|
| 36 |
+
initialize_agents(app, preload_small_models=False)
|
| 37 |
+
print("β Agents initialized")
|
| 38 |
+
|
| 39 |
+
# List all routes
|
| 40 |
+
print("\n" + "=" * 60)
|
| 41 |
+
print("REGISTERED ROUTES:")
|
| 42 |
+
print("=" * 60)
|
| 43 |
+
|
| 44 |
+
routes_found = []
|
| 45 |
+
generate_patient_summary_found = False
|
| 46 |
+
|
| 47 |
+
for route in app.routes:
|
| 48 |
+
if hasattr(route, "methods") and hasattr(route, "path"):
|
| 49 |
+
methods = list(route.methods)
|
| 50 |
+
path = route.path
|
| 51 |
+
routes_found.append((methods, path))
|
| 52 |
+
print(f" {methods} {path}")
|
| 53 |
+
|
| 54 |
+
# Check for the specific endpoint we're looking for
|
| 55 |
+
if path == "/generate_patient_summary" and "POST" in methods:
|
| 56 |
+
generate_patient_summary_found = True
|
| 57 |
+
|
| 58 |
+
print("=" * 60)
|
| 59 |
+
print(f"Total routes: {len(routes_found)}")
|
| 60 |
+
print("=" * 60)
|
| 61 |
+
|
| 62 |
+
# Verify critical endpoints
|
| 63 |
+
print("\n" + "=" * 60)
|
| 64 |
+
print("ENDPOINT VERIFICATION:")
|
| 65 |
+
print("=" * 60)
|
| 66 |
+
|
| 67 |
+
critical_endpoints = {
|
| 68 |
+
"/generate_patient_summary": False,
|
| 69 |
+
"/api/info": False,
|
| 70 |
+
"/debug/routes": False,
|
| 71 |
+
"/": False,
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
for methods, path in routes_found:
|
| 75 |
+
if path in critical_endpoints:
|
| 76 |
+
critical_endpoints[path] = True
|
| 77 |
+
|
| 78 |
+
all_found = True
|
| 79 |
+
for endpoint, found in critical_endpoints.items():
|
| 80 |
+
status = "β" if found else "β"
|
| 81 |
+
print(f" {status} {endpoint}")
|
| 82 |
+
if not found:
|
| 83 |
+
all_found = False
|
| 84 |
+
|
| 85 |
+
print("=" * 60)
|
| 86 |
+
|
| 87 |
+
if generate_patient_summary_found:
|
| 88 |
+
print("\nβββ SUCCESS! /generate_patient_summary endpoint is registered βββ")
|
| 89 |
+
else:
|
| 90 |
+
print("\nβββ ERROR! /generate_patient_summary endpoint NOT found βββ")
|
| 91 |
+
sys.exit(1)
|
| 92 |
+
|
| 93 |
+
if all_found:
|
| 94 |
+
print("β All critical endpoints are registered")
|
| 95 |
+
print("\nReady for deployment to HF Spaces!")
|
| 96 |
+
else:
|
| 97 |
+
print("\nβ Some endpoints are missing (see above)")
|
| 98 |
+
|
| 99 |
+
print("\n" + "=" * 60)
|
| 100 |
+
print("Test completed successfully!")
|
| 101 |
+
print("=" * 60)
|
| 102 |
+
|
| 103 |
+
except Exception as e:
|
| 104 |
+
print(f"\nβββ ERROR: {str(e)}")
|
| 105 |
+
import traceback
|
| 106 |
+
print("\nTraceback:")
|
| 107 |
+
print(traceback.format_exc())
|
| 108 |
+
sys.exit(1)
|
| 109 |
+
|