This commit is contained in:
2026-06-05 14:12:02 +02:00
parent 76e9427901
commit 592e6cd2a2
8 changed files with 2409 additions and 161 deletions
+1
View File
@@ -0,0 +1 @@
OPENAI_API_KEY=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
+50
View File
@@ -0,0 +1,50 @@
# OrdinaceProjekt
## DŮLEŽITÉ — pracovní adresář
Hlavní projekt je **adresář obsahující tento soubor AGENTS.md** (kořen projektu OrdinaceProjekt).
Výsledné soubory (skripty, knihovny, data) vždy ukládej do tohoto kořenového adresáře nebo jeho podadresářů.
Worktree (`.Codex/worktrees/*`) slouží jen pro interní práci Codex, ne jako výstup.
## Přečti na začátku každé konverzace
Každý adresář se skriptem má vlastní `NOTES.md` s technickými detaily. Přečti relevantní NOTES.md podle toho, čeho se konverzace týká.
## Anthropic API klíč
Uložen v `Medevio/.env` jako `ANTHROPIC_API_KEY=sk-ant-...`.
Skripty, které volají Codex API, si ho načítají samy — vzor:
```python
def _load_env():
env_path = Path(__file__).resolve().parent.parent / "Medevio" / ".env"
if env_path.exists():
for line in env_path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if "=" in line and not line.startswith("#"):
k, v = line.split("=", 1)
os.environ[k.strip()] = v.strip()
_load_env()
```
## Sdílené knihovny (`Knihovny/`)
Před psaním nového kódu vždy zkontroluj, zda existuje vhodná sdílená funkce.
Import vždy přes `sys.path` na kořen projektu nebo přímou cestou.
| Modul | Klíčová funkce / třída | Popis |
|-------|------------------------|-------|
| `najdi_dropbox.py` | `get_dropbox_root() → str` | Zjistí cestu k Dropboxu z registru nebo info.json — **používej místo pevných cest** |
| `EmailMessagingGraph.py` | — | Odesílání e-mailů přes Microsoft Graph API |
| `mysql_db.py` | — | Připojení a operace s MySQL databází |
| `medicus_db.py` | — | Připojení k databázi Medicus (Firebird) |
| `vzpb2b_client.py` | — | Klient pro VZP B2B API (stav pojištění) |
## Přehled skriptů
| Skript | Adresář | Popis |
|--------|---------|-------|
| `stahni_str8ts.py` | `SběrDatRůzné/DailyStr8ts/` | Stahuje daily Str8ts puzzle jako PDF, odesílá emailem — viz [NOTES.md](SběrDatRůzné/DailyStr8ts/NOTES.md) |
| `10_StahnoutXML.py`, `11_ParseXML.py` | `Recepty/NačteníPředpisuWithClaude/` | Pipeline pro stahování detailů receptů z eRecept SÚKL — viz [NacistPredpis_DOKUMENTACE.md](Recepty/NačteníPředpisuWithClaude/NacistPredpis_DOKUMENTACE.md) |
+377
View File
@@ -0,0 +1,377 @@
# FakturyRename.py
# Verze: 1.2
# Datum: 05JUN2026
# Autor: Vladimír Buzalka
#
# Popis:
# Projde PDF faktury a doklady přímo ve vstupním adresáři, pošle je do
# OpenAI Responses API k vytěžení údajů a navrhne jednotný název souboru.
# Výsledný formát názvu:
# YYYY-MM-DD Typ Dodavatel ČÍSLO [popis] [částka MĚNA].pdf
#
# Při DRY_RUN = False skript soubor přejmenuje a přesune do podadresáře
# NamedInvoicesbyOpenAI, aby další běh zpracovával jen nové dokumenty.
# Loguje původní název, návrh, tokeny, odhad ceny a stav zpracování.
import os
from dotenv import load_dotenv
import base64
import json
import re
import time
from pathlib import Path
from openai import OpenAI
# =========================
# CENA API
# =========================
USD_TO_CZK = 25.0
# # Ceny nastav ručně podle modelu, který používáš.
# # Zde počítáme:
# # input = 5 USD / 1M tokenů
# # output = 30 USD / 1M tokenů
# PRICE_INPUT_USD_PER_1M = 5.00
# PRICE_OUTPUT_USD_PER_1M = 30.00
# # Model s podporou PDF / vision vstupu.
# MODEL = "gpt-5.5"
MODEL = "gpt-5.4-mini"
PRICE_INPUT_USD_PER_1M = 0.75
PRICE_OUTPUT_USD_PER_1M = 4.50
# =========================
# NASTAVENÍ
# =========================
FOLDER = Path(
r"u:\Dropbox\Ordinace\!!MUDr. Michaela Buzalková s.r.o\Prosek\#040 Faktury přijaté"
)
PROCESSED_FOLDER = FOLDER / "NamedInvoicesbyOpenAI"
# Pro test na 3 fakturách nech DRY_RUN = True.
# Skript jen vypíše a zaloguje návrhy názvů, ale soubory nepřejmenuje.
DRY_RUN = False
# Nepůjde do podadresářů, protože používáme glob(), ne rglob().
PDF_PATTERN = "*.pdf"
LOG_FILE = FOLDER / "_rename_log_invoices.txt"
ENV_FILE = Path(r"U:\ordinaceprojekt\.env")
# =========================
# PRAVIDLA PRO POJMENOVÁNÍ
# =========================
NAMING_RULES = """
Jsi pomocník pro pojmenování naskenovaných PDF dokladů MUDr. Michaely Buzalkové.
ÚKOL:
Z PDF faktury/dokladu vytěž datum, typ dokladu, dodavatele, číslo dokladu, stručný popis, částku a měnu.
Vrať pouze JSON s polem "filename".
CÍLOVÝ FORMÁT:
YYYY-MM-DD Typ Dodavatel ČÍSLO [popis] [částka MĚNA].pdf
PŘÍKLADY:
2026-06-01 Faktura ASKER 261103225 [kontejner Yannick 1.5 l] [339.00 CZK].pdf
2026-06-01 Faktura MEDIPOS 10195703 [CRP, kapiláry, písty, rukavice, nádoba] [5578.97 CZK].pdf
2026-05-29 Faktura Ptáček 202604570 [vakcíny Adacel, Vaqta, Havrix] [9235.20 CZK].pdf
2026-05-29 Faktura Poliklinika Prosek 91260763 [lékárna] [16165.40 CZK].pdf
2026-06-01 Dodací list QuickSeal 200609058 [VivaDiag Hydroxyvitamin D3] [2620.00 CZK].pdf
DŮLEŽITÁ PRAVIDLA:
1. Prefix [POHODA] nikdy nepřidávej.
2. Používej datum vystavení dokladu, ne datum splatnosti.
3. Typ dokladu vyber podle dokumentu:
- Faktura
- Dobropis
- Paragon
- Dodací list
- Zálohová faktura
- Smlouva
- Platba
- Poplatek
- Výdajový pokladní doklad
4. Pokud je v dokumentu napsáno "Dodací list není daňový doklad - nehraďte", typ musí být "Dodací list", ne "Faktura".
5. Dodavatel zapisuj krátce a konzistentně:
- MEDIPOS
- MEDEVIO
- MEDATRON
- ASKER
- QuickSeal
- Poliklinika Prosek
- Alza
- Microsoft
- OpenAI
- Ptáček
6. SPECIÁLNÍ PRAVIDLO: pokud je dodavatel/firma "Distribuce CZ", v názvu souboru použij dodavatele "Ptáček".
7. SPECIÁLNÍ PRAVIDLO: u faktur MEDIPOS použij jako číslo dokladu variabilní symbol nebo hlavní číslo faktury bez mezer, například 10195703. Nepoužívej interní evidenční číslo typu FV-5703/2026.
8. Částku piš vždy s desetinnou tečkou a měnou, například [5578.97 CZK].
9. Když je částka v Kč, měna je CZK.
10. Popis drž krátký, praktický a česky.
11. Popis dávej do hranatých závorek.
12. Nepoužívej dvojtečky, lomítka, uvozovky ani znaky nevhodné pro Windows názvy souborů.
13. Pokud jde jen o dodací list bez daňového dokladu, částku můžeš uvést, ale typ musí zůstat Dodací list.
14. Pokud si nejsi jistý popisem, použij obecný popis typu [materiál do ordinace], [lékárna], [vakcíny], [testy].
15. Výstup musí být pouze validní JSON, nic jiného.
JSON FORMÁT:
{
"filename": "YYYY-MM-DD Faktura Dodavatel 123456 [popis] [123.45 CZK].pdf"
}
"""
# =========================
# POMOCNÉ FUNKCE
# =========================
def pdf_to_base64_data_url(path: Path) -> str:
data = path.read_bytes()
b64 = base64.b64encode(data).decode("utf-8")
return f"data:application/pdf;base64,{b64}"
def sanitize_windows_filename(name: str) -> str:
"""
Očistí název souboru pro Windows.
"""
# Zakázané znaky ve Windows: < > : " / \ | ? *
name = re.sub(r'[<>:"/\\|?*]', " ", name)
# Sjednocení mezer
name = re.sub(r"\s+", " ", name).strip()
# Windows nemá rád tečku nebo mezeru na konci
name = name.rstrip(" .")
if not name.lower().endswith(".pdf"):
name += ".pdf"
return name
def unique_path(target: Path) -> Path:
"""
Pokud cílový soubor existuje, přidá (2), (3), ...
"""
if not target.exists():
return target
stem = target.stem
suffix = target.suffix
parent = target.parent
i = 2
while True:
candidate = parent / f"{stem} ({i}){suffix}"
if not candidate.exists():
return candidate
i += 1
def extract_json_object(text: str) -> dict:
"""
Kdyby model náhodou vrátil něco kolem JSONu, zkusí vytáhnout první JSON objekt.
"""
text = text.strip()
try:
return json.loads(text)
except json.JSONDecodeError:
pass
match = re.search(r"\{.*\}", text, flags=re.DOTALL)
if not match:
raise ValueError(f"Model nevrátil JSON:\n{text}")
return json.loads(match.group(0))
def get_usage_value(usage, key: str) -> int:
"""
Bezpečně přečte usage hodnotu.
Funguje pro objekt i dict.
"""
if usage is None:
return 0
if isinstance(usage, dict):
return usage.get(key, 0) or 0
return getattr(usage, key, 0) or 0
def calculate_cost_from_usage(usage) -> dict:
"""
Spočítá odhad ceny z response.usage.
"""
input_tokens = get_usage_value(usage, "input_tokens")
output_tokens = get_usage_value(usage, "output_tokens")
total_tokens = get_usage_value(usage, "total_tokens")
if not total_tokens:
total_tokens = input_tokens + output_tokens
input_cost_usd = input_tokens / 1_000_000 * PRICE_INPUT_USD_PER_1M
output_cost_usd = output_tokens / 1_000_000 * PRICE_OUTPUT_USD_PER_1M
total_cost_usd = input_cost_usd + output_cost_usd
total_cost_czk = total_cost_usd * USD_TO_CZK
return {
"input_tokens": input_tokens,
"output_tokens": output_tokens,
"total_tokens": total_tokens,
"input_cost_usd": input_cost_usd,
"output_cost_usd": output_cost_usd,
"total_cost_usd": total_cost_usd,
"total_cost_czk": total_cost_czk,
}
def ask_openai_for_filename(client: OpenAI, pdf_path: Path) -> tuple[str, dict]:
file_data = pdf_to_base64_data_url(pdf_path)
response = client.responses.create(
model=MODEL,
input=[
{
"role": "user",
"content": [
{
"type": "input_file",
"filename": pdf_path.name,
"file_data": file_data,
},
{
"type": "input_text",
"text": NAMING_RULES,
},
],
}
],
)
text = response.output_text.strip()
obj = extract_json_object(text)
filename = obj.get("filename", "").strip()
if not filename:
raise ValueError(f"JSON neobsahuje filename:\n{text}")
cost = calculate_cost_from_usage(response.usage)
return sanitize_windows_filename(filename), cost
def log_line(text: str) -> None:
print(text)
with LOG_FILE.open("a", encoding="utf-8") as f:
f.write(text + "\n")
# =========================
# HLAVNÍ BĚH
# =========================
def main() -> None:
if not FOLDER.exists():
raise FileNotFoundError(f"Adresář neexistuje: {FOLDER}")
# Načtení API klíče z .env
load_dotenv(ENV_FILE)
if not os.getenv("OPENAI_API_KEY"):
raise RuntimeError(
f"Chybí OPENAI_API_KEY. Zkontroluj soubor {ENV_FILE}"
)
client = OpenAI()
pdfs = sorted(FOLDER.glob(PDF_PATTERN))
pdfs = [p for p in pdfs if p.is_file() and p.suffix.lower() == ".pdf"]
if not pdfs:
print("Nenalezeno žádné PDF.")
return
total_input_tokens = 0
total_output_tokens = 0
total_tokens = 0
total_cost_usd = 0.0
total_cost_czk = 0.0
log_line("")
log_line("=" * 80)
log_line(f"START: {time.strftime('%Y-%m-%d %H:%M:%S')}")
log_line(f"Adresář: {FOLDER}")
log_line(f"Hotové faktury: {PROCESSED_FOLDER}")
log_line(f"Počet PDF: {len(pdfs)}")
log_line(f"DRY_RUN: {DRY_RUN}")
log_line(f"MODEL: {MODEL}")
log_line(f"Kurz: 1 USD = {USD_TO_CZK:.2f} CZK")
log_line("=" * 80)
for i, pdf in enumerate(pdfs, start=1):
log_line(f"\n[{i}/{len(pdfs)}] Původní název: {pdf.name}")
try:
new_name, cost = ask_openai_for_filename(client, pdf)
total_input_tokens += cost["input_tokens"]
total_output_tokens += cost["output_tokens"]
total_tokens += cost["total_tokens"]
total_cost_usd += cost["total_cost_usd"]
total_cost_czk += cost["total_cost_czk"]
log_line(f" Návrh: {new_name}")
log_line(
f" Tokeny: input={cost['input_tokens']}, "
f"output={cost['output_tokens']}, "
f"total={cost['total_tokens']}"
)
log_line(
f" Cena volání: ${cost['total_cost_usd']:.6f} "
f"{cost['total_cost_czk']:.2f}"
)
target = unique_path(PROCESSED_FOLDER / new_name)
if target.name != new_name:
log_line(f" Cíl po vyřešení konfliktu: {target.name}")
if DRY_RUN:
log_line(f" Cíl: {target}")
log_line(" Stav: DRY-RUN, nepřejmenováno/nepřesunuto")
else:
PROCESSED_FOLDER.mkdir(exist_ok=True)
pdf.rename(target)
if pdf.name == new_name:
log_line(" Stav: PŘESUNUTO")
else:
log_line(" Stav: PŘEJMENOVÁNO A PŘESUNUTO")
except Exception as e:
log_line(f" CHYBA: {type(e).__name__}: {e}")
log_line("")
log_line("=" * 80)
log_line("SOUHRN CENY")
log_line(f"Tokeny celkem: input={total_input_tokens}, output={total_output_tokens}, total={total_tokens}")
log_line(f"Cena celkem: ${total_cost_usd:.6f}{total_cost_czk:.2f}")
log_line("=" * 80)
log_line("\nHOTOVO")
if __name__ == "__main__":
main()
-161
View File
@@ -1,161 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Jednorázový skript: znovu stáhne přílohy pro 1c935d36-c9df-46a1-9ef2-b7f327f376c7 (Šmídová).
Přeskočí přílohy, které jsou již v medevio_downloads. Po úspěchu označí požadavek jako zpracovaný.
"""
import requests
import pymysql
import time
from pathlib import Path
TARGET_REQUEST_ID = "1c935d36-c9df-46a1-9ef2-b7f327f376c7"
RETRY_ATTEMPTS = 5
RETRY_DELAY = 3 # sekund mezi pokusy
TOKEN_PATH = Path(__file__).resolve().parent.parent / "token.txt"
DB_CONFIG = {
"host": "192.168.1.76",
"port": 3306,
"user": "root",
"password": "Vlado9674+",
"database": "medevio",
"charset": "utf8mb4",
"cursorclass": pymysql.cursors.DictCursor,
}
GRAPHQL_QUERY = r"""
query ClinicRequestDetail_GetPatientRequest2($requestId: UUID!) {
patientRequestMedicalRecords: listMedicalRecordsForPatientRequest(
attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT]
patientRequestId: $requestId
pageInfo: {first: 100, offset: 0}
) {
attachmentType
id
medicalRecord {
contentType
description
downloadUrl
id
url
visibleToPatient
}
}
}
"""
def extract_filename_from_url(url: str) -> str:
try:
return url.split("/")[-1].split("?")[0]
except Exception:
return "unknown_filename"
def read_token(p: Path) -> str:
tok = p.read_text(encoding="utf-8").strip()
return tok.split(" ", 1)[1] if tok.startswith("Bearer ") else tok
def download_with_retry(url: str, attempts: int, delay: int) -> bytes:
for attempt in range(1, attempts + 1):
try:
r = requests.get(url, timeout=60)
if r.status_code == 200:
return r.content
print(f" ⚠️ HTTP {r.status_code}, pokus {attempt}/{attempts}")
except Exception as e:
print(f" ⚠️ Chyba stahování (pokus {attempt}/{attempts}): {e}")
if attempt < attempts:
time.sleep(delay)
raise RuntimeError(f"Stahování selhalo po {attempts} pokusech: {url}")
def main():
token = read_token(TOKEN_PATH)
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
conn = pymysql.connect(**DB_CONFIG)
# Načíst již stažené attachment_id pro tento požadavek
with conn.cursor() as cur:
cur.execute("SELECT attachment_id FROM medevio_downloads WHERE request_id = %s", (TARGET_REQUEST_ID,))
existing_ids = {row["attachment_id"] for row in cur.fetchall()}
print(f"🔍 Zpracovávám požadavek {TARGET_REQUEST_ID}")
print(f" Již staženo příloh: {len(existing_ids)}")
# GraphQL dotaz
payload = {
"operationName": "ClinicRequestDetail_GetPatientRequest2",
"query": GRAPHQL_QUERY,
"variables": {"requestId": TARGET_REQUEST_ID},
}
r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
attachments = r.json().get("data", {}).get("patientRequestMedicalRecords", [])
print(f" Nalezeno příloh celkem: {len(attachments)}")
# Načíst createdAt pro INSERT
with conn.cursor() as cur:
cur.execute("SELECT createdAt FROM pozadavky WHERE id = %s", (TARGET_REQUEST_ID,))
row = cur.fetchone()
created_date = row["createdAt"] if row else None
saved = 0
skipped = 0
errors = 0
with conn.cursor() as cur:
for a in attachments:
m = a.get("medicalRecord") or {}
att_id = a.get("id")
if att_id in existing_ids:
print(f" ⏭️ Přeskočeno (již existuje): {att_id}")
skipped += 1
continue
url = m.get("downloadUrl")
if not url:
print(f" ⚠️ Příloha {att_id} nemá downloadUrl, přeskakuji")
skipped += 1
continue
try:
content = download_with_retry(url, RETRY_ATTEMPTS, RETRY_DELAY)
filename = extract_filename_from_url(url)
cur.execute("""
INSERT INTO medevio_downloads (
request_id, attachment_id, attachment_type,
filename, content_type, file_size,
created_at, file_content
) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
""", (TARGET_REQUEST_ID, att_id, a.get("attachmentType"), filename,
m.get("contentType"), len(content), created_date, content))
existing_ids.add(att_id)
print(f" 💾 Uloženo: {filename} ({len(content) / 1024:.1f} kB)")
saved += 1
time.sleep(0.5)
except Exception as e:
print(f" ❌ Chyba: {e}")
errors += 1
conn.commit()
if errors == 0:
with conn.cursor() as cur:
cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (TARGET_REQUEST_ID,))
conn.commit()
print(f"\n✅ Hotovo. Uloženo: {saved}, přeskočeno: {skipped}. Požadavek označen jako zpracovaný.")
else:
print(f"\n⚠️ Hotovo s chybami. Uloženo: {saved}, přeskočeno: {skipped}, chyby: {errors}.")
print(" Požadavek NEBYL označen jako zpracovaný (opakujte po kontrole).")
conn.close()
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
# Pravidla pro přejmenování souborů
Tato pravidla platí vždy při generování polí `poznamka` a `nazev_souboru`.
1. Název souboru má vždy tvar: `RODNECISLO YYYY-MM-DD Příjmení, Jméno [TYP ODBORNOST] [popis].pdf`
- TYP je vždy buď `LZ` (lékařská zpráva / ambulantní zpráva) nebo `PZ` (propouštěcí zpráva z hospitalizace).
- Jiné typy dokumentů (Laboratoř, CT, MRI, kolonoskopie, poukaz FT apod.) nemají TYP prefix — píší se celým názvem: `[Laboratoř]`, `[CT břicha]` atd.
- Příklady: `[LZ chirurgie]`, `[PZ interna]`, `[Laboratoř]`, `[CT břicha]`
2. Když je typ dokumentu PZ (propouštěcí zpráva), umísti do druhé závorky jako první věc data hospitalizace ve tvaru `DDMMMYYYYDDMMMYYYY` (měsíc třemi písmeny anglicky, velká, bez mezer), za pomlčkou pak popis.
- Příklad: `[PZ interna] [1215APR2026 srdeční selhání]`
- Pokud je datum přijetí a propuštění ve stejném měsíci, stačí: `[1215APR2026 ...]`
- 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 (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 dle stadií CHRIG1CHRIG5.
- **Jednotka:** Nejprve zkontroluj jednotku uvedenou v laboratoři:
- Pokud je hodnota v **ml/s** nebo **ml/sec** (typicky malá čísla jako 0.8, 1.14, 1.5…), přenásob ×60 pro převod na ml/min.
- Pokud je hodnota v **ml/min** nebo **ml/min/1.73m²** (typicky velká čísla jako 55, 68, 90…), použij přímo.
- **Klasifikace** (v ml/min/1.73m²): ≥ 90 → CHRIG1, 6089 → CHRIG2, 4559 → CHRIG3a, 3044 → CHRIG3b, 1529 → CHRIG4, < 15 → CHRIG5.
- Prahové hodnoty pro orientaci při jednotce ml/s: ≥ 1.50 → G1, 1.001.49 → G2, 0.750.99 → G3a, 0.500.74 → G3b, 0.250.49 → G4, < 0.25 → G5.
- Klasifikaci uváděj pouze pokud je CHRIG2 nebo horší (tj. eGFR < 90 ml/min nebo < 1.50 ml/s) — 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í]`.
7. V číselných hodnotách VŽDY používej desetinnou tečku, nikoli desetinnou čárku. Toto pravidlo platí absolutně pro všechna čísla v `poznamka` i `nazev_souboru` — např. `TG 4.73`, nikoli `TG 4,73`.
8. Rozpoznávání vzorců — sideropenická anémie: Pokud laboratorní výsledky splňují typický obraz sideropenické (železo-deficitní) anémie, přidej diagnózu jako první část druhé závorky ve tvaru `[sideropenická anémie, ...]`.
Typický obraz (stačí kombinace několika z těchto nálezů):
- Krevní obraz: ↓ Hb, ↓ Htk, ↓ MCV (mikrocytóza), ↓ MCH nebo ↓ MCHC (hypochromie), ↑ RDW (anisocytóza)
- Metabolismus železa: ↓ sérové Fe (železo), ↓ ferritin, ↑ transferrin (nebo TIBC), ↓ saturace transferrinu
- Diagnózu uveď pouze pokud je obraz dostatečně přesvědčivý (alespoň ↓ Hb + ↓ MCV nebo ↓ Fe/ferritin).
- Příklad výsledného názvu: `[Laboratoř] [sideropenická anémie, Hb 98, MCV 71, Fe 5.2]`
9. Jaterní enzymy (ALT, AST, GGT, ALP, LD/LDH) a bilirubin — hodnoty pod dolní hranicí normy (snížené) nezmiňuj v `poznamka` ani v `nazev_souboru`. Uváděj pouze hodnoty nad normu (zvýšené).
10. Druhá závorka pro LZ a PZ — obsah a pořadí: Pro dokumenty typu LZ (lékařská zpráva) a PZ (propouštěcí zpráva) tvoří druhou závorku tyto části v tomto pořadí (oddělené čárkou):
a) **Typ návštěvy** — uveď pouze pokud je explicitně rozpoznatelný ze zprávy:
- `kontrola` — plánovaná kontrola (např. „plánovaná kontrola", „přichází na kontrolu")
- `neplánovaná kontrola` — pokud je výslovně uvedeno, že kontrola nebyla plánovaná
- `akutní` — pacient přichází do akutní ambulance nebo cestou RZS/záchranné služby
- Pokud typ návštěvy není ve zprávě uveden, tuto část zcela vynech (nepsat žádný fallback).
b) **Hlavní diagnóza** — získej z části „Diagnózy", „Závěr" nebo „Dg." — uveď první (hlavní) diagnózu, která je obvykle důvodem návštěvy. Stručně, výstižně.
c) **Termín příští plánované kontroly** — pokud je na konci dokumentu uveden konkrétní plánovaný termín příští kontroly (např. „jaro 2027", „za 3 měsíce", „ročně"), umísti ho jako **poslední část druhé závorky**.
- Uváděj pouze explicitně naplánované termíny — formát: `ko` + termín bez mezery, např. `ko jaro2027`, `ko za6m`, `ko ročně`.
- **Nezahrn** podmíněné návštěvy jako „dle obtíží", „při zhoršení", „při hematurii ihned" apod. — ty jsou samozřejmé a do názvu nepatří.
- Pokud dokument žádný plánovaný termín neobsahuje, tuto část vynech.
- Příklad (s typem návštěvy): `[LZ kardiologie] [kontrola, ICHS, ko za3m]`
- Příklad (bez typu návštěvy): `[LZ neurologie] [migréna, pokračovat v léčbě]`
- Příklad akutní: `[LZ interna] [akutní, dekompenzovaná hypertenze, hospitalizace]`
- Příklad s termínem kontroly: `[LZ urologie] [kontrola, hematurie microsc., angiomyolipoma renis, ko jaro2027]`
- Pro PZ zůstává datum hospitalizace jako první (před typem návštěvy), viz pravidlo 2.
11. Datum v názvu souboru nesmí být v budoucnosti: Pokud datum nalezené na zprávě a navrhované pro název souboru je pozdější než dnešní datum, je to chyba (např. špatně rozpoznané číslo). Hledej na zprávě jiné datum. Pokud žádné vhodné datum nenajdeš, použij dnešní datum.
12. Poukaz domácí péče (DP): Dokument nadepsaný „POUKAZ NA VYŠETŘENÍ / OŠETŘENÍ DP" nebo „poukaz domácí péče" se pojmenovává takto:
- První závorka: vždy `[domácí péče]` (bez prefixu LZ/PZ).
- Datum souboru: pole „Datum" na poukazu (datum vystavení), ve formátu YYYY-MM-DD.
- Druhá závorka obsahuje v tomto pořadí, odděleno čárkou:
a) **Číslo poukazu** — pole „Pořadové číslo poukazu" (celé číslo, např. `1`).
b) **Platnost** — „do DDMMMYYYY" kde datum je z pole „Platnost do" (měsíc třemi velkými písmeny anglicky, bez mezer), např. `do 30JUN2026`.
c) **Výkony** — každý výkon (kód ze sloupce „Požadováno") se uvede jako:
- `{kód} ad hoc` — pokud je u výkonu uvedeno **0x týdně** (bez ohledu na četnost denně); znamená to výkon pouze dle potřeby, ne na pravidelné bázi.
- `{kód} {N}xd{M}xt` — pokud je týdenní četnost M > 0; N = četnost denně, M = četnost týdně. Např. pro 1x denně 3x týdně: `06313 1xd3xt`.
- Příklad (oba výkony ad hoc): `[domácí péče] [1 do 30JUN2026, 06313 ad hoc, 06323 ad hoc]`
- Příklad (pravidelné výkony): `[domácí péče] [2 do 31AUG2026, 06313 1xd5xt, 06321 2xd7xt]`
@@ -1818,5 +1818,69 @@
{ {
"original": "0760245079 2026-06-03 [EKG] [bez hodnocení].pdf", "original": "0760245079 2026-06-03 [EKG] [bez hodnocení].pdf",
"corrected": "0760245079 Ryšavá, Denisa 2026-06-03 [EKG] [bez hodnocení].pdf" "corrected": "0760245079 Ryšavá, Denisa 2026-06-03 [EKG] [bez hodnocení].pdf"
},
{
"original": "366103079 2026-06-01 Čížkovská, Jaroslava [domácí péče] [1 do 30JUN2026].pdf",
"corrected": "366103079 2026-06-01 Čížkovská, Jaroslava [K od psychiatra] [že máme zařídit domácí péči, kterou pacientka domů nepustí].pdf"
},
{
"original": "435520110 2026-06-01 Nechodomová, Marie [LZ gastroenterologie] [Inkompetence kardie, pseudopolyp subkardiálně, biliární reflux, atrofie fornixu, hyperémie antra].pdf",
"corrected": "435520110 2026-06-01 Nechodomová, Marie [LZ gastroenterologie] [gastroskopie Inkompetence kardie, pseudopolyp subkardiálně, biliární reflux, atrofie fornixu, hyperémie antra].pdf"
},
{
"original": "5404211967 2014-11-19 Zich, Jiří [operační protokol neurochirurgie] [Stenóza L4/5, miniinvazivní over-the-top dekomprese L4/5 zleva].pdf",
"corrected": "5404211967 2014-11-19 Zich, Jiří [operační protokol neurochirurgie] [Stenóza L45, miniinvazivní over-the-top dekomprese L45 zleva].pdf"
},
{
"original": "5404211967 2014-11-24 Zich, Jiří [PZ neurochirurgie] [1824NOV2014 degenerativní stenóza L4/5, miniinvazivní over-the-top dekomprese L4/5 zleva].pdf",
"corrected": "5404211967 2014-11-24 Zich, Jiří [PZ neurochirurgie] [1824NOV2014 degenerativní stenóza L45, miniinvazivní over-the-top dekomprese L45 zleva].pdf"
},
{
"original": "5404211967 Zich, Jiří [dopis pacientovi] [žádost o typ kovové výztuhy bérce z r. 2001 před op. kolena].pdf",
"corrected": "5404211967 2026-06-05 Zich, Jiří [dopis pacienta] [žádost o typ kovové výztuhy bérce z r. 2001 před op. kolena].pdf"
},
{
"original": "5404211967 2022-06-22 Zich, Jiří [PZ ortopedicko-traumatologická] [2022JUN2022 extrakce OS hřebu bérce vlevo, gonartróza L kolena, TEP plánována].pdf",
"corrected": "5404211967 2022-06-22 Zich, Jiří [PZ ortopedie] [2022JUN2022 extrakce OS hřebu bérce vlevo, gonartróza L kolena, TEP plánována].pdf"
},
{
"original": "5404211967 2026-06-01 Zich, Jiří [řidičský průkaz zdravotní způsobilost] [zdravotně způsobilý sk. B, platnost do 01.06.2028].pdf",
"corrected": "5404211967 2026-06-01 Zich, Jiří [Posudek ŘP] [zdravotně způsobilý sk. B, platnost do 01.06.2028].pdf"
},
{
"original": "5404211967 2026-06-01 Zich, Jiří [Prohlášení zdravotní způsobilosti řidiče] [sk. B, cítí se zdráv, užívá Tamsulosin na prostatu].pdf",
"corrected": "5404211967 2026-06-01 Zich, Jiří [Prohlášení ŘP] [sk. B, cítí se zdráv, užívá Tamsulosin na prostatu].pdf"
},
{
"original": "7857103232 2014-07-14 Dubová, Zita [LZ neurologie] [noční můry od dětství, RLS, spánková anamnéza, ESS 15/24].pdf",
"corrected": "7857103232 2014-07-14 Dubová, Zita [LZ neurologie] [noční můry od dětství, RLS, spánková anamnéza, ESS 1524].pdf"
},
{
"original": "8157220159 2007-03-27 Vrňáková, Lucie [LZ hematologie] [kontrola, kompletní remise HL, gonadotox, subklinická hypothyreóza, diskrétní plicní tox].pdf",
"corrected": "8157220159 2007-06-27 Vrňáková, Lucie [LZ hematologie] [kontrola, kompletní remise HL, gonadotox, subklinická hypothyreóza, diskrétní plicní tox].pdf"
},
{
"original": "8157220159 2009-06-30 Vrňáková, Lucie [LZ hematologie] [kontrola, kompletní remise 7 let po terapii, incip. poradiační hypothyreóza, ko endokrinologie].pdf",
"corrected": "8157220159 2009-07-01 Vrňáková, Lucie [LZ hematologie] [kontrola, kompletní remise 7 let po terapii, incip. poradiační hypothyreóza, ko endokrinologie].pdf"
},
{
"original": "8157220159 2022-03-16 Vrňáková, Lucie [LZ kardiologie] [kontrola, stp. CHT a AR 2001, EF 73%, norm. diastol. fce, stopová MR/TR/PR, bez zn. plicní HTN, ko za 3-5 let].pdf",
"corrected": "8157220159 2022-03-16 Vrňáková, Lucie [LZ kardiologie] [kontrola, stp. CHT a AR 2001, EF 73%, norm. diastol. fce, stopová MRTRPR, bez zn. plicní HTN, ko za 3-5 let].pdf"
},
{
"original": "8812310408 2026-06-04 Sekrt, Zdeněk [EKG] [bez hodnocení].pdf",
"corrected": "8812310408 2026-06-04 Sekrt, Zdeněk [EKG] [bez hodnocení].pdf"
},
{
"original": "5459051862 2026-06-04 Vortelová, Eva [EKG] [bez hodnocení].pdf",
"corrected": "5459051862 2026-06-04 Vortelová, Eva [EKG] [bez hodnocení].pdf"
},
{
"original": "5962050149 2026-06-04 Jelínková, Eva [EKG] [bez hodnocení].pdf",
"corrected": "5962050149 2026-06-04 Jelínková, Eva [EKG] [bez hodnocení].pdf"
},
{
"original": "405712023 2026-06-05 Pilná, Marta [EKG] [bez hodnocení].pdf",
"corrected": "405712023 2026-06-05 Pilná, Marta [EKG] [bez hodnocení].pdf"
} }
] ]
+30
View File
@@ -0,0 +1,30 @@
Stack trace:
Frame Function Args
0007FFFFB540 00021005FE8E (000210285F68, 00021026AB6E, 0007FFFFB540, 0007FFFFA440) msys-2.0.dll+0x1FE8E
0007FFFFB540 0002100467F9 (000000000000, 000000000000, 000000000000, 0007FFFFB818) msys-2.0.dll+0x67F9
0007FFFFB540 000210046832 (000210286019, 0007FFFFB3F8, 0007FFFFB540, 000000000000) msys-2.0.dll+0x6832
0007FFFFB540 000210068CF6 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28CF6
0007FFFFB540 000210068E24 (0007FFFFB550, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28E24
0007FFFFB820 00021006A225 (0007FFFFB550, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A225
End of stack trace
Loaded modules:
000100400000 bash.exe
7FFD0F4F0000 ntdll.dll
7FFD0D6F0000 KERNEL32.DLL
7FFD0CD00000 KERNELBASE.dll
7FFD08A10000 apphelp.dll
7FFD0F260000 USER32.dll
7FFD0D320000 win32u.dll
7FFD0E6D0000 GDI32.dll
000210040000 msys-2.0.dll
7FFD0CBE0000 gdi32full.dll
7FFD0D350000 msvcp_win.dll
7FFD0D3F0000 ucrtbase.dll
7FFD0D510000 advapi32.dll
7FFD0F090000 msvcrt.dll
7FFD0F410000 sechost.dll
7FFD0E780000 RPCRT4.dll
7FFD0CB60000 bcrypt.dll
7FFD0C410000 CRYPTBASE.DLL
7FFD0D1E0000 bcryptPrimitives.dll
7FFD0D7C0000 IMM32.DLL