CoolFace
Apppublic

Timoladunni/NursingNote

sourceHugging Faceupdated 11mo agoView on Hugging Face
0likes
app.py230 linesDownload Raw Back to root
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