This commit is contained in:
2026-04-21 09:44:33 +02:00
parent 9d5e20676b
commit 509ebd1ac4
7 changed files with 375 additions and 38 deletions
+109 -38
View File
@@ -25,11 +25,15 @@ if sys.platform == "win32":
import anthropic
from pdf2image import convert_from_path
sys.path.insert(0, str(Path(__file__).parent.parent))
from Knihovny.najdi_dropbox import get_dropbox_root
POPPLER_PATH = r"C:/Poppler/Library/bin"
CORRECTIONS_FILE = Path(__file__).parent / "corrections.json"
TO_PROCESS = Path(__file__).parent / "ToProcess"
PROCESSED = Path(__file__).parent / "Processed"
DOKUMENTACE = Path(r"U:\Dropbox\Ordinace\Dokumentace_zpracovaná")
_DROPBOX = Path(get_dropbox_root())
TO_PROCESS = _DROPBOX / r"Ordinace\Dokumentace_ke_zpracování\Ricoh Fi-8040\KeZpracování"
PROCESSED = _DROPBOX / r"Ordinace\Dokumentace_ke_zpracová\Ricoh Fi-8040\Zpracováno"
DOKUMENTACE = _DROPBOX / r"Ordinace\Dokumentace_zpracovaná"
# ─── Konfigurace ──────────────────────────────────────────────────────────────
@@ -224,8 +228,9 @@ def extract_patient_info(pdf_path: str) -> dict:
"- \"jmeno\": celé jméno pacienta (příjmení + jméno + případný titul)\n"
"- \"rodne_cislo\": rodné číslo pacienta BEZ lomítka (pouze číslice)\n"
"- \"datum_zpravy\": datum zprávy ve formátu YYYY-MM-DD\n"
"- \"typ_dokumentu\": typ dokumentu — pokud je to lékařská/ambulantní/propouštěcí zpráva, "
"použij \"LZ {oddělení}\" (např. \"LZ chirurgie\", \"LZ kardiologie\", \"LZ plicní\", \"LZ ORL\"). "
"- \"typ_dokumentu\": typ dokumentu — "
"\"LZ {oddělení}\" = ambulantní/lékařská zpráva (např. \"LZ chirurgie\", \"LZ kardiologie\", \"LZ plicní\", \"LZ ORL\"); "
"\"PZ {oddělení}\" = propouštěcí zpráva z hospitalizace (např. \"PZ interna\", \"PZ neurologie\"). "
"Jiné typy: \"Laboratoř\", \"CT břicha\", \"MRI páteře\", \"kolonoskopie\", "
"\"operační protokol oční\", \"poukaz FT\", \"diagnostická mamografie\" atd.\n"
"- \"poznamka\": krátká klinická poznámka česky, max 80 znaků\n"
@@ -273,6 +278,75 @@ def extract_patient_info(pdf_path: str) -> dict:
def sanitize_filename(name: str) -> str:
return re.sub(r'[<>:"/\\|?*]', '', name)
def _rename_dialog(nazev: str, info_lines: list[str]) -> str | None:
"""
Tkinter dialog pro schválení / opravu názvu souboru.
Vrátí finální název (s .pdf) nebo None = přeskočit.
"""
import tkinter as tk
result = {"value": None}
root = tk.Tk()
root.tk.call("encoding", "system", "utf-8")
root.title("Schválení názvu souboru")
root.resizable(True, False)
root.attributes("-topmost", True)
pad = {"padx": 12, "pady": 6}
# Informační sekce
frame_info = tk.Frame(root, bg="#f0f0f0", bd=1, relief="sunken")
frame_info.pack(fill="x", **pad)
for line in info_lines:
color = "#b00000" if line.startswith("") else "#004080" if line.startswith("") else "#333"
tk.Label(frame_info, text=line, anchor="w", bg="#f0f0f0",
fg=color, font=("Segoe UI", 10)).pack(fill="x", padx=8, pady=1)
# Pole pro název (bez .pdf)
tk.Label(root, text="Název souboru (bez .pdf):", anchor="w",
font=("Segoe UI", 9, "bold")).pack(fill="x", padx=12, pady=(10, 2))
nazev_bez = nazev[:-4] if nazev and nazev.endswith(".pdf") else (nazev or "")
var = tk.StringVar(value=nazev_bez)
entry = tk.Entry(root, textvariable=var, font=("Segoe UI", 10), width=90)
entry.pack(fill="x", padx=12, pady=(0, 10))
entry.icursor(tk.END)
entry.focus_set()
# Tlačítka
frame_btn = tk.Frame(root)
frame_btn.pack(pady=(0, 12))
def schvalit(event=None):
result["value"] = var.get().strip()
root.destroy()
def preskocit(event=None):
result["value"] = None
root.destroy()
tk.Button(frame_btn, text="✓ Schválit (Enter)", command=schvalit,
bg="#2a7a2a", fg="white", font=("Segoe UI", 10, "bold"),
padx=16, pady=6).pack(side="left", padx=8)
tk.Button(frame_btn, text="✗ Přeskočit (Esc)", command=preskocit,
bg="#7a2a2a", fg="white", font=("Segoe UI", 10),
padx=16, pady=6).pack(side="left", padx=8)
root.bind("<Return>", schvalit)
root.bind("<Escape>", preskocit)
# Vystředit okno na obrazovce
root.update_idletasks()
w, h = root.winfo_width(), root.winfo_height()
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry(f"+{(sw - w) // 2}+{(sh - h) // 2}")
root.mainloop()
return result["value"]
def print_verification(verif: dict, rc_from_scan: str):
"""Vypíše výsledek ověření proti Medicus."""
status = verif["status"]
@@ -292,67 +366,64 @@ def print_verification(verif: dict, rc_from_scan: str):
elif status == "offline":
print(f" — Medicus: nedostupný (offline), ověření přeskočeno")
def interactive_rename(pdf_path: Path, info: dict, verif: dict) -> bool:
"""
Zobrazí výsledek ověření a navržený název, umožní schválení nebo opravu.
Otevře tkinter dialog pro schválení / opravu názvu.
Schválený soubor přesune do Processed/ a smaže z ToProcess/.
"""
# Kontrola duplicit v Dokumentace_zpracovaná
rc = re.sub(r"\D", "", verif["patient"]["rodcis"] if verif.get("patient") else info.get("rodne_cislo") or "")
datum = info.get("datum_zpravy") or ""
duplicity = check_duplicates(rc, datum)
if duplicity:
print()
print(f" ⚠ DUPLICITA — v Dokumentace_zpracovaná již existuje stejný pacient + datum:")
for d in duplicity:
print(f" · {d}")
# Pokud fuzzy match opravil RČ, aktualizuj navržený název souboru
# Oprava RČ při fuzzy matchi
nazev = info.get("nazev_souboru")
if verif["status"] == "fuzzy" and verif.get("rc_corrected") and nazev:
rc_scan = re.sub(r"\D", "", info.get("rodne_cislo") or "")
nazev = nazev.replace(rc_scan, verif["rc_corrected"], 1)
print(f" → Název aktualizován s opraveným RČ")
# Sestavení info řádků pro dialog
rc_from_scan = re.sub(r"\D", "", info.get("rodne_cislo") or "")
status = verif["status"]
patient = verif.get("patient")
info_lines = []
if status == "ok":
info_lines.append(f"✓ Medicus: {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}")
elif status == "fuzzy":
info_lines.append(f"⚠ RČ ze skenu '{rc_from_scan}' → opraveno na {verif['rc_corrected']}")
info_lines.append(f" Pacient: {patient['prijmeni']} {patient['jmeno']} | RČ {patient['rodcis']}")
elif status == "not_found":
info_lines.append(f"✗ RČ '{rc_from_scan}' nenalezeno v Medicus")
else:
info_lines.append("— Medicus nedostupný (offline)")
if duplicity:
info_lines.append(f"⚠ DUPLICITA: {', '.join(duplicity)}")
print()
print("" * 70)
if nazev:
print(f" Navržený název: {nazev}")
else:
print(" Nepodařilo se vygenerovat název souboru.")
print(" Otevírám dialog...")
print()
print(" [Enter] = schválit → uložit do Processed a smazat z ToProcess")
print(" [n] = přeskočit")
print(" [text] = zadat správný název (bez .pdf)")
print()
odpoved = _rename_dialog(nazev or "", info_lines)
try:
odpoved = input(" > ").strip()
except (EOFError, KeyboardInterrupt):
print("\nPřerušeno.")
return False
if odpoved.lower() == "n":
if odpoved is None:
print(" Přeskočeno.")
return False
if odpoved == "":
final_name = nazev
else:
if not odpoved.endswith(".pdf"):
odpoved += ".pdf"
final_name = odpoved
if nazev and nazev != final_name:
save_correction(nazev, final_name)
if not odpoved.endswith(".pdf"):
odpoved += ".pdf"
final_name = sanitize_filename(odpoved)
if not final_name:
if nazev and nazev != final_name:
save_correction(nazev, final_name)
if not final_name or final_name == ".pdf":
print(" Název je prázdný, přeskakuji.")
return False
final_name = sanitize_filename(final_name)
dest = PROCESSED / final_name
if dest.exists():
print(f" VAROVÁNÍ: '{final_name}' již existuje v Processed, přeskakuji.")
return False