Share what has been happening, what you have noticed, and what you take.
The assistant turns it into a clear timeline, useful questions, and background notes.
Export actions include the symptoms, notes, medications, timeline, questions,
and relevant info. Review before sending, saving, or pasting into another service.
Medical Appointment Prep helps people turn symptoms, notes, and
medications into a visit-ready timeline, questions, and background
information they can review with a clinician.
Informational onlyNo diagnosisPatient-controlled export4B small-model buildllama.cpp Space runtime
The interface is designed to feel familiar and approachable, with
plain-language prompts and report sections that match how people
prepare for appointments.
Safety
Organization, not advice
The app helps organize what the user provides. It does not diagnose,
choose treatment, or replace a qualified healthcare professional.
Hackathon fit
Small model, custom Gradio UI
The app is designed for the Backyard AI track: a specific appointment-prep
workflow, a custom Gradio Server frontend, and a MedGemma 1.5 4B GGUF
runtime through llama.cpp in the hosted Space.
I always find it hard to remember what to ask or mention in the middle
of an appointment. Helping a parent with appointments can be even more
confusing, and this helps ensure we get the right help needed. Having
this sheet to read from or share with my doctor will help me in my
future appointments.
- My Spouse
Acknowledgements
Thank you to the Build Small Hackathon sponsors.
This project was built for the Hugging Face Build Small Hackathon.
Thanks to the sponsors for supporting small-model experiments, and
especially to OpenAI's Codex for helping shape, test, and ship the app.
"""
def create_server_app() -> gr.Server:
"""Create a custom Server-mode app with Gradio's queued API backend."""
server = gr.Server(title="Medical Appointment Prep Assistant")
@server.api(
name="generate",
concurrency_limit=1,
concurrency_id="llama-cpp-gpu",
api_visibility="public",
)
def generate(symptoms: str, notes: str, medications: str) -> tuple[str, str, str]:
return run_inference(symptoms, notes, medications)
@server.get("/", response_class=HTMLResponse)
async def homepage():
return _custom_frontend_html()
@server.get("/about", response_class=HTMLResponse)
async def about_page():
return _about_frontend_html()
@server.get("/assets/{asset_name}")
async def asset(asset_name: str):
allowed_assets = {
"server.css": CUSTOM_UI_CSS_PATH,
"server.js": CUSTOM_UI_JS_PATH,
"assistant-robot.jpeg": ROBOT_IMAGE_PATH,
}
asset_path = allowed_assets.get(asset_name)
if asset_path is None:
return HTMLResponse("Not found", status_code=404)
return FileResponse(ROOT_DIR / asset_path)
@server.get("/api/medications")
async def medication_suggestions(q: str = ""):
return {"choices": filter_medication_choices(q, load_medication_choices(), limit=20)}
return server
def launch_app() -> None:
server_host = settings.get("server", {}).get("host", "127.0.0.1")
server_port = settings.get("server", {}).get("port", 7860)
if os.getenv("APP_UI_MODE", "").strip().lower() == "blocks":
ui = create_ui()
ui.launch(
server_name=server_host,
server_port=server_port,
theme=APPLE_THEME,
css_paths=[APPLE_CSS_PATH],
head=THEME_MODE_HEAD,
footer_links=["api"],
share=False,
inbrowser=True,
)
return
server = create_server_app()
server.launch(
server_name=server_host,
server_port=server_port,
show_error=True,
inbrowser=True,
)
def create_ui() -> gr.Blocks:
app_cfg = settings.get("app", {})
model_cfg = settings.get("model", {})
backend = model_cfg.get("backend", "ollama")
selected_model_preset_id = get_default_model_preset_id(settings, backend)
selected_model_settings = _model_settings_for_selection(selected_model_preset_id)
all_medication_choices = load_medication_choices()
medication_summary = medication_index_summary()
deployment = app_cfg.get("deployment", "local")
is_local_deployment = deployment == "local"
if is_local_deployment:
about_heading = "Local medical appointment preparation."
about_copy = "This tool organizes appointment notes with a local language model."
elif deployment == "huggingface":
about_heading = "Space-local medical appointment preparation."
about_copy = (
"This tool organizes appointment notes with a language model running "
"inside this Hugging Face Space."
)
else:
about_heading = "Hosted medical appointment preparation."
about_copy = "This tool organizes appointment notes with a hosted language model backend."
if backend.lower() in ("hf_transformers", "huggingface", "transformers"):
get_model(selected_model_settings)
with gr.Blocks(
title="Medical Appointment Prep Assistant",
elem_id="app-shell",
fill_width=True,
) as app:
gr.HTML(
f"""
Medical Appointment Prep
Medical Appointment Prep
Arrive clear, organized, and ready.
Turn symptoms, notes, and medications into a concise timeline,
visit questions, and relevant background information.
"""
)
with gr.Tab("Prepare", elem_classes=["main-tabs"]):
with gr.Row(elem_classes=["prep-grid"]):
with gr.Column(scale=1, elem_classes=["input-pane"]):
gr.HTML(
"""
Tell us about your visit
"""
)
gr.HTML('
Symptoms
')
symptoms = gr.Textbox(
label="Symptoms",
show_label=False,
placeholder="Headache behind eyes for 3 days, worse in the morning, mild nausea",
lines=6,
max_lines=12,
elem_classes=["apple-input"],
)
gr.HTML('
')
medication_name = gr.Textbox(
label="Medication Name",
show_label=False,
placeholder="Select a medication above, or type any medication, vitamin, or supplement",
lines=1,
max_lines=2,
elem_classes=["apple-input"],
)
gr.HTML('
How You Take It
')
medication_instructions = gr.Textbox(
label="Medication Instructions",
show_label=False,
placeholder="How you take it, e.g. once daily, as needed, with food",
lines=2,
max_lines=4,
elem_classes=["apple-input"],
)
add_medication_btn = gr.Button(
"Add Medication",
variant="secondary",
elem_classes=["secondary-pill", "add-medication-button"],
)
medications = gr.Textbox(
label="Current Medications",
show_label=False,
placeholder="Selected medications will appear here. You can also edit this list directly.",
lines=4,
max_lines=8,
elem_classes=["apple-input"],
)
with gr.Row(elem_classes=["button-row"]):
submit_btn = gr.Button(
"Generate Prep Report",
variant="primary",
size="lg",
elem_classes=["primary-pill"],
)
clear_btn = gr.Button(
"Clear",
variant="secondary",
elem_classes=["secondary-pill"],
)
with gr.Column(scale=1, elem_classes=["output-pane"]):
gr.HTML(
"""
Your appointment prep
"""
)
with gr.Tabs(elem_classes=["output-tabs"]):
with gr.Tab("Timeline"):
timeline_output = gr.Markdown(
label="Symptom Timeline",
value=DEFAULT_OUTPUT,
elem_classes=["report-output"],
)
with gr.Tab("Questions"):
questions_output = gr.Markdown(
label="Questions to Ask",
value=DEFAULT_OUTPUT,
elem_classes=["report-output"],
)
with gr.Tab("Relevant Info"):
relevant_output = gr.Markdown(
label="Relevant Medical Information",
value=DEFAULT_OUTPUT,
elem_classes=["report-output"],
)
with gr.Tab("About", elem_classes=["main-tabs"]):
gr.HTML(
f"""
About
{about_heading}
{about_copy}
It is for informational and organizational purposes only, not diagnosis,
treatment, or a substitute for professional medical advice.
I always find it hard to remember what to ask or mention in the middle
of an appointment. Helping a parent with appointments can be even more
confusing, and this helps ensure we get the right help needed. Having
this sheet to read from or share with my doctor will help me in my
future appointments.
- My Spouse
Acknowledgements
Built for the Hugging Face Build Small Hackathon. Thank you to the
sponsors supporting small-model work, especially
OpenAI Codex.