sanjeevani-api / backend /app /api /v1 /endpoints /documents.py
Sivaneshakumar's picture
V1
151ec26
Raw History Blame Contribute Delete
5.24 kB
import json
from typing import List
from fastapi import APIRouter, Depends, UploadFile, File, Request, status
from sqlalchemy.ext.asyncio import AsyncSession
from backend.app.core.database import get_db
from backend.app.schemas.document import MedicalDocumentResponse, DocumentAnalysisResponse, DocumentUploadResponse
from backend.app.schemas.ner import NEREntity
from backend.app.schemas.common import BaseResponse
from backend.app.services.document_service import DocumentService
from backend.app.repositories.document_repo import DocumentRepository
from backend.app.api.deps import get_current_user, get_client_ip
from backend.app.models.user import User
from backend.app.models.document import MedicalDocument
from backend.app.core.exceptions import ResourceNotFoundError, PermissionDeniedError
router = APIRouter()
def _format_document_response(doc: MedicalDocument) -> MedicalDocumentResponse:
analysis_resp = None
if doc.analysis:
analysis = doc.analysis
findings = json.loads(analysis.important_findings) if analysis.important_findings else []
conditions = json.loads(analysis.detected_conditions) if analysis.detected_conditions else []
medications = json.loads(analysis.detected_medications) if analysis.detected_medications else []
entities = [
NEREntity(
text=e.text,
label=e.label,
start=e.start_offset,
end=e.end_offset,
confidence=e.confidence,
model=e.model_name,
)
for e in (analysis.entities or [])
]
analysis_resp = DocumentAnalysisResponse(
id=analysis.id,
document_id=analysis.document_id,
raw_text=analysis.raw_text,
cleaned_text=analysis.cleaned_text,
summary=analysis.summary,
important_findings=findings,
detected_conditions=conditions,
detected_medications=medications,
clinical_recommendations=analysis.clinical_recommendations,
entities=entities,
processed_at=analysis.processed_at,
)
return MedicalDocumentResponse(
id=doc.id,
user_id=doc.user_id,
filename=doc.filename,
original_filename=doc.original_filename,
file_type=doc.file_type,
file_size=doc.file_size,
status=doc.status,
error_message=doc.error_message,
analysis=analysis_resp,
created_at=doc.created_at,
updated_at=doc.updated_at,
)
@router.post("/upload", response_model=BaseResponse[MedicalDocumentResponse])
async def upload_medical_document(
request: Request,
file: UploadFile = File(...),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""
Securely upload a medical report (PDF, DOCX, TXT), perform text extraction,
biomedical entity recognition, and clinical summarization.
"""
ip = get_client_ip(request)
doc_service = DocumentService(db)
doc = await doc_service.process_document_upload(file=file, user_id=current_user.id, ip_address=ip)
formatted = _format_document_response(doc)
return BaseResponse(
success=True,
message="Document uploaded and analyzed successfully.",
data=formatted,
)
@router.get("", response_model=BaseResponse[List[MedicalDocumentResponse]])
async def list_documents(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Retrieve all medical reports and document analyses uploaded by the current user."""
doc_repo = DocumentRepository(db)
docs = await doc_repo.get_user_documents(current_user.id)
formatted_docs = [_format_document_response(d) for d in docs]
return BaseResponse(
success=True,
data=formatted_docs,
)
@router.get("/{document_id}", response_model=BaseResponse[MedicalDocumentResponse])
async def get_document(
document_id: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Fetch detailed analysis, extracted entities, and summary for a specific document."""
doc_repo = DocumentRepository(db)
doc = await doc_repo.get_document_details(document_id, user_id=current_user.id)
if not doc:
raise ResourceNotFoundError(resource="Medical Document", resource_id=document_id)
return BaseResponse(
success=True,
data=_format_document_response(doc),
)
@router.delete("/{document_id}", response_model=BaseResponse[dict])
async def delete_document(
document_id: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Delete a medical report and all associated entity analysis records."""
doc_repo = DocumentRepository(db)
doc = await doc_repo.get_document_details(document_id, user_id=current_user.id)
if not doc:
raise ResourceNotFoundError(resource="Medical Document", resource_id=document_id)
await doc_repo.delete(document_id)
return BaseResponse(
success=True,
message="Document deleted successfully.",
data={"deleted_id": document_id},
)