praxis-briefing / briefing.py
jempf's picture
UI: clean EHR-style clinical theme; remove Peitho branding.
487b99f
Raw
History Blame Contribute Delete
5.8 kB
"""Mock Sprechstundenplan and prompts for Praxis-Briefing."""
from __future__ import annotations
from dataclasses import dataclass
@dataclass(frozen=True)
class BriefingPatient:
"""One demo appointment on today's schedule."""
time_label: str
name: str
age: int
reason: str
@dataclass(frozen=True)
class DemoQuestion:
"""Suggested voice question for the GP demo."""
prompt: str
log_label: str
TODAY_LABEL: str = "Mittwoch, 3. Juni 2026"
SCHEDULE: tuple[BriefingPatient, ...] = (
BriefingPatient("08:30", "Laura Müller", 34, "Halsschmerzen seit drei Tagen"),
BriefingPatient("09:00", "Thomas Schmidt", 58, "Blutdruck-Kontrolle"),
BriefingPatient("09:30", "Ayşe Yilmaz", 72, "Knieschmerzen rechts"),
BriefingPatient("10:30", "Jonas Weber", 19, "Attest für Sport"),
)
DEMO_QUESTIONS: tuple[DemoQuestion, ...] = (
DemoQuestion("Wer ist mein nächster Patient?", "Nächster Patient"),
DemoQuestion("Wie alt ist Frau Müller?", "Alter Müller"),
DemoQuestion("Was ist das Anliegen von Herrn Schmidt?", "Anliegen Schmidt"),
DemoQuestion("Wann kommt Jonas Weber?", "Termin Weber"),
)
BASE_SYSTEM_PROMPT: str = (
"Du bist der Sprach-Assistent einer Hausarztpraxis. "
"Du hast den heutigen Terminplan vorliegen und vollen Zugriff darauf. "
"Antworte immer kurz auf Deutsch, in genau einem Satz, "
"nur mit Informationen aus dem Plan. "
"Sage niemals, dass du keinen Zugriff oder keine Liste hast."
)
def format_schedule_markdown() -> str:
"""Render the mock day list for the setup tab."""
lines: list[str] = [
f"### Sprechstundenplan — {TODAY_LABEL}",
"",
"| Zeit | Patientin / Patient | Alter | Anliegen |",
"| --- | --- | ---: | --- |",
]
for slot in SCHEDULE:
lines.append(
f"| {slot.time_label} | {slot.name} | {slot.age} | {slot.reason} |"
)
lines.extend(
[
"",
"_Demo-Daten, keine echten Patienten. Kein Zugriff auf ein Praxissystem._",
]
)
return "\n".join(lines)
def format_schedule_plain() -> str:
"""Compact schedule string for the system prompt."""
parts: list[str] = []
for slot in SCHEDULE:
parts.append(
f"{slot.time_label} {slot.name}, {slot.age}, {slot.reason}."
)
return " ".join(parts)
def format_demo_questions_markdown() -> str:
"""Show example questions the GP can ask by voice."""
lines: list[str] = ["**Beispielfragen (frei formulierbar):**", ""]
for question in DEMO_QUESTIONS:
lines.append(f"- „{question.prompt}“")
return "\n".join(lines)
def format_schedule_html() -> str:
"""Render today's schedule as a clean clinical table panel."""
rows: list[str] = []
for slot in SCHEDULE:
rows.append(
"<tr>"
f"<td class='sc-time'>{slot.time_label}</td>"
f"<td class='sc-name'>{slot.name}</td>"
f"<td class='sc-age'>{slot.age}</td>"
f"<td class='sc-reason'>{slot.reason}</td>"
"</tr>"
)
return (
"<section class='panel'>"
"<header class='panel-head'>Sprechstundenplan"
f"<span class='panel-meta'>{TODAY_LABEL}</span></header>"
"<table class='sched'>"
"<thead><tr><th>Zeit</th><th>Patient/in</th><th>Alter</th><th>Anliegen</th></tr></thead>"
f"<tbody>{''.join(rows)}</tbody>"
"</table>"
"<footer class='panel-note'>Demo-Daten · keine echten Patienten · "
"kein Zugriff auf ein Praxissystem</footer>"
"</section>"
)
def format_demo_questions_html() -> str:
"""Render example voice questions as calm outline chips."""
chips: list[str] = [
f"<span class='chip'>{question.prompt}</span>" for question in DEMO_QUESTIONS
]
return (
"<div class='ask'>"
"<div class='ask-label'>Beispielfragen</div>"
f"<div class='chips'>{''.join(chips)}</div>"
"</div>"
)
def format_hero_html() -> str:
"""EHR-style top bar: clinic mark, app name, today's date."""
return (
"<div class='topbar'>"
"<div class='brand'>"
"<span class='brand-logo' aria-hidden='true'>+</span>"
"<span class='brand-text'>"
"<span class='brand-name'>Praxis-Briefing</span>"
"<span class='brand-sub'>Sprechstunden-Assistent</span>"
"</span>"
"</div>"
f"<div class='top-meta'>{TODAY_LABEL}<span class='top-meta-tag'>Sprechstunde</span></div>"
"</div>"
)
FEWSHOT_EXAMPLES: tuple[tuple[str, str], ...] = (
(
"Wer ist mein nächster Patient?",
"Ihr erster Termin ist um 08:30 Laura Müller, 34, mit Halsschmerzen.",
),
(
"Was ist das Anliegen von Herrn Schmidt?",
"Herr Schmidt kommt um 09:00 zur Blutdruck-Kontrolle.",
),
(
"Wann kommt Frau Yilmaz?",
"Frau Yilmaz kommt um 09:30 wegen Knieschmerzen rechts.",
),
(
"Wie alt ist Jonas Weber?",
"Jonas Weber ist 19 Jahre alt und kommt um 10:30 für ein Attest.",
),
)
def build_system_prompt() -> str:
"""Behavioral prompt plus the full schedule as context."""
return f"{BASE_SYSTEM_PROMPT} Heutiger Terminplan: {format_schedule_plain()}"
def build_user_grounding() -> str:
"""Short lead-in before each spoken question (plan already in context)."""
return "Beantworte meine folgende gesprochene Frage kurz und nur aus dem heutigen Terminplan."
def classify_reply(assistant_reply: str) -> str:
"""Coarse log tag for the session table."""
normalized: str = assistant_reply.lower()
if "nichts im heutigen plan" in normalized or "praxissystem" in normalized:
return "nicht_im_plan"
return "aus_plan"