Spaces:
Running on Zero
Running on Zero
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 · "
f"**SOAP generation:** {generation_s:.2f}s · "
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=[])
|