diff --git a/Medevio/60 ScansProcessing/CLAUDE.md b/Medevio/60 ScansProcessing/CLAUDE.md index 7ae0874..31798e2 100644 --- a/Medevio/60 ScansProcessing/CLAUDE.md +++ b/Medevio/60 ScansProcessing/CLAUDE.md @@ -12,6 +12,7 @@ Spuštění: `python extract_patient_info.py` (bez argumentů = celá složka To 2. Claude Vision API (sonnet-4-6) extrahuje: jméno, RČ, datum, typ dokumentu, poznámku, navržený název, rotaci 3. Ověří pacienta v Medicus Firebird (tabulka KAR, pole RODCIS/PRIJMENI/JMENO) 4. Fuzzy matching RČ při nenalezení: vynechání cifry + záměna podobných (0↔8, 1↔7, 5↔6, 3↔8) + checksum /11 + - Fallback: pokud RČ stále nenalezeno, vyhledá dle příjmení+jméno (z Claude) — status `by_name` / `by_name_multi` 5. Upozorní na duplicitu v `U:\Dropbox\Ordinace\Dokumentace_zpracovaná\` 6. Interaktivní schválení / oprava názvu 7. JPG/PNG → skutečné PDF (správná orientace, DPI=150, quality=80) diff --git a/Medevio/60 ScansProcessing/corrections.json b/Medevio/60 ScansProcessing/corrections.json index cbc390f..4521021 100644 --- a/Medevio/60 ScansProcessing/corrections.json +++ b/Medevio/60 ScansProcessing/corrections.json @@ -1066,5 +1066,69 @@ { "original": "6604011073 2025-12-08 Kramule, Petr [Laboratoř] [stěr/výtěr krk, fyziologická mikrobiota HCD].pdf", "corrected": "6604011073 2025-12-08 Kramule, Petr [Laboratoř] [stěrvýtěr krk, fyziologická mikrobiota HCD].pdf" + }, + { + "original": "8504043768 2026-05-12 Pospíchal, David [LZ praktický lékař] [přeregistrace, výpis z dokumentace, poslední návštěva 226 resp. infekt, elevace CRP].pdf", + "corrected": "8504043768 2026-05-12 Pospíchal, David [LZ praktický lékař] [přeregistrace, výpis z dokumentace, poslední návštěva FEB2026 resp. infekt, elevace CRP].pdf" + }, + { + "original": "496203179 2026-05-11 Netřebská, Blanka [LZ rehabilitace] [vyrozumění o pokračování v řízení, LRP KLP, koxartroza, gonartroza].pdf", + "corrected": "496203179 2026-05-11 Netřebská, Blanka [Schválení lázně OZP] [schválení 21 dní, VII_7, koxartroza, gonartroza].pdf" + }, + { + "original": "460610084 2024-07-30 Baladrán, Antonín [LZ oční] [myopie levis o.u. cum astigmat., presbyopie, cat sen CN o.u., op. kataraktu výhledově].pdf", + "corrected": "460610084 2024-07-30 Baladrán, Antonín [LZ oční] [může řídit s brýlemi, myopie levis o.u. cum astigmat., presbyopie, cat sen CN o.u., op. kataraktu výhledově].pdf" + }, + { + "original": "460610084 2026-01-20 Baladrán, Antonín [LZ urologie] [papilární karcinom L ledviny pT1aN1M0, st.p. NE l.sin. 2022, progrese paraaort. LU vlevo, CT 52026].pdf", + "corrected": "460610084 2026-01-20 Baladrán, Antonín [LZ urologie] [papilární karcinom L ledviny pT1aN1M0, st.p. NE l.sin. 2022, progrese paraaort. LU vlevo, CT MAY2026].pdf" + }, + { + "original": "505805215 2026-04-30 Sedláčková, Vlasta [LZ kardiologie] [st.p. náhradě mitrální chlopně SJM Epic No29, EF LK 55% sy ND NYHA I-II, lehká sekund. trikusp. regurg., PASP 32-37mmHg, paFiS dg. 52023, rivaroxaban].pdf", + "corrected": "505805215 2026-04-30 Sedláčková, Vlasta [LZ kardiologie] [st.p. náhradě mitrální chlopně SJM Epic No29, EF LK 55% sy ND NYHA I-II, lehká sekund. trikusp. regurg., PASP 32-37mmHg, paFiS dg. 52023, rivaroxaban, kontrola +6m].pdf" + }, + { + "original": "510802325 2026-05-11 Simion, Vladimír [LZ oční] [keratokonj. l.utr., vlevo defekt epitelu, susp. expoziční keratopatie, laxita víček].pdf", + "corrected": "510802325 2026-05-11 Simion, Vladimír [LZ oční] [zánět spojivek l.utr., vlevo defekt epitelu, susp. expoziční keratopatie, laxita víček].pdf" + }, + { + "original": "5409194296 2026-05-05 Sklenář, Vladimír [LZ interna] [kontrola, obezita BMI 38.22, DM2, HTN, paFiS, NT-proBNP 551.70, bez efektu Mysimby].pdf", + "corrected": "5409194296 2026-05-05 Sklenář, Vladimír [LZ interna] [kontrola, obezita BMI 38.22, DM2, HTN, paFiS, NT-proBNP 551.70, bez efektu Mysimby, kontrola NOV2026].pdf" + }, + { + "original": "5761140275 2019-09-11 Vrňáková, Jaroslava [LZ kardiologie] [EKG: bez projevů myokard. ischemie či hypertrofie, bez závažných poruch rytmu].pdf", + "corrected": "5761140275 2019-09-11 Vrňáková, Jaroslava [EKG] [EKG bez projevů myokard. ischemie či hypertrofie, bez závažných poruch rytmu].pdf" + }, + { + "original": "5761140275 2016-11-19 Vrňáková, Jaroslava [EKG] [EKG bez přesvědčivých patomorfol. změn, poruchy rytmu ani převodu].pdf", + "corrected": "5761140275 2016-10-19 Vrňáková, Jaroslava [EKG] [EKG bez přesvědčivých patomorfol. změn, poruchy rytmu ani převodu].pdf" + }, + { + "original": "5955100272 2025-04-08 Čulíková, Hana [LZ endokrinologie] [Autoimunitní thyreoiditida, hypotyr., substituce, DXA osteopénie femur/krček/předloktí, dyslipidémie, HTN].pdf", + "corrected": "5955100272 2025-04-08 Čulíková, Hana [LZ endokrinologie] [Autoimunitní thyreoiditida, hypotyr., substituce, DXA osteopénie femurkrčekpředloktí, dyslipidémie, HTN].pdf" + }, + { + "original": "8806100413 2025-12-31 Zbranek, Adam [LZ ortopedie] [st.p. fraktuře diafýz tibie a fibuly vpravo, výkon 23.12., rány klidné].pdf", + "corrected": "8806100413 2025-12-31 Zbranek, Adam [LZ ortopedie] [kontrola, st.p. fraktuře diafýz tibie a fibuly vpravo, výkon 23.12., rány klidné].pdf" + }, + { + "original": "9901040160 2026-05-12 Tvrz, Matěj [Holter TK] [HTN, avg SYS 134/139 den/120 noc, dipper 14%, SYS>140 42% den, 58% noc].pdf", + "corrected": "9901040160 2026-05-12 Tvrz, Matěj [Holter TK] [HTN, avg SYS 134139 den120 noc, dipper 14%, SYS140 42% den, 58% noc].pdf" + }, + { + "original": "460610084 2026-05-12 Baladrán, Antonín [Lékařský posudek řidič] [zdravotně způsobilý s podmínkou sk. B brýle, platnost do 12.05.2028].pdf", + "corrected": "460610084 2026-05-12 Baladrán, Antonín [Posudek ŘP] [schopen B s brýlemi].pdf" + }, + { + "original": "460610084 2026-05-12 Baladrán, Antonín [Posudek ŘP] [schopen B s brýlemi].pdf", + "corrected": "460610084 2026-05-12 Baladrán, Antonín [Prohlášení ŘP] [cítí se na to].pdf" + }, + { + "original": "485507406 2026-05-12 Jourová, Eva [Posudek ŘP] [schopna B].pdf", + "corrected": "485507406 2026-05-12 Jourová, Eva [Posudek ŘP] [schopen bez omezení B].pdf" + }, + { + "original": "485507406 2026-05-12 Jourová, Eva [Prohlášení ŘP] [cítí se zdráva, sk. B, SOS léky po štípnutí hmyzem].pdf", + "corrected": "485507406 2026-05-12 Jourová, Eva [Prohlášení ŘP] [cítí se na to].pdf" } ] \ No newline at end of file diff --git a/Medevio/60 ScansProcessing/extract_patient_info_novy.py b/Medevio/60 ScansProcessing/extract_patient_info_novy.py index 7c15432..3d11f21 100644 --- a/Medevio/60 ScansProcessing/extract_patient_info_novy.py +++ b/Medevio/60 ScansProcessing/extract_patient_info_novy.py @@ -165,6 +165,59 @@ def _rc_checksum_ok(rc: str) -> bool: return int(digits) % 11 == 0 return True +def _parse_jmeno_prijmeni(name_str: str) -> tuple[str, str] | None: + """Parsuje 'Příjmení, Jméno' nebo 'Příjmení Jméno' -> (prijmeni, jmeno).""" + name_str = name_str.strip() + if "," in name_str: + parts = [p.strip() for p in name_str.split(",", 1)] + if len(parts) == 2 and parts[0] and parts[1]: + return parts[0], parts[1] + parts = name_str.split() + if len(parts) >= 2: + return parts[0], " ".join(parts[1:]) + return None + +def _lookup_by_name(cur, prijmeni: str, jmeno: str) -> list[dict]: + """Vyhledá pacienty v KAR podle příjmení a prvního slova jména.""" + jmeno_first = jmeno.split()[0] if jmeno.split() else jmeno + cur.execute( + "SELECT IDPAC, PRIJMENI, JMENO, RODCIS FROM KAR " + "WHERE UPPER(PRIJMENI) = UPPER(?)", + (prijmeni,) + ) + rows = cur.fetchall() + result = [] + for row in rows: + db_jmeno = (row[2] or "").strip().upper() + if db_jmeno.startswith(jmeno_first.upper()): + result.append({ + "idpac": row[0], + "prijmeni": row[1].strip(), + "jmeno": row[2].strip(), + "rodcis": row[3].strip(), + }) + return result + +def verify_patient_by_name(name_str: str) -> dict: + """Vyhledá pacienta v Medicus podle jména — fallback když RČ chybí.""" + parsed = _parse_jmeno_prijmeni(name_str) + if not parsed: + return {"status": "not_found", "patient": None, "rc_corrected": None} + prijmeni, jmeno = parsed + con = _medicus_connect() + if con is None: + return {"status": "offline", "patient": None, "rc_corrected": None} + try: + cur = con.cursor() + matches = _lookup_by_name(cur, prijmeni, jmeno) + if not matches: + return {"status": "not_found", "patient": None, "rc_corrected": None} + if len(matches) == 1: + return {"status": "by_name", "patient": matches[0], "rc_corrected": None} + return {"status": "by_name_multi", "patient": matches[0], "rc_corrected": None, "all_matches": matches} + finally: + con.close() + def verify_patient(rc_raw: str) -> dict: rc = re.sub(r"\D", "", rc_raw or "") if not rc: @@ -570,6 +623,24 @@ def process_file(pdf_path: Path): nazev = nazev.replace(rc_from_scan, verif["rc_corrected"], 1) print(f" → RČ opraveno: {rc_from_scan} → {verif['rc_corrected']}") + # Fallback: RČ nenalezeno → zkus vyhledat podle jména z Claude + if verif["status"] == "not_found" and info.get("jmeno"): + jmeno_z_claude = info["jmeno"] + print(f" RČ nenalezeno, zkouším vyhledat dle jména: {jmeno_z_claude}") + verif_name = verify_patient_by_name(jmeno_z_claude) + if verif_name["status"] in ("by_name", "by_name_multi"): + verif = verif_name + rc_z_medicus = re.sub(r"\D", "", verif["patient"]["rodcis"]) + p = verif["patient"] + print(f" → Nalezeno dle jména: {p['prijmeni']} {p['jmeno']} | RČ {p['rodcis']}") + if verif_name["status"] == "by_name_multi": + print(f" ⚠ Více shod ({len(verif_name['all_matches'])}) — přijat první výsledek") + # Aktualizuj RČ v navrženém názvu + if nazev and rc_z_medicus: + nazev = re.sub(r"^null\s*", rc_z_medicus + " ", nazev) + if not nazev.startswith(rc_z_medicus): + nazev = re.sub(r"^\S+\s*", rc_z_medicus + " ", nazev) + # Info řádky pro dialog status = verif["status"] patient = verif.get("patient") @@ -583,6 +654,11 @@ def process_file(pdf_path: Path): elif status == "fuzzy": info_lines.append(f"⚠ RČ ze skenu '{rc_ocr}' → opraveno na {verif['rc_corrected']}") info_lines.append(f" Pacient: {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}") + elif status == "by_name": + info_lines.append(f"✓ Nalezeno dle jména: {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}") + elif status == "by_name_multi": + count = len(verif.get("all_matches", [])) + info_lines.append(f"⚠ Nalezeno dle jména ({count} shod, 1. výsledek): {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}") elif status == "not_found": info_lines.append(f"✗ RČ '{rc_ocr}' nenalezeno v Medicus") else: