Timoladunni/NursingNote
0
1import gradio as gr2import whisper3import re4from datetime import datetime5 6# lazy-load whisper so the Space boots reliably7_model = None8def get_model():9 global _model10 if _model is None:11 _model = whisper.load_model("tiny")12 return _model13 14# ----------------- small extractors -----------------15def split_speakers(text: str):16 """split very simply on Nurse: / Patient:"""17 nurse_parts, patient_parts = [], []18 text = text.replace("\\n", "\n")19 lines = re.split(r'(?<=\.)\s+|\n+', text)20 for line in lines:21 clean = line.strip()22 if not clean:23 continue24 low = clean.lower()25 if low.startswith("nurse:"):26 nurse_parts.append(clean[len("nurse:"):].strip())27 elif low.startswith("patient:"):28 patient_parts.append(clean[len("patient:"):].strip())29 else:30 # dump unknown lines into patient bucket31 patient_parts.append(clean)32 return " ".join(nurse_parts).strip(), " ".join(patient_parts).strip()33 34def find_chief_complaint(text: str):35 m = re.search(r"(my|i have|i'm having|the problem is)\s+([^\.]+)", text, re.IGNORECASE)36 return m.group(0).strip() if m else ""37 38def find_med(text: str):39 meds = []40 if "abilify" in text.lower():41 meds.append("Abilify")42 common = re.findall(r"(tylenol|ibuprofen|advil|motrin|metformin|lisinopril)", text, re.IGNORECASE)43 meds += [c.capitalize() for c in common]44 return ", ".join(sorted(set(meds)))45 46def find_sleep(text: str):47 if re.search(r"sleep(ing)? (ok|okay|well|better)", text, re.IGNORECASE):48 return "Sleeping adequately."49 return ""50 51def denies_suicidal(text: str):52 return bool(re.search(r"den(y|ies|ied) suicidal|no suicidal|denies si", text, re.IGNORECASE))53 54def denies_hallucinations(text: str):55 return bool(re.search(r"no (visual|auditory) hallucination|denies hallucination", text, re.IGNORECASE))56 57def find_weight(text: str):58 m = re.search(r"lost (\d+)\s*(pounds|lbs?)", text, re.IGNORECASE)59 return m.group(0) if m else ""60 61def find_stress(text: str):62 if "stress" in text.lower() or "stressor" in text.lower():63 return "Reports managing family/life stressors."64 return ""65 66def suggest_icd(text: str):67 """very tiny suggester just to populate the section"""68 suggestions = []69 if "depress" in text.lower() or "mood" in text.lower():70 suggestions.append(("F33.9", "Major depressive disorder, recurrent, unspecified"))71 if "anxiety" in text.lower():72 suggestions.append(("F41.9", "Anxiety disorder, unspecified"))73 if "psych" in text.lower() or "hallucination" in text.lower():74 suggestions.append(("F29", "Unspecified psychosis"))75 if not suggestions:76 suggestions.append(("Z76.89", "Person encountering health services in other circumstances"))77 return suggestions78 79# ----------------- note builder -----------------80def build_note(transcript: str, patient_name: str, nurse_name: str) -> str:81 nurse_talk, patient_talk = split_speakers(transcript)82 source = patient_talk or transcript83 84 cc = find_chief_complaint(source)85 meds = find_med(source)86 sleep = find_sleep(source)87 suicidal = denies_suicidal(source)88 halluc = denies_hallucinations(source)89 weight = find_weight(source)90 stress = find_stress(source)91 icds = suggest_icd(source)92 93 now = datetime.now().strftime("%Y-%m-%d %H:%M")94 95 lines = []96 lines.append(f"Visit Summary")97 visit_summary_parts = []98 99 if cc:100 visit_summary_parts.append(f"{patient_name or 'The patient'} presented reporting {cc}.")101 else:102 visit_summary_parts.append(f"{patient_name or 'The patient'} presented for follow-up.")103 104 if meds:105 visit_summary_parts.append(f"The medication ({meds}) is helping manage symptoms and stressors.")106 if suicidal:107 visit_summary_parts.append("Patient denied suicidal ideation.")108 if halluc:109 visit_summary_parts.append("Patient denied visual and auditory hallucinations.")110 if sleep:111 visit_summary_parts.append(sleep)112 if weight:113 visit_summary_parts.append(f"Patient {weight}.")114 if not visit_summary_parts:115 visit_summary_parts.append("See subjective section for details.")116 lines.append(" ".join(visit_summary_parts))117 lines.append("")118 119 # Subjective120 lines.append("Subjective")121 lines.append("History of Present Illness")122 if cc:123 lines.append(f"{patient_name or 'The patient'} reports {cc}.")124 if sleep:125 lines.append(sleep)126 if stress:127 lines.append(stress)128 if meds:129 lines.append(f"Current medication: {meds}.")130 if suicidal:131 lines.append("Denies suicidal ideation.")132 if halluc:133 lines.append("Denies visual and auditory hallucinations.")134 lines.append("")135 136 # Objective137 lines.append("Objective")138 lines.append("Physical Examination")139 psych_line = "Psychiatric: "140 psych_bits = []141 if halluc:142 psych_bits.append("No visual or auditory hallucinations.")143 if suicidal:144 psych_bits.append("No suicidal ideation.")145 if not psych_bits:146 psych_bits.append("Mental status within normal limits by conversation; full assessment recommended.")147 lines.append(f"- {psych_line}{' '.join(psych_bits)}")148 lines.append("")149 150 # Assessment & Plan151 lines.append("Assessment & Plan")152 # 1. psychiatric condition on medication153 ap_lines = []154 ap_lines.append("1. Psychiatric condition on medication")155 med_sentence = "Patient reports improvement in psychiatric symptoms since starting medication."156 if meds:157 med_sentence = f"Patient reports improvement in psychiatric symptoms with good response to {meds}."158 ap_lines.append(med_sentence)159 if suicidal:160 ap_lines.append("She denies suicidal ideation.")161 if halluc:162 ap_lines.append("She denies visual and auditory hallucinations.")163 ap_lines.append("No adverse reactions noted in the conversation.")164 ap_lines.append("- Plan:")165 if meds:166 ap_lines.append(f" - Continue {meds}.")167 else:168 ap_lines.append(" - Continue current psychiatric regimen.")169 ap_lines.append(" - Continue current diet and exercise regimen as tolerated.")170 lines.extend(ap_lines)171 lines.append("")172 173 # add weight management example like your screenshot174 lines.append("2. Weight management")175 if weight:176 lines.append(f"Patient {weight} through diet modifications and physical activity; encourage continuation.")177 else:178 lines.append("Encourage healthy diet and regular physical activity.")179 lines.append("")180 181 # Clinical Codes182 lines.append("Clinical Codes")183 for code, desc in icds:184 lines.append(f"{code} {desc}")185 lines.append("")186 187 # Patient Instructions188 lines.append("Patient Instructions")189 lines.append("Thank you for meeting with me today. Below is a summary of the items we discussed and the next steps in your care plan.")190 if meds:191 lines.append(f"1. Continue taking {meds} as prescribed.")192 else:193 lines.append("1. Continue taking your prescribed medication as instructed.")194 lines.append("2. Keep working on your diet and stay physically active every day.")195 lines.append("3. Notify the clinic if your symptoms worsen, or if you experience suicidal thoughts or hallucinations.")196 lines.append("4. Keep follow-up appointments as scheduled.")197 lines.append("")198 lines.append(f"Documented by: {nurse_name or '________________'}")199 200 return "\n".join(lines)201 202# ----------------- main fn -----------------203def voice_to_note(patient_name, nurse_name, audio_path):204 if audio_path is None:205 return "No audio provided.", "No note generated."206 model = get_model()207 result = model.transcribe(audio_path)208 transcript = result["text"]209 note = build_note(transcript, patient_name, nurse_name)210 return transcript, note211 212# ----------------- UI -----------------213demo = gr.Interface(214 fn=voice_to_note,215 inputs=[216 gr.Textbox(label="Patient name", placeholder="e.g. Imani S."),217 gr.Textbox(label="Nurse name", placeholder="e.g. T. Oladunni, RN"),218 gr.Audio(sources=["microphone", "upload"], type="filepath",219 label="🎙️ Speak or upload the nurse–patient conversation")220 ],221 outputs=[222 gr.Textbox(label="Transcript (from speech)", lines=8),223 gr.Textbox(label="Structured Nursing Note", lines=32),224 ],225 title="Nurse–Patient Conversation → Structured Nursing Note",226 description="Speak like: 'Nurse: ...', 'Patient: ...'. The app will build Visit Summary, Subjective, Objective, Assessment & Plan, Clinical Codes, and Patient Instructions."227)228 229demo.launch()230 