|
|
|
from typing import Tuple, Optional, Dict |
|
from .meldrx import MeldRxAPI |
|
from .responseparser import PatientDataExtractor |
|
from .pdfutils import PDFGenerator |
|
import logging |
|
from huggingface_hub import InferenceClient |
|
import os |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
if not HF_TOKEN: |
|
raise ValueError("HF_TOKEN environment variable not set.") |
|
client = InferenceClient(api_key=HF_TOKEN) |
|
MODEL_NAME = "meta-llama/Llama-3.3-70B-Instruct" |
|
|
|
def generate_ai_discharge_summary(patient_dict: Dict[str, str]) -> Optional[str]: |
|
"""Generate a discharge summary using AI based on extracted patient data.""" |
|
try: |
|
|
|
formatted_summary = format_discharge_summary(patient_dict) |
|
|
|
logger.info("Generating AI discharge summary with patient info: %s", formatted_summary) |
|
|
|
messages = [ |
|
{ |
|
"role": "assistant", |
|
"content": ( |
|
"You are a senior medical practitioner tasked with creating discharge summaries. " |
|
"Generate a complete discharge summary based on the provided patient information." |
|
) |
|
}, |
|
{"role": "user", "content": formatted_summary} |
|
] |
|
|
|
stream = client.chat.completions.create( |
|
model=MODEL_NAME, |
|
messages=messages, |
|
temperature=0.4, |
|
max_tokens=3584, |
|
top_p=0.7, |
|
stream=True |
|
) |
|
|
|
discharge_summary = "" |
|
for chunk in stream: |
|
content = chunk.choices[0].delta.content |
|
if content: |
|
discharge_summary += content |
|
|
|
logger.info("AI discharge summary generated successfully") |
|
return discharge_summary.strip() |
|
|
|
except Exception as e: |
|
logger.error(f"Error generating AI discharge summary: {str(e)}", exc_info=True) |
|
return None |
|
|
|
def generate_discharge_paper_one_click( |
|
api: MeldRxAPI, |
|
patient_id: str = "", |
|
first_name: str = "", |
|
last_name: str = "" |
|
) -> Tuple[Optional[str], str, Optional[str], Optional[str]]: |
|
""" |
|
Generate a discharge summary PDF with one click using MeldRx API data. |
|
|
|
Returns: |
|
Tuple of (pdf_path, status_message, basic_summary, ai_summary) |
|
""" |
|
try: |
|
patients_data = api.get_patients() |
|
if not patients_data or "entry" not in patients_data: |
|
return None, "Failed to fetch patient data from MeldRx API", None, None |
|
|
|
extractor = PatientDataExtractor(patients_data, "json") |
|
|
|
if not extractor.patients: |
|
return None, "No patients found in the data", None, None |
|
|
|
matching_patients = [] |
|
for i in range(len(extractor.patients)): |
|
extractor.set_patient_by_index(i) |
|
patient_data = extractor.get_patient_dict() |
|
|
|
patient_data.setdefault('id', 'unknown') |
|
patient_data.setdefault('first_name', '') |
|
patient_data.setdefault('last_name', '') |
|
|
|
if (not patient_id or patient_data.get("id", "") == patient_id) and \ |
|
(not first_name or patient_data.get("first_name", "").lower() == first_name.lower()) and \ |
|
(not last_name or patient_data.get("last_name", "").lower() == last_name.lower()): |
|
matching_patients.append(patient_data) |
|
|
|
if not matching_patients: |
|
return None, "No matching patients found with the provided criteria", None, None |
|
|
|
patient_data = matching_patients[0] |
|
extractor.set_patient_by_index(0) |
|
|
|
|
|
basic_summary = format_discharge_summary(patient_data) |
|
ai_summary = generate_ai_discharge_summary(patient_data) |
|
|
|
if not ai_summary: |
|
return None, "Failed to generate AI summary", basic_summary, None |
|
|
|
pdf_gen = PDFGenerator() |
|
filename = f"discharge_{patient_data.get('id', 'unknown')}_{patient_data.get('last_name', 'patient')}.pdf" |
|
pdf_path = pdf_gen.generate_pdf_from_text(ai_summary, filename) |
|
|
|
if pdf_path: |
|
return pdf_path, "Discharge summary generated successfully", basic_summary, ai_summary |
|
return None, "Failed to generate PDF file", basic_summary, ai_summary |
|
|
|
except Exception as e: |
|
logger.error(f"Error in one-click discharge generation: {str(e)}", exc_info=True) |
|
return None, f"Error generating discharge summary: {str(e)}", None, None |
|
|
|
def format_discharge_summary(patient_data: dict) -> str: |
|
"""Format patient data into a discharge summary text.""" |
|
patient_data.setdefault('name_prefix', '') |
|
patient_data.setdefault('first_name', '') |
|
patient_data.setdefault('last_name', '') |
|
patient_data.setdefault('dob', 'Unknown') |
|
patient_data.setdefault('age', 'Unknown') |
|
patient_data.setdefault('sex', 'Unknown') |
|
patient_data.setdefault('id', 'Unknown') |
|
patient_data.setdefault('address', 'Unknown') |
|
patient_data.setdefault('city', 'Unknown') |
|
patient_data.setdefault('state', 'Unknown') |
|
patient_data.setdefault('zip_code', 'Unknown') |
|
patient_data.setdefault('phone', 'Unknown') |
|
patient_data.setdefault('admission_date', 'Unknown') |
|
patient_data.setdefault('discharge_date', 'Unknown') |
|
patient_data.setdefault('diagnosis', 'Unknown') |
|
patient_data.setdefault('medications', 'None specified') |
|
patient_data.setdefault('doctor_first_name', 'Unknown') |
|
patient_data.setdefault('doctor_last_name', 'Unknown') |
|
patient_data.setdefault('hospital_name', 'Unknown') |
|
patient_data.setdefault('doctor_address', 'Unknown') |
|
patient_data.setdefault('doctor_city', 'Unknown') |
|
patient_data.setdefault('doctor_state', 'Unknown') |
|
patient_data.setdefault('doctor_zip', 'Unknown') |
|
|
|
summary = [ |
|
"DISCHARGE SUMMARY", |
|
"", |
|
"PATIENT INFORMATION", |
|
f"Name: {patient_data['name_prefix']} {patient_data['first_name']} {patient_data['last_name']}".strip(), |
|
f"Date of Birth: {patient_data['dob']}", |
|
f"Age: {patient_data['age']}", |
|
f"Gender: {patient_data['sex']}", |
|
f"Patient ID: {patient_data['id']}", |
|
"", |
|
"CONTACT INFORMATION", |
|
f"Address: {patient_data['address']}", |
|
f"City: {patient_data['city']}, {patient_data['state']} {patient_data['zip_code']}", |
|
f"Phone: {patient_data['phone']}", |
|
"", |
|
"ADMISSION INFORMATION", |
|
f"Admission Date: {patient_data['admission_date']}", |
|
f"Discharge Date: {patient_data['discharge_date']}", |
|
f"Diagnosis: {patient_data['diagnosis']}", |
|
"", |
|
"MEDICATIONS", |
|
f"{patient_data['medications']}", |
|
"", |
|
"PHYSICIAN INFORMATION", |
|
f"Physician: Dr. {patient_data['doctor_first_name']} {patient_data['doctor_last_name']}".strip(), |
|
f"Hospital: {patient_data['hospital_name']}", |
|
f"Address: {patient_data['doctor_address']}", |
|
f"City: {patient_data['doctor_city']}, {patient_data['doctor_state']} {patient_data['doctor_zip']}", |
|
] |
|
|
|
return "\n".join(line for line in summary if line.strip() or line == "") |