z230
This commit is contained in:
@@ -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
|
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)
|
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
|
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á\`
|
5. Upozorní na duplicitu v `U:\Dropbox\Ordinace\Dokumentace_zpracovaná\`
|
||||||
6. Interaktivní schválení / oprava názvu
|
6. Interaktivní schválení / oprava názvu
|
||||||
7. JPG/PNG → skutečné PDF (správná orientace, DPI=150, quality=80)
|
7. JPG/PNG → skutečné PDF (správná orientace, DPI=150, quality=80)
|
||||||
|
|||||||
@@ -1066,5 +1066,69 @@
|
|||||||
{
|
{
|
||||||
"original": "6604011073 2025-12-08 Kramule, Petr [Laboratoř] [stěr/výtěr krk, fyziologická mikrobiota HCD].pdf",
|
"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"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -165,6 +165,59 @@ def _rc_checksum_ok(rc: str) -> bool:
|
|||||||
return int(digits) % 11 == 0
|
return int(digits) % 11 == 0
|
||||||
return True
|
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:
|
def verify_patient(rc_raw: str) -> dict:
|
||||||
rc = re.sub(r"\D", "", rc_raw or "")
|
rc = re.sub(r"\D", "", rc_raw or "")
|
||||||
if not rc:
|
if not rc:
|
||||||
@@ -570,6 +623,24 @@ def process_file(pdf_path: Path):
|
|||||||
nazev = nazev.replace(rc_from_scan, verif["rc_corrected"], 1)
|
nazev = nazev.replace(rc_from_scan, verif["rc_corrected"], 1)
|
||||||
print(f" → RČ opraveno: {rc_from_scan} → {verif['rc_corrected']}")
|
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
|
# Info řádky pro dialog
|
||||||
status = verif["status"]
|
status = verif["status"]
|
||||||
patient = verif.get("patient")
|
patient = verif.get("patient")
|
||||||
@@ -583,6 +654,11 @@ def process_file(pdf_path: Path):
|
|||||||
elif status == "fuzzy":
|
elif status == "fuzzy":
|
||||||
info_lines.append(f"⚠ RČ ze skenu '{rc_ocr}' → opraveno na {verif['rc_corrected']}")
|
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']}")
|
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":
|
elif status == "not_found":
|
||||||
info_lines.append(f"✗ RČ '{rc_ocr}' nenalezeno v Medicus")
|
info_lines.append(f"✗ RČ '{rc_ocr}' nenalezeno v Medicus")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user