notebookvb
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
recept_resolver.py — vyřizuje "čekající" žádosti o recept přes Telegram.
|
||||
|
||||
Jediný proces, který mluví s Telegramem (kvůli getUpdates). Ve smyčce:
|
||||
1) pošle otázky pro nové pending záznamy (které ještě otázku nemají),
|
||||
2) long-polluje odpovědi; odpověď (reply na otázku) → podle obsahu:
|
||||
• RČ (9–10 číslic) → definitivní volba pacienta → založí požadavek
|
||||
• číslo kandidáta → vybere kandidáta → založí požadavek
|
||||
• „ne“ → přeskočí (nezakládá)
|
||||
Po založení označí původní e-mail kategorií ClaudeZpracovalRecept.
|
||||
|
||||
Telegram přenos je v recept_telegram.py (token/chat dodá uživatel).
|
||||
Bez odpovědi záznam zůstává 'ceka' (čeká se libovolně dlouho).
|
||||
|
||||
Spuštění: python recept_resolver.py
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(HERE.parent / "EmailAgent"))
|
||||
sys.path.insert(0, str(HERE.parent))
|
||||
|
||||
import recept_pending as PEND # noqa: E402
|
||||
import recept_dialog as DLG # noqa: E402
|
||||
import recept_telegram as TG # noqa: E402
|
||||
import graph_mail # noqa: E402 (značení mailu)
|
||||
import mcp_medevio as MED # noqa: E402 (zaloz_pozadavek_recept)
|
||||
from Knihovny.mysql_db import connect_mysql # noqa: E402
|
||||
|
||||
MAILBOX = "ordinace@buzalkova.cz"
|
||||
PROCESSED_CATEGORY = "ClaudeZpracovalRecept"
|
||||
SINCE_FILE = HERE / "_resolver_since.txt" # poslední zpracované message_id
|
||||
|
||||
|
||||
def log(msg: str) -> None:
|
||||
print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)
|
||||
|
||||
|
||||
def _norm_rc(s: str) -> str:
|
||||
return re.sub(r"\D", "", s or "")
|
||||
|
||||
|
||||
def najdi_pacienta_dle_rc(rc: str):
|
||||
"""RČ → (uuid, jmeno, prijmeni) z medevio_pacient, nebo None."""
|
||||
rc = _norm_rc(rc)
|
||||
if not rc:
|
||||
return None
|
||||
try:
|
||||
conn = connect_mysql()
|
||||
conn.ping(reconnect=True)
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT patient_id, name, surname FROM medevio_pacient "
|
||||
"WHERE REPLACE(identification_number,'/','') = %s LIMIT 1",
|
||||
[rc],
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return row if row else None
|
||||
except Exception as e:
|
||||
log(f"[uuid lookup chyba] {type(e).__name__}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def _load_since():
|
||||
try:
|
||||
return int(SINCE_FILE.read_text(encoding="utf-8").strip())
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _save_since(s: int) -> None:
|
||||
SINCE_FILE.write_text(str(s), encoding="utf-8")
|
||||
|
||||
|
||||
def posli_nove_otazky() -> None:
|
||||
"""Pošle otázku do Telegramu pro každý pending záznam bez otázky."""
|
||||
for rec in PEND.cekajici_bez_otazky():
|
||||
try:
|
||||
mid = TG.posli_otazku(DLG.format_otazka(rec))
|
||||
PEND.aktualizuj(rec["id"], otazka_message_id=mid)
|
||||
log(f"otázka odeslána (pending {rec['id'][:8]}, msg {mid})")
|
||||
except Exception as e:
|
||||
log(f"otázku nelze odeslat ({type(e).__name__}: {e}) — zkusím příště")
|
||||
break # nejspíš výpadek / nenakonfigurováno → nech na příští kolo
|
||||
|
||||
|
||||
def _zaloz_pro_rc(rec: dict, rc: str) -> None:
|
||||
info = najdi_pacienta_dle_rc(rc)
|
||||
if not info:
|
||||
TG.posli_zpravu(f"⚠ RČ {rc} není v Medeviu — nezakládám. Zkus jiné RČ.")
|
||||
return
|
||||
uuid_, jmeno, prijmeni = info[0], info[1], info[2]
|
||||
try:
|
||||
res = MED.zaloz_pozadavek_recept(
|
||||
uuid_, rec.get("leky_str", ""), rec.get("pozn_str", "")
|
||||
)
|
||||
except Exception as e:
|
||||
TG.posli_zpravu(f"❌ Chyba při zakládání: {type(e).__name__}: {e}")
|
||||
return
|
||||
PEND.aktualizuj(rec["id"], stav="zalozeno",
|
||||
vysledek={"request_id": res["request_id"], "rc": rc,
|
||||
"pacient": f"{prijmeni} {jmeno}"})
|
||||
try:
|
||||
graph_mail.add_category(MAILBOX, rec["email_message_id"], PROCESSED_CATEGORY)
|
||||
except Exception as e:
|
||||
log(f"[mail označení] {type(e).__name__}: {e}")
|
||||
TG.posli_zpravu(f"✅ Založeno: {prijmeni} {jmeno} (RČ {rc}) — "
|
||||
f"{rec.get('leky_str', '')}")
|
||||
log(f"založeno {res['request_id']} pro {prijmeni} {jmeno}")
|
||||
|
||||
|
||||
def zpracuj_odpoved(u: dict) -> None:
|
||||
"""Zpracuje jednu příchozí Telegram zprávu."""
|
||||
rid = u.get("reply_to_message_id")
|
||||
rec = PEND.najdi_dle_otazky(rid) if rid else None
|
||||
|
||||
if rec is None:
|
||||
cekaji = PEND.cekajici()
|
||||
if len(cekaji) == 1:
|
||||
rec = cekaji[0] # jediný čekající → ber to na něj
|
||||
else:
|
||||
if cekaji:
|
||||
TG.posli_zpravu("Odpověz prosím jako reply na konkrétní dotaz "
|
||||
"(čeká jich víc).")
|
||||
return
|
||||
|
||||
if rec.get("stav") != "ceka":
|
||||
return
|
||||
|
||||
d = DLG.parse_odpoved(u.get("text", ""))
|
||||
if d["akce"] == "preskoc":
|
||||
PEND.aktualizuj(rec["id"], stav="preskoceno")
|
||||
TG.posli_zpravu("OK, nezakládám.")
|
||||
elif d["akce"] == "rc":
|
||||
_zaloz_pro_rc(rec, d["rc"])
|
||||
elif d["akce"] == "kandidat":
|
||||
kand = rec.get("kandidati") or []
|
||||
i = d["index"] - 1
|
||||
if 0 <= i < len(kand):
|
||||
_zaloz_pro_rc(rec, kand[i].get("rc", ""))
|
||||
else:
|
||||
TG.posli_zpravu(f"Kandidát {d['index']} neexistuje (mám {len(kand)}).")
|
||||
else:
|
||||
TG.posli_zpravu("Nerozumím. Pošli RČ pacienta, číslo kandidáta, nebo „ne“.")
|
||||
|
||||
|
||||
def smycka(poll_s: int = 5) -> None:
|
||||
try:
|
||||
TG.priprav() # naprimuj entitu Vlada (jinak fresh session spadne)
|
||||
except Exception as e:
|
||||
log(f"[priprav] {type(e).__name__}: {e}")
|
||||
since = _load_since()
|
||||
if since is None:
|
||||
# první start — vezmi aktuální stav jako základ, starou historii ignoruj
|
||||
since = TG.baseline_since()
|
||||
_save_since(since)
|
||||
log(f"baseline since_id={since}")
|
||||
log("Resolver běží (Ctrl+C ukončí).")
|
||||
while True:
|
||||
try:
|
||||
posli_nove_otazky()
|
||||
nove, since = TG.nacti_odpovedi(since)
|
||||
for u in nove:
|
||||
zpracuj_odpoved(u)
|
||||
_save_since(since)
|
||||
except KeyboardInterrupt:
|
||||
log("Konec.")
|
||||
break
|
||||
except Exception as e:
|
||||
log(f"[smyčka] {type(e).__name__}: {e}")
|
||||
time.sleep(poll_s)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
smycka()
|
||||
Reference in New Issue
Block a user