112 lines
4.0 KiB
Python
112 lines
4.0 KiB
Python
import json
|
|
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.ai.gemini_client import GeminiClient
|
|
from app.database.database import get_db
|
|
from app.schemas.documents import DocumentExtractionResponse
|
|
from app.services.onboarding_service import OnboardingService
|
|
|
|
from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile
|
|
from app.core.security import get_auth_context, AuthContext, check_rate_limit
|
|
|
|
router = APIRouter(
|
|
prefix="/v1/documents",
|
|
tags=["Medical Documents"],
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/{session_id}/upload",
|
|
response_model=DocumentExtractionResponse,
|
|
)
|
|
async def upload_medical_document(
|
|
session_id: str,
|
|
file: UploadFile = File(...),
|
|
req_obj: Request = None,
|
|
auth: AuthContext = Depends(get_auth_context),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
if req_obj and req_obj.client:
|
|
check_rate_limit(req_obj.client.host, limit=10, window_sec=60)
|
|
|
|
onboarding_service = OnboardingService()
|
|
gemini_client = GeminiClient()
|
|
|
|
session = onboarding_service.get_session(db, session_id)
|
|
if not session:
|
|
raise HTTPException(status_code=404, detail="Onboarding session not found")
|
|
|
|
# 1b. Verify Session Ownership (IDOR Prevention)
|
|
if session.patient_id != auth.patient_id and auth.role != "admin":
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Forbidden: You do not have authorization to upload documents to this session.",
|
|
)
|
|
|
|
# Enforce MIME type and File Size Limits (10MB MAX)
|
|
allowed_mimes = ["image/jpeg", "image/png", "image/webp", "application/pdf"]
|
|
mime_type = file.content_type or "application/pdf"
|
|
if mime_type not in allowed_mimes:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Unsupported document format: {mime_type}. Allowed formats: JPEG, PNG, WEBP, PDF.",
|
|
)
|
|
|
|
file_bytes = await file.read()
|
|
if len(file_bytes) > 10 * 1024 * 1024:
|
|
raise HTTPException(
|
|
status_code=413,
|
|
detail="File size exceeds maximum allowed limit of 10MB.",
|
|
)
|
|
|
|
patient_context = {
|
|
"id": session.patient_id,
|
|
"name": session.patient_name,
|
|
"age": session.age,
|
|
"gender": session.gender,
|
|
"category": session.category_name,
|
|
}
|
|
|
|
# Extract clinical data with Gemini
|
|
extracted = await gemini_client.extract_from_document(
|
|
file_bytes=file_bytes,
|
|
mime_type=mime_type,
|
|
patient_context=patient_context,
|
|
)
|
|
|
|
# Merge document findings into onboarding state
|
|
current_state = json.loads(state.state_json)
|
|
|
|
# Append medications if found
|
|
meds_found = extracted.get("medications_found", [])
|
|
if meds_found:
|
|
existing_meds = current_state.get("medications", {})
|
|
items = existing_meds.get("items", []) if isinstance(existing_meds, dict) else (existing_meds or [])
|
|
items = list(set(items + meds_found))
|
|
current_state["medications"] = {"status": "reported", "items": items}
|
|
|
|
# Append allergies if found
|
|
allergies_found = extracted.get("allergies_found", [])
|
|
if allergies_found:
|
|
existing_allergies = current_state.get("allergies", {})
|
|
items = existing_allergies.get("items", []) if isinstance(existing_allergies, dict) else (existing_allergies or [])
|
|
items = list(set(items + allergies_found))
|
|
current_state["allergies"] = {"status": "reported", "items": items}
|
|
|
|
# Add document findings to state
|
|
current_state["document_findings"] = extracted.get("findings", [])
|
|
|
|
onboarding_service.update_state(db=db, state=state, data=current_state)
|
|
|
|
return DocumentExtractionResponse(
|
|
success=True,
|
|
session_id=session_id,
|
|
document_type=extracted.get("document_type", "medical_report"),
|
|
summary=extracted.get("summary", "Document analyzed successfully"),
|
|
findings=extracted.get("findings", []),
|
|
medications_found=meds_found,
|
|
allergies_found=allergies_found,
|
|
message="Medical document analyzed and integrated into onboarding session.",
|
|
)
|