Spaces:
Sleeping
Sleeping
Update api/routes/pdf.py
Browse files- api/routes/pdf.py +65 -61
api/routes/pdf.py
CHANGED
|
@@ -5,6 +5,7 @@ from utils.helpers import calculate_age, escape_latex_special_chars, hyphenate_l
|
|
| 5 |
from datetime import datetime
|
| 6 |
from bson import ObjectId
|
| 7 |
from bson.errors import InvalidId
|
|
|
|
| 8 |
import logging
|
| 9 |
import asyncio
|
| 10 |
from typing import List, Dict, Optional
|
|
@@ -20,109 +21,112 @@ logger = logging.getLogger(__name__)
|
|
| 20 |
router = APIRouter()
|
| 21 |
|
| 22 |
# Configuration
|
| 23 |
-
|
| 24 |
|
| 25 |
-
async def
|
| 26 |
-
|
|
|
|
| 27 |
"patient_id": patient.get("fhir_id"),
|
| 28 |
-
"
|
| 29 |
-
"
|
| 30 |
-
"
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
},
|
| 47 |
-
"notes": patient.get("notes", []),
|
| 48 |
-
"conditions": patient.get("conditions", []),
|
| 49 |
-
"medications": patient.get("medications", []),
|
| 50 |
-
"encounters": patient.get("encounters", [])
|
| 51 |
-
}
|
| 52 |
}
|
|
|
|
| 53 |
|
| 54 |
async def generate_and_store_summary(patient: dict) -> Optional[Dict]:
|
|
|
|
| 55 |
try:
|
| 56 |
-
summary = await
|
| 57 |
db = patients_collection.database
|
| 58 |
-
await db[
|
| 59 |
{"patient_id": summary["patient_id"]},
|
| 60 |
{"$set": summary},
|
| 61 |
upsert=True
|
| 62 |
)
|
| 63 |
-
logger.info(f"
|
| 64 |
return summary
|
| 65 |
except Exception as e:
|
| 66 |
-
logger.error(f"Error
|
| 67 |
return None
|
| 68 |
|
| 69 |
-
async def
|
| 70 |
-
|
|
|
|
| 71 |
try:
|
| 72 |
-
|
| 73 |
-
patients = await cursor.to_list(length=None)
|
| 74 |
for patient in patients:
|
| 75 |
summary = await generate_and_store_summary(patient)
|
| 76 |
if summary:
|
| 77 |
-
|
| 78 |
-
return
|
| 79 |
except Exception as e:
|
| 80 |
-
logger.error(f"Error
|
| 81 |
-
return
|
| 82 |
|
| 83 |
async def watch_for_new_patients():
|
|
|
|
| 84 |
try:
|
| 85 |
logger.info("Starting MongoDB change stream for new summaries")
|
| 86 |
-
db = patients_collection.database
|
| 87 |
pipeline = [{'$match': {'operationType': 'insert'}}]
|
| 88 |
while True:
|
| 89 |
try:
|
| 90 |
async with patients_collection.watch(pipeline) as stream:
|
| 91 |
async for change in stream:
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
except Exception as e:
|
| 96 |
-
logger.error(f"Change stream processing error: {str(e)}")
|
| 97 |
except PyMongoError as e:
|
| 98 |
-
logger.error(f"MongoDB
|
| 99 |
await asyncio.sleep(5)
|
| 100 |
except Exception as e:
|
| 101 |
-
logger.error(f"Fatal error in
|
| 102 |
|
| 103 |
@router.on_event("startup")
|
| 104 |
async def startup_event():
|
| 105 |
asyncio.create_task(watch_for_new_patients())
|
|
|
|
| 106 |
|
| 107 |
-
@router.
|
| 108 |
-
async def
|
| 109 |
-
background_tasks: BackgroundTasks,
|
| 110 |
-
current_user: dict = Depends(get_current_user)
|
| 111 |
-
):
|
| 112 |
if current_user.get('role') not in ['admin', 'doctor']:
|
| 113 |
-
raise HTTPException(status_code=403, detail="
|
| 114 |
-
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
-
|
| 118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
if current_user.get('role') not in ['admin', 'doctor']:
|
| 120 |
-
raise HTTPException(status_code=403, detail="
|
|
|
|
| 121 |
try:
|
| 122 |
db = patients_collection.database
|
| 123 |
-
|
| 124 |
-
return
|
| 125 |
except Exception as e:
|
| 126 |
raise HTTPException(status_code=500, detail=f"Error listing summaries: {str(e)}")
|
| 127 |
|
| 128 |
-
pdf = router
|
|
|
|
| 5 |
from datetime import datetime
|
| 6 |
from bson import ObjectId
|
| 7 |
from bson.errors import InvalidId
|
| 8 |
+
import os
|
| 9 |
import logging
|
| 10 |
import asyncio
|
| 11 |
from typing import List, Dict, Optional
|
|
|
|
| 21 |
router = APIRouter()
|
| 22 |
|
| 23 |
# Configuration
|
| 24 |
+
SUMMARY_COLLECTION = "patient_summary_json"
|
| 25 |
|
| 26 |
+
async def generate_summary_json(patient: dict) -> Dict:
|
| 27 |
+
"""Generate a structured JSON summary from a patient dict."""
|
| 28 |
+
summary = {
|
| 29 |
"patient_id": patient.get("fhir_id"),
|
| 30 |
+
"full_name": patient.get("full_name"),
|
| 31 |
+
"gender": patient.get("gender"),
|
| 32 |
+
"date_of_birth": patient.get("date_of_birth"),
|
| 33 |
+
"age": calculate_age(patient.get("date_of_birth")),
|
| 34 |
+
"address": ", ".join(filter(None, [
|
| 35 |
+
patient.get("address"),
|
| 36 |
+
patient.get("city"),
|
| 37 |
+
patient.get("state"),
|
| 38 |
+
patient.get("postal_code"),
|
| 39 |
+
patient.get("country")
|
| 40 |
+
])),
|
| 41 |
+
"marital_status": patient.get("marital_status"),
|
| 42 |
+
"language": patient.get("language"),
|
| 43 |
+
"notes": patient.get("notes", []),
|
| 44 |
+
"conditions": patient.get("conditions", []),
|
| 45 |
+
"medications": patient.get("medications", []),
|
| 46 |
+
"encounters": patient.get("encounters", []),
|
| 47 |
+
"generated_at": datetime.utcnow()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
}
|
| 49 |
+
return summary
|
| 50 |
|
| 51 |
async def generate_and_store_summary(patient: dict) -> Optional[Dict]:
|
| 52 |
+
"""Generate and store patient summary JSON in MongoDB."""
|
| 53 |
try:
|
| 54 |
+
summary = await generate_summary_json(patient)
|
| 55 |
db = patients_collection.database
|
| 56 |
+
await db[SUMMARY_COLLECTION].update_one(
|
| 57 |
{"patient_id": summary["patient_id"]},
|
| 58 |
{"$set": summary},
|
| 59 |
upsert=True
|
| 60 |
)
|
| 61 |
+
logger.info(f"Inserted JSON summary for patient {summary['patient_id']}")
|
| 62 |
return summary
|
| 63 |
except Exception as e:
|
| 64 |
+
logger.error(f"Error storing summary for patient {patient.get('fhir_id')}: {str(e)}")
|
| 65 |
return None
|
| 66 |
|
| 67 |
+
async def generate_all_summaries() -> List[Dict]:
|
| 68 |
+
"""Generate and store summaries for all patients."""
|
| 69 |
+
results = []
|
| 70 |
try:
|
| 71 |
+
patients = await patients_collection.find({}).to_list(length=None)
|
|
|
|
| 72 |
for patient in patients:
|
| 73 |
summary = await generate_and_store_summary(patient)
|
| 74 |
if summary:
|
| 75 |
+
results.append(summary)
|
| 76 |
+
return results
|
| 77 |
except Exception as e:
|
| 78 |
+
logger.error(f"Error in generate_all_summaries: {str(e)}")
|
| 79 |
+
return results
|
| 80 |
|
| 81 |
async def watch_for_new_patients():
|
| 82 |
+
"""Watch MongoDB change stream for new patients and generate summaries."""
|
| 83 |
try:
|
| 84 |
logger.info("Starting MongoDB change stream for new summaries")
|
|
|
|
| 85 |
pipeline = [{'$match': {'operationType': 'insert'}}]
|
| 86 |
while True:
|
| 87 |
try:
|
| 88 |
async with patients_collection.watch(pipeline) as stream:
|
| 89 |
async for change in stream:
|
| 90 |
+
patient = change['fullDocument']
|
| 91 |
+
logger.info(f"New patient detected: {patient.get('fhir_id')}")
|
| 92 |
+
await generate_and_store_summary(patient)
|
|
|
|
|
|
|
| 93 |
except PyMongoError as e:
|
| 94 |
+
logger.error(f"MongoDB change stream error: {str(e)}")
|
| 95 |
await asyncio.sleep(5)
|
| 96 |
except Exception as e:
|
| 97 |
+
logger.error(f"Fatal error in watch_for_new_patients: {str(e)}")
|
| 98 |
|
| 99 |
@router.on_event("startup")
|
| 100 |
async def startup_event():
|
| 101 |
asyncio.create_task(watch_for_new_patients())
|
| 102 |
+
asyncio.create_task(generate_all_summaries())
|
| 103 |
|
| 104 |
+
@router.get("/generate-summary/{patient_id}")
|
| 105 |
+
async def generate_summary_for_one(patient_id: str, current_user: dict = Depends(get_current_user)):
|
|
|
|
|
|
|
|
|
|
| 106 |
if current_user.get('role') not in ['admin', 'doctor']:
|
| 107 |
+
raise HTTPException(status_code=403, detail="Unauthorized")
|
| 108 |
+
|
| 109 |
+
try:
|
| 110 |
+
query = {"fhir_id": patient_id}
|
| 111 |
+
patient = await patients_collection.find_one(query)
|
| 112 |
+
if not patient:
|
| 113 |
+
raise HTTPException(status_code=404, detail="Patient not found")
|
| 114 |
|
| 115 |
+
summary = await generate_and_store_summary(patient)
|
| 116 |
+
return {"status": "success", "summary": summary}
|
| 117 |
+
except Exception as e:
|
| 118 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 119 |
+
|
| 120 |
+
@router.get("/list-json-summaries", response_model=List[Dict])
|
| 121 |
+
async def list_all_summaries(current_user: dict = Depends(get_current_user)):
|
| 122 |
if current_user.get('role') not in ['admin', 'doctor']:
|
| 123 |
+
raise HTTPException(status_code=403, detail="Unauthorized")
|
| 124 |
+
|
| 125 |
try:
|
| 126 |
db = patients_collection.database
|
| 127 |
+
summaries = await db[SUMMARY_COLLECTION].find({}).to_list(length=None)
|
| 128 |
+
return summaries
|
| 129 |
except Exception as e:
|
| 130 |
raise HTTPException(status_code=500, detail=f"Error listing summaries: {str(e)}")
|
| 131 |
|
| 132 |
+
pdf = router
|