File size: 3,914 Bytes
ecfd585
 
 
 
 
 
 
 
c0b9ab9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ecfd585
c0b9ab9
 
 
ecfd585
c0b9ab9
 
ecfd585
 
 
c0b9ab9
 
cce75df
 
 
ecfd585
 
 
 
c0b9ab9
ecfd585
c0b9ab9
 
 
 
 
ecfd585
 
9c945c6
 
 
 
 
ecfd585
 
9c945c6
ecfd585
 
 
 
 
c0b9ab9
ecfd585
 
 
9c945c6
 
 
 
cce75df
c0b9ab9
ecfd585
c0b9ab9
 
ecfd585
c0b9ab9
 
 
9c945c6
 
 
 
ecfd585
c0b9ab9
 
9c945c6
ecfd585
 
c0b9ab9
 
9c945c6
 
 
 
 
 
 
c0b9ab9
 
9c945c6
 
ecfd585
9c945c6
c0b9ab9
 
 
ecfd585
 
 
 
 
 
 
 
 
 
 
9c945c6
 
 
 
ecfd585
 
cce75df
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
"""AI medical scribe: audio -> MedASR transcript -> MedGemma SOAP note."""

import os

import gradio as gr

from llm import run_pipeline

_CLIPS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_audio", "clips")

SAMPLES = [
    ("Sample 1 — Psychiatric referral", os.path.join(_CLIPS_DIR, "D0420-S1-T01_clip.wav")),
    ("Sample 2 — Mood check-in", os.path.join(_CLIPS_DIR, "D0420-S2-T01_clip.wav")),
    ("Sample 3 — Sleep & nightmares", os.path.join(_CLIPS_DIR, "D0420-S3-T01_clip.wav")),
]

THEME = gr.themes.Soft(primary_hue=gr.themes.colors.blue)

CSS = """
.gradio-container { max-width: 1100px !important; }
#hero {
    background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
    color: #fff;
    border-radius: 16px;
    padding: 28px;
}
#hero h1 { margin: 0 0 8px 0; font-size: 31px; font-weight: 800; }
.pill {
    display: inline-block;
    background: rgba(255,255,255,.2);
    border: 1px solid rgba(255,255,255,.4);
    padding: 5px 13px;
    border-radius: 999px;
    font-size: 12.5px;
    margin: 0 8px 6px 0;
}
"""

HERO = """
<div id="hero">
  <h1>Medical Notes Using Medgemma</h1>
  <p>Turn a raw clinical recording into a structured SOAP note — nothing is
  fabricated beyond what was actually said.</p>
</div>
"""


def timing_md(transcription_s: float, generation_s: float) -> str:
    total = transcription_s + generation_s
    return (
        f"**Transcription:** {transcription_s:.2f}s &nbsp;·&nbsp; "
        f"**SOAP generation:** {generation_s:.2f}s &nbsp;·&nbsp; "
        f"**Total:** {total:.2f}s"
    )


PLACEHOLDER_TRANSCRIPT = ""
PLACEHOLDER_SOAP = "*Select an audio file and click Run.*"
PLACEHOLDER_TIMING = ""


def run(audio_file):
    if audio_file is None:
        return "No audio file selected.", PLACEHOLDER_SOAP, PLACEHOLDER_TIMING

    result = run_pipeline(audio_file)
    return (
        result.transcript,
        result.soap_note,
        timing_md(result.transcription_seconds, result.generation_seconds),
    )


def clear_audio():
    return None, PLACEHOLDER_TRANSCRIPT, PLACEHOLDER_SOAP, PLACEHOLDER_TIMING


with gr.Blocks(title="Medical Notes Using Medgemma") as demo:
    gr.HTML(HERO)

    with gr.Row():
        sample_buttons = [gr.Button(label, size="sm") for label, _ in SAMPLES]

    with gr.Row():
        with gr.Column(scale=3):
            audio_input = gr.Audio(
                label="Audio recording",
                sources=["upload"],
                type="filepath",
                buttons=[],
            )
        with gr.Column(scale=1, min_width=160):
            run_button = gr.Button("Run pipeline", variant="primary", size="lg")
            clear_button = gr.Button("Clear audio", size="sm")

    with gr.Row():
        with gr.Column():
            gr.Markdown("### MedASR Transcript")
            with gr.Group():
                transcript_output = gr.Textbox(
                    show_label=False,
                    lines=15,
                    container=False,
                    placeholder="Transcript will appear here…",
                )
        with gr.Column():
            gr.Markdown("### SOAP Note — MedGemma 4B")
            with gr.Group():
                soap_output = gr.Markdown(PLACEHOLDER_SOAP)

    timing_output = gr.Markdown(PLACEHOLDER_TIMING)

    for btn, (_, path) in zip(sample_buttons, SAMPLES):
        btn.click(lambda p=path: p, outputs=[audio_input])

    audio_input.change(
        fn=run,
        inputs=[audio_input],
        outputs=[transcript_output, soap_output, timing_output],
    )
    run_button.click(
        fn=run,
        inputs=[audio_input],
        outputs=[transcript_output, soap_output, timing_output],
    )
    clear_button.click(
        fn=clear_audio,
        outputs=[audio_input, transcript_output, soap_output, timing_output],
    )

if __name__ == "__main__":
    demo.launch(theme=THEME, css=CSS, footer_links=[])