diff --git a/Medevio/60 ScansProcessing/corrections.json b/Medevio/60 ScansProcessing/corrections.json index 75d6ee8..cd74962 100644 --- a/Medevio/60 ScansProcessing/corrections.json +++ b/Medevio/60 ScansProcessing/corrections.json @@ -710,5 +710,53 @@ { "original": "8908180402 2026-03-05 Tůma, Patrik [Žádanka IPZS] [žádanka o vyšetření zdrav. stavu, invalidita kontrolní, 517 Kč].pdf", "corrected": "8908180402 2026-03-05 Tůma, Patrik [Žádanka IPZS] [žádanka o vyšetření zdrav. stavu, invalidita, cílené, 517 Kč].pdf" + }, + { + "original": "400424003 2026-04-26 Faměra, Jiří [LZ interna] [86l, celk. zhoršení, kašel, perimaleol. otoky, flutter síní v anamnéze, EKG sinus, RTG hilová hyperemie].pdf", + "corrected": "400424003 2026-04-26 Faměra, Jiří [LZ interna] [přivezen RZZ, 86l, celk. zhoršení, kašel, perimaleol. otoky, flutter síní v anamnéze, EKG sinus, RTG hilová hyperemie].pdf" + }, + { + "original": "415716459 2026-04-29 Kekrtová, Jarmila [Laboratoř] [dg. N394, D-dimery 6.99 mg/l FEU (norma 0.00-0.50), hlášeno].pdf", + "corrected": "415716459 2026-04-29 Kekrtová, Jarmila [Laboratoř] [dg. N394, D-dimery 6.99 mgl FEU (norma 0.00-0.50), hlášeno].pdf" + }, + { + "original": "435720013 2026-04-29 Lišková, Jaroslava [Laboratoř] [dg. N309, glukóza 3 (↑), leukocyty 1 (↑), leukocyty sediment 37/ul (norma 0-10)].pdf", + "corrected": "435720013 2026-04-29 Lišková, Jaroslava [Laboratoř] [dg. N309, U_glukóza 3 (↑), U_leukocyty 1 (↑), U_leukocyty sediment 37ul (norma 0-10)].pdf" + }, + { + "original": "436114002 2026-04-22 Petrovská, Eliška [diagnostická mamografie] [BI-RADS kat.1, normální nález, typ žlázy BI-RADS B tukově žlázový].pdf", + "corrected": "436114002 2026-04-22 Petrovská, Eliška [mamografie] [BIRADS kat.1, normální nález, typ žlázy BIRADS B tukově žlázový].pdf" + }, + { + "original": "475727064 2026-04-08 Povolná, Věra [IADL test] [70 bodů – částečná nesoběstačnost v aktivitách denního života].pdf", + "corrected": "475727064 2026-04-08 Povolná, Věra [IADL test] [50 bodů – částečná nesoběstačnost v aktivitách denního života].pdf" + }, + { + "original": "475727064 2026-04-06 Povolná, Věra [Barthelův test ADL] [100 bodů – nezávislý].pdf", + "corrected": "475727064 2026-04-30 Povolná, Věra [Barthelův test ADL] [100 bodů – nezávislý].pdf" + }, + { + "original": "511212227 2026-04-30 Klimeš, Radko [LZ oční] [dg. H400, V PO 5/7.5, V LO +0.5 5/7.5, Tn PO 18.7 LO 22.7 mmHg, schopen řídit bez brýlí].pdf", + "corrected": "511212227 2026-04-30 Klimeš, Radko [LZ oční] [dg. H400, V PO 57.5, V LO +0.5 57.5, Tn PO 18.7 LO 22.7 mmHg, schopen řídit bez brýlí].pdf" + }, + { + "original": "5657111867 2026-04-29 Kocumová, Zdeňka [Laboratoř] [cholesterol 5.40 (↑), MCV 98.9 (↑), MCH 34.1 (↑), U_hustota 1008 (↓)].pdf", + "corrected": "5657111867 2026-04-29 Kocumová, Zdeňka [Laboratoř] [Z000, cholesterol 5.40 (↑), MCV 98.9 (↑), MCH 34.1 (↑), U_hustota 1008 (↓)].pdf" + }, + { + "original": "5962050149 2026-04-30 Jelínková, Eva [měření TK] [měření TK ráno i večer, hodnoty 108-133/61-76, 1 tableta 1-0-0].pdf", + "corrected": "5962050149 2026-04-30 Jelínková, Eva [domácí měření TK] [měření TK ráno i večer, hodnoty 108-13361-76, pěkně korigovaný TK, 1 tableta 1-0-0].pdf" + }, + { + "original": "7602044780 2026-04-30 Suchý, Vladimír [PZ nefrologie] [SLE se sek. APS, AKI, proliferativní GN, ATN, po 1.+2. cyklu CFA Eurolupus, renální biopsie].pdf", + "corrected": "7602044780 2026-04-30 Suchý, Vladimír [LZ nefrologie] [SLE se sek. APS, AKI, proliferativní GN, ATN, po 1.+2. cyklu CFA Eurolupus, renální biopsie].pdf" + }, + { + "original": "9705081617 Krob, Milan split_005.pdf", + "corrected": "9705081617 Krob, Milan [EKG] [normální křivka].pdf" + }, + { + "original": "9705081617 null Krob, Milan [PZ pediatrie] [prematuritas gravis, dystrofie, psychomotorická retardace, susp. autistické rysy, ptosa, strabismus, amblyopie, tarsektomie l.dx].pdf", + "corrected": "9705081617 2002-04-26 Krob, Milan [LZ pediatrie] [prematuritas gravis, dystrofie, psychomotorická retardace, susp. autistické rysy, ptosa, strabismus, amblyopie, tarsektomie l.dx].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 6b243ff..4ff5105 100644 --- a/Medevio/60 ScansProcessing/extract_patient_info_novy.py +++ b/Medevio/60 ScansProcessing/extract_patient_info_novy.py @@ -231,7 +231,7 @@ def build_corrections_prompt() -> str: # ─── Claude Vision API ──────────────────────────────────────────────────────── -def extract_info(pdf_path: Path) -> dict: +def extract_info(pdf_path: Path, known_patient: str | None = None, known_rc: str | None = None) -> dict: print(" Převádím na obrázek...") suffix = pdf_path.suffix.lower() if suffix in (".jpg", ".jpeg", ".png"): @@ -248,9 +248,27 @@ def extract_info(pdf_path: Path) -> dict: gc.collect() image_b64 = base64.standard_b64encode(buf.getvalue()).decode("utf-8") + if known_patient and known_rc: + # Identita pacienta je známa z názvu souboru — Claude se soustředí jen na obsah zprávy + patient_hint = ( + f"Pacient je již znám: RČ={known_rc}, jméno={known_patient}. " + f"Pole \"jmeno\" nastav na \"{known_patient}\" a \"rodne_cislo\" na \"{known_rc}\". " + f"Soustřeď se hlavně na datum zprávy, typ dokumentu a klinickou poznámku.\n" + ) + nazev_format = ( + f"\"{known_rc} {{datum_zpravy}} {known_patient} [{{typ_dokumentu}}] [{{poznamka}}].pdf\"" + ) + else: + patient_hint = "" + nazev_format = ( + "\"{rodne_cislo} {datum_zpravy} {Příjmení}, {Jméno} [{typ_dokumentu}] [{poznamka}].pdf\" " + "(jméno bez titulu, RČ bez lomítka)" + ) + prompt = ( load_naming_rules() + build_corrections_prompt() + + patient_hint + "Toto je naskenovaná lékařská zpráva v češtině. " "Vrať JSON s těmito poli:\n" "- \"jmeno\": celé jméno pacienta (příjmení + jméno + případný titul)\n" @@ -265,9 +283,7 @@ def extract_info(pdf_path: Path) -> dict: "DŮLEŽITÉ: pokud zpráva obsahuje sekci \"Závěr:\" nebo \"Závěr vyšetření:\", " "použij VÝHRADNĚ obsah této sekce — je nejdůležitější. " "Teprve pokud závěr chybí, shrň obsah z celé zprávy.\n" - "- \"nazev_souboru\": název souboru ve formátu " - "\"{rodne_cislo} {datum_zpravy} {Příjmení}, {Jméno} [{typ_dokumentu}] [{poznamka}].pdf\" " - "(jméno bez titulu, RČ bez lomítka)\n" + f"- \"nazev_souboru\": název souboru ve formátu {nazev_format}\n" "- \"rotace\": o kolik stupňů CCW je třeba otočit obrázek aby byl text čitelně na výšku nebo šířku " "(hodnoty: 0, 90, 180, 270). Pokud je text již správně orientovaný, vrať 0.\n\n" "Pokud pole nenajdeš, použij null. Nepiš nic jiného než JSON." @@ -357,6 +373,19 @@ def run_variant_picker(variants_data: list) -> str | None: return json.loads(out).get("chosen") if out else None +# ─── Detekce split názvu ────────────────────────────────────────────────────── + +# Vzor: "7952090443 Kalousová, Eva split_001.pdf" +_SPLIT_RE = re.compile(r"^(\d{9,10})\s+(.+?)\s+split_\d+\.pdf$", re.IGNORECASE) + +def _parse_split_filename(name: str) -> tuple[str, str] | None: + """Vrátí (rc_digits, 'Příjmení, Jméno') nebo None.""" + m = _SPLIT_RE.match(name) + if m: + return m.group(1), m.group(2) + return None + + # ─── Hlavní flow ────────────────────────────────────────────────────────────── def process_file(pdf_path: Path): @@ -369,17 +398,27 @@ def process_file(pdf_path: Path): preview, geom_file = open_preview(pdf_path) below_y = read_preview_bottom(geom_file) - # 2. Claude Vision API - info = extract_info(pdf_path) - nazev = info.get("nazev_souboru") or pdf_path.name + # 2. Zjisti RČ a jméno — buď z názvu (split soubor) nebo přes Claude Vision API + split = _parse_split_filename(pdf_path.name) + if split: + rc_from_scan, name_from_filename = split + print(f" Split soubor — RČ z názvu: {rc_from_scan}, jméno: {name_from_filename}") + # Claude stále voláme, ale předáme mu identitu pacienta — ať se soustředí na obsah + info = extract_info(pdf_path, known_patient=name_from_filename, known_rc=rc_from_scan) + # RC a jméno bereme z názvu souboru, ne z Claudovy odpovědi + nazev = info.get("nazev_souboru") or pdf_path.name + nazev = re.sub(r"^\d{9,10}\s+", f"{rc_from_scan} ", nazev) # přepiš RC v názvu naším + else: + info = extract_info(pdf_path) + nazev = info.get("nazev_souboru") or pdf_path.name + rc_from_scan = re.sub(r"\D", "", info.get("rodne_cislo") or "") # 3. Medicus ověření + fuzzy matching RČ - rc_from_scan = re.sub(r"\D", "", info.get("rodne_cislo") or "") print(f" Ověřuji v Medicus (RČ: {rc_from_scan})...") verif = verify_patient(rc_from_scan) - # Oprava RČ při fuzzy matchi - if verif["status"] == "fuzzy" and verif.get("rc_corrected") and nazev: + # Oprava RČ při fuzzy matchi (jen pro nesplit soubory — u split máme RC spolehlivé) + if not split and verif["status"] == "fuzzy" and verif.get("rc_corrected") and nazev: nazev = nazev.replace(rc_from_scan, verif["rc_corrected"], 1) print(f" → RČ opraveno: {rc_from_scan} → {verif['rc_corrected']}") @@ -387,6 +426,8 @@ def process_file(pdf_path: Path): status = verif["status"] patient = verif.get("patient") info_lines = [] + if split: + info_lines.append(f"⚡ Split soubor — identita z názvu: {name_from_filename} | RČ {rc_from_scan}") if status == "ok": info_lines.append(f"✓ Medicus: {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}") elif status == "fuzzy": diff --git a/Medevio/60 ScansProcessing/naming_rules.md b/Medevio/60 ScansProcessing/naming_rules.md index 42f785f..785a8f0 100644 --- a/Medevio/60 ScansProcessing/naming_rules.md +++ b/Medevio/60 ScansProcessing/naming_rules.md @@ -12,7 +12,7 @@ Tato pravidla platí vždy při generování polí `poznamka` a `nazev_souboru`. - Pokud je datum přijetí a propuštění ve stejném měsíci, stačí: `[12–15APR2026 ...]` - Pokud datum hospitalizace nelze určit, druhou závorku napiš bez datumu. -3. Když je dokument typ "Laboratoř", do `poznamka` uváděj POUZE hodnoty mimo normu (patologické nálezy) — hodnoty v normě vynech. Osmolalitu séra nikdy nezmiňuj, ani když je mimo normu. +3. Když je dokument typ "Laboratoř", do `poznamka` uváděj POUZE hodnoty mimo normu (patologické nálezy) — hodnoty v normě vynech. **Osmolalitu séra (Osmolalita, Osm, osmolality) NIKDY nezmiňuj — ani když je mimo normu, ani v jakékoli zkratce.** Toto je absolutní výjimka: osmolalita se do názvu souboru ani do poznámky nepíše nikdy za žádných okolností. Chybně: `C_Osmolalita 293 (↑)` — správně: tuto hodnotu zcela vynech. 4. Pokud laboratorní výsledky obsahují glomerulární filtraci — bývá označena jako eGFR, CKD-EPI nebo CK-EPI — do `poznamka` nikdy nepiš číselnou hodnotu eGFR. Místo toho uveď pouze klasifikaci: eGFR ≥ 90 → CHRIG1, 60–89 → CHRIG2, 45–59 → CHRIG3a, 30–44 → CHRIG3b, 15–29 → CHRIG4, < 15 → CHRIG5. Klasifikaci uváděj pouze pokud je CHRIG2 nebo horší (tj. eGFR < 90) — CHRIG1 je v normě, nezmiňuj ho. 5. Když je dokument typ "Laboratoř" a zpráva obsahuje diagnózu (dg., dg:, diagnóza), umísti ji do `nazev_souboru` jako první část druhé závorky, tedy: `[Laboratoř] [dg. XY00 - stručná poznamka]`. 6. Zkratky a pojmenování: slovo „sono" (sonografie/ultrazvuk) piš vždy malými písmeny — `sono břicha`, `sono ŠŽ`, nikoli `SONO`. Štítnou žlázu označuj vždy zkratkou `ŠŽ`. Sonografii prsu/prsů (sono mamm., sono mamografie, sono mamma apod.) piš vždy jako `sono prsů`. Denzitometrii (DEXA, DXA, denzitometrie) piš vždy pouze jako `[DXA]` — bez prefixu LZ. Algologii piš vždy jako `[LZ léčba bolesti]`. Dermatovenerologii (dermatologie, dermatovenerologie, kožní) piš vždy jako `[LZ kožní]`. Angiologii piš vždy jako `[LZ cévní]`.