File size: 9,663 Bytes
5aec14b aa6bf8a 5aec14b 8acfcaf aaf8cf2 4bb7d6f e82969b 15ec37f aaf8cf2 e82969b 8acfcaf e82969b 15ec37f aa6bf8a e82969b aa6bf8a 15ec37f aa6bf8a 15ec37f aa6bf8a 15ec37f aa6bf8a aaf8cf2 5aec14b c37ed45 5aec14b 15ec37f aaf8cf2 5aec14b c37ed45 15ec37f 5aec14b c37ed45 5aec14b aa6bf8a c37ed45 15ec37f aa6bf8a c37ed45 5aec14b be39fa4 5aec14b be39fa4 4bb7d6f c37ed45 be39fa4 c37ed45 be39fa4 aa6bf8a 8acfcaf c37ed45 5aec14b be39fa4 5aec14b c37ed45 be39fa4 15ec37f 8acfcaf c37ed45 5aec14b aa6bf8a 15ec37f 5aec14b 15ec37f aa6bf8a 5aec14b aa6bf8a 5aec14b aaf8cf2 15ec37f aaf8cf2 aa6bf8a 15ec37f 5aec14b 8acfcaf aa6bf8a 5aec14b 8acfcaf 5aec14b aa6bf8a 5aec14b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# utils/oneclick.py
from typing import Tuple, Optional, Dict
from .meldrx import MeldRxAPI
from .responseparser import PatientDataExtractor
from .pdfutils import PDFGenerator
from .verifier import DischargeVerifier
import logging
import json
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"
verifier = DischargeVerifier()
def generate_ai_discharge_summary(patient_dict: Dict[str, str], client) -> Tuple[Optional[str], Optional[str]]:
"""Generate a discharge summary using AI and verify it for hallucinations."""
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
discharge_summary = discharge_summary.strip()
logger.info("AI discharge summary generated successfully")
# Verify the summary for hallucinations
question = "Provide a complete discharge summary based on the patient information."
verified_summary = verifier.verify_discharge_summary(
context=formatted_summary,
question=question,
answer=discharge_summary
)
return discharge_summary, verified_summary
except Exception as e:
logger.error(f"Error generating AI discharge summary: {str(e)}", exc_info=True)
return None, None
def generate_discharge_paper_one_click(
api: MeldRxAPI,
client,
patient_id: str = "",
first_name: str = "",
last_name: str = ""
) -> Tuple[Optional[str], str, Optional[str], Optional[str], Optional[str]]:
try:
patients_data = api.get_patients()
if not patients_data or "entry" not in patients_data:
logger.error("No patient data received from MeldRx API")
return None, "Failed to fetch patient data from MeldRx API", None, None, None
logger.debug(f"Raw patient data from API: {patients_data}")
extractor = PatientDataExtractor(patients_data, "json")
if not extractor.patients:
logger.error("No patients found in the parsed data")
return None, "No patients found in the data", None, None, None
logger.info(f"Found {len(extractor.patients)} patients in the data")
matching_patients = []
all_patient_ids = []
all_patient_names = []
for i in range(len(extractor.patients)):
extractor.set_patient_by_index(i)
patient_data = extractor.get_patient_dict()
patient_id_from_data = str(patient_data.get('id', '')).strip().lower()
first_name_from_data = str(patient_data.get('first_name', '')).strip().lower()
last_name_from_data = str(patient_data.get('last_name', '')).strip().lower()
all_patient_ids.append(patient_id_from_data)
all_patient_names.append(f"{first_name_from_data} {last_name_from_data}".strip())
patient_id_input = str(patient_id).strip().lower()
first_name_input = str(first_name).strip().lower()
last_name_input = str(last_name).strip().lower()
logger.debug(f"Patient {i}: ID={patient_id_from_data}, Name={first_name_from_data} {last_name_from_data}")
logger.debug(f"Comparing - Input: ID={patient_id_input}, First={first_name_input}, Last={last_name_input}")
# Match logic: ID takes precedence, then first/last name
matches = False
if patient_id_input and patient_id_from_data == patient_id_input:
matches = True
elif not patient_id_input and first_name_input and last_name_input:
if first_name_input == first_name_from_data and last_name_input == last_name_from_data:
matches = True
elif not patient_id_input and not first_name_input and not last_name_input:
continue # Skip if no criteria provided
if matches:
matching_patients.append(patient_data)
logger.info(f"Found matching patient: ID={patient_id_from_data}, "
f"Name={first_name_from_data} {last_name_from_data}")
if not matching_patients:
search_criteria = f"ID: {patient_id or 'N/A'}, First: {first_name or 'N/A'}, Last: {last_name or 'N/A'}"
logger.warning(f"No patients matched criteria: {search_criteria}")
logger.info(f"Available patient IDs: {all_patient_ids}")
logger.info(f"Available patient names: {all_patient_names}")
return None, (f"No patients found matching criteria: {search_criteria}\n"
f"Available IDs: {', '.join(all_patient_ids)}\n"
f"Available Names: {', '.join(all_patient_names)}"), None, None, None
patient_data = matching_patients[0] # Take the first match
logger.info(f"Selected patient data: {patient_data}")
basic_summary = format_discharge_summary(patient_data)
ai_summary, verified_summary = generate_ai_discharge_summary(patient_data, client)
if not ai_summary or not verified_summary:
return None, "Failed to generate or verify AI summary", basic_summary, None, 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 and verified successfully", basic_summary, ai_summary, verified_summary
return None, "Failed to generate PDF file", basic_summary, ai_summary, verified_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, None
def format_discharge_summary(patient_data: dict) -> str:
"""Format patient data into a discharge summary text."""
patient_data.setdefault('id', 'Unknown')
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('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['first_name']} {patient_data['last_name']}".strip(),
f"Patient ID: {patient_data['id']}",
f"Date of Birth: {patient_data['dob']}",
f"Age: {patient_data['age']}",
f"Gender: {patient_data['sex']}",
"",
"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 == "") |