Files
ordinaceprojekt/OrdinaceAgentEmail/NOTES.md
T
Vladimir Buzalka 2346ad7739 notebookvb
2026-06-13 21:46:11 +02:00

5.5 KiB

OrdinaceAgentEmail — agent na žádosti o recept

Hledá ve schránce ordinace@buzalkova.cz e-maily, kde pacient žádá o předepsání léku (recept), vytěžuje pacienta + požadované léky a pacienta ověřuje v kartotéce Medicusu.

Stav: testovací režim (read-only)

recepty_agent.py zatím jen načte NEWEST_N (= 5) nejnovějších mailů z Inboxu, klasifikuje je Claude modelem a vypíše report do konzole a _log_recepty.txt. Ve schránce nic nemění (žádné kategorie, přesuny, odpovědi), žádný state.json.

Tok

  1. Graph APInewest_inbox_messages(): N nejnovějších mailů z Inboxu, bez filtru na přílohy ($orderby receivedDateTime desc — bez filtru funguje, na rozdíl od kombinace s hasAttachments, viz EmailAgent).
  2. AI klasifikace + vytěžení (Claude claude-haiku-4-5) — pro každý mail JSON: je_zadost_o_recept, pacient (může se lišit od odesílatele — příbuzní píší za pacienta), rodne_cislo (přesně jak je v textu), datum_narozeni, leky[] (nazev + poznamka), poznamka, duvod.
  3. Ověření v Medicusu (MedicusLookup) — celá kartotéka se načte do paměti (KAR ~6300 pacientů + kontakty z KARKONTAKT: ~70 e-mailů, ~4150 telefonů; TYP: 1=pevná, 2=mobil, 3=e-mail). Párování v pořadí spolehlivosti:
    1. z textu mailu (Medicus ukládá RČ bez lomítka) — jednoznačné,
    2. e-mail odesílatele proti KARKONTAKT,
    3. telefon z textu mailu proti KARKONTAKT (jen číslice, bez +420 — telefonů je v kartotéce hodně, často rozhodne i duplicitní jména),
    4. jméno — bez diakritiky, bez ohledu na pořadí slov (Jaroslav Klíma = Klíma Jaroslav); při více kandidátech zúžení datem narození (z datum_narozeni nebo odvozeným z nesedícího RČ). Výstup: [SHODA RČ/E-MAIL/JMÉNO/JMÉNO+DATUM] s detaily pacienta (RČ, datum narození, pojišťovna, idpac, příznak vyřazení), nebo [NENALEZEN].
  4. Nejednoznačnost (více pacientů stejného jména, např. otec a syn)resolve_by_prescriptions(): načte nestornované recepty kandidátů z tabulky RECEPT (STORNO <> 'T', posledních RECEPT_MONTHS = 24 měsíců) a rozhodne podle shody požadovaných léků s historií:
    1. Deterministicky_drug_matches(): substring oběma směry („tadalafil" ~ „TADALAFIL ACCORD") + prefix prvních slov od 5 znaků („Concord" ~ „CONCOR"). Jediný kandidát s nejvyšším nenulovým skóre vyhrává → [SHODA JMÉNO+LÉKY V HISTORII].
    2. Claude fallback — když deterministika nerozhodne (nikdo/více se shodou), model dostane požadované léky + seznamy předepsaných léků kandidátů a rozhodne i přes generika/účinné látky → [SHODA JMÉNO+LÉKY+AI]. Když ani AI nerozhodne → [NEROZHODNUTO]
      • výpis kandidátů k ruční kontrole.
  5. Report + cena AI za běh (~0,04 Kč/mail).

Sdílená infrastruktura

  • EmailAgent/graph_mail.py — import přes sys.path (stejná app registrace, Mail.Read Application). Credentials natvrdo tam.
  • Knihovny/medicus_db.py — Firebird připojení k Medicusu (DSN podle názvu počítače, na Z230 → reporter:c:\medicus\medicus.fdb).
  • ANTHROPIC_API_KEY z Medevio/.env.

Vytvoření požadavku v Medeviu — medevio_recept.py

Funkce pro agenta: jakmile je pacient + léky správně identifikován, založí mu v Medeviu požadavek „Recept na léky", aby ho lékař viděl (Medevio kontrolujeme průběžně, e-mail zřídka).

from medevio_recept import vytvor_recept
rid = vytvor_recept(rodne_cislo="730920/8104",
                    nazev_leku="Euthyrox 100 µg",
                    poznamka="docházejí mi léky")

Co se stane (vše odchyceno z webu Medevia 2026-06-13, ověřeno na testovacím pacientovi):

  1. RČ → patient UUID přes MySQL medevio.medevio_pacient (identification_numberpatient_id).
  2. fillECRFForm (prázdný) → createPatientRequestWithoutReservation → založí „Recept na léky".
  3. createClinicPatientRequestNote → obě pole do interní poznámky (formátováno „Název léků / Poznámka").
  4. assignTagToPatientRequest → štítek CLAUDE (pridat_stitek=False vypne).

Proč interní poznámka, ne dotazník: lékařský přístup neumí vyplnit pacientský ECRF dotazník smysluplně (z lékařské strany má jen 1 pole nazev-leku), proto obsah jde do interní poznámky (viditelná jen pro ordinaci).

Auth: Bearer token z Medevio/token.txt (dlouhodobý). Test: python medevio_recept.py (založí testovací Recept na Vladkovi 0210db7b-…). Pro test bez DB lookup je parametr patient_uuid=. Mutace + konstanty jsou v Medevio/medevio_api_notes.md.

Známé limity / TODO

  • E-mailových kontaktů je v kartotéce málo (~70 z 6300 pacientů) — párování e-mailem zabere zřídka; telefonů je ~4150, proto se vytěžuje i telefon z textu mailu. Do budoucna by šlo e-mail odesílatele po ručním potvrzení do KARKONTAKT doplňovat.
  • Párování jménem vyžaduje přesnou shodu množiny slov — překlepy ve jméně nenajde (kandidát: fuzzy matching / nabídka podobných jmen).
  • Zatím bez označování mailů, bez summary e-mailu, bez odpovědi pacientovi — kandidáti na další krok (vzor: EmailAgent/faktury_agent.py).
  • Bez idempotence (žádný state) — testovací běhy čtou vždy posledních N mailů.

Spuštění

python U:\ordinaceprojekt\OrdinaceAgentEmail\recepty_agent.py