pdf-extract
Extrakce ručních poznámek, zvýraznění, podtržení a označených obrázků z PDF knih. Detekuje barevné anotace (zelené, žluté, červené, modré, černé) a vytvoří strukturovaný .md soubor s přepisem.
PDF Extract – extrakce poznámek z knih v4.1
Kdy použít
- Uživatel chce vytáhnout své ruční poznámky a zvýraznění z PDF knihy
- Trigger fráze: "extrahuj poznámky", "poznámky z PDF", "/pdf-extract", "vytáhni z knihy"
Vstup
- Cesta k PDF souboru (povinné)
- Volitelně: výstupní cesta, konkrétní rozsah stran
Kontext uživatele
- Uživatel anotuje digitálním perem na tabletu
- Typické anotace: čárky u textu, ohraničení pasáží, podtržení, sem tam ruční poznámka
- Tahy jsou vždy nepravidelné (nikdy dokonale rovné) – to je klíčový rozlišovací znak od tištěného obsahu
- Schémata a diagramy v knize mají být zachovány jako obrázky, NE převáděny na text
Dávkový režim (výchozí chování)
KRITICKÉ – MUSÍŠ DODRŽET:
- Výchozí: zpracuj prvních 50 stran, vytvoř výstupní
.mdsoubor a ZASTAV SE - STOP po prvních 50 stranách – vypiš uživateli výsledky a ČEKEJ na jeho odpověď
- Uživatel si výstup zkontroluje a řekne, jestli pokračovat s dalšími stranami
- NEPOKRAČUJ automaticky na strany 51+ bez explicitního pokynu uživatele
- Pokud uživatel explicitně řekne "zpracuj celou knihu" / "všechny strany" / "pokračuj", teprve pak pokračuj s dalšími stranami
- Při pokračování přidávej do existujícího
.mdsouboru, nemazej předchozí výsledky
Architektura – šetření kontextu
KRITICKÉ: Tento skill zpracovává desítky až stovky stran s obrázky. Aby nedocházelo k vyčerpání kontextového okna:
- Fáze 1 (detekce) běží v hlavním kontextu – je levná, výstupem je jen seznam čísel stran
- Fáze 2 (vizuální analýza + extrakce) se deleguje na Agent subagenty s model: "opus" (1M kontext)
- Subagenty zpracovávají dávky stran a vrací pouze strukturovaný markdown text, ne obrázky
- Hlavní kontext pak jen skládá výsledky z subagentů do výstupního souboru
Kategorie stran podle náročnosti zpracování:
- Jednoduché (PDF annotations: highlight, underline, strikeout) → extrahuj přímo z PDF dat, BEZ vizuální kontroly
- Marginální (vektorové kresby POUZE na okrajích stránky, tj. x < 60 nebo x > page_width - 60) → programatická extrakce spárováním souřadnic kreseb s textovými bloky (krok 4A-2), BEZ vizuální kontroly – toto je spolehlivější než vizuální analýza, protože fill-only paths se v PNG renderují jako extrémně tenké/neviditelné čáry
- Složité (vektorové kresby v těle stránky, ink anotace, barevné pixely, ruční text) → vyžadují vizuální kontrolu přes PNG → deleguj na subagenty
Workflow
1. Instalace závislostí (pokud chybí)
Ověř dostupnost a nainstaluj pokud chybí:
pip3 install PyMuPDF Pillow numpy
2. Zjisti metadata knihy
import fitz # PyMuPDF
doc = fitz.open("<cesta_k_pdf>")
title = doc.metadata.get("title", "")
author = doc.metadata.get("author", "")
page_count = len(doc)
- Pokud metadata chybí, odvoď název z názvu souboru
- Informuj uživatele: název, autor, počet stran
3. Detekce anotovaných stran (Fáze 1 – hlavní kontext)
Zpracovávej po dávkách (50–100 stran), aby se šetřila paměť.
3a. Detekce barevných pixelových anotací
Renderuj stránky přes PyMuPDF a hledej barevné pixely:
import numpy as np
from PIL import Image
pix = page.get_pixmap(dpi=100)
img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.h, pix.w, pix.n)
r, g, b = img[:,:,0], img[:,:,1], img[:,:,2]
Detekční pravidla pro jednotlivé barvy:
| Barva | Podmínka | Význam |
|---|---|---|
| Černá | viz krok 3b (vektorová detekce) | Hlavní barva – poznámky, podtržení, zatržení |
| Zelená | (g > 100) & (g > r*1.2) & (g > b*1.2) & ((g-r) > 30) | Zvýraznění, zatržení |
| Žlutá | (r > 150) & (g > 150) & (b < 100) & (r+g > 350) | Highlighter |
| Červená | (r > 150) & (r > g*1.5) & (r > b*1.5) | Důležité, opravy |
| Modrá | (b > 100) & (b > r*1.2) & (b > g*1.2) & ((b-r) > 30) | Poznámky, otázky |
| Oranžová | (r > 180) & (g > 80) & (g < 160) & (b < 80) | Doplňkové zvýraznění |
Práh: > 50 barevných pixelů dané barvy = podezřelá strana
3b. Detekce černých anotací (PRIMÁRNÍ – uživatel píše digitálním perem)
Černé anotace jsou nejčastější typ. Detekce je náročnější, protože tištěný text je také černý.
KLÍČOVÉ ROZLIŠENÍ ruční vs. tištěné: Uživatel píše digitálním perem na tabletu. Jeho tahy jsou vždy nepravidelné – nikdy dokonale rovné čáry, body v nepravidelných rozestupech, mírné odchylky od přímky. Tištěné prvky mají přesnou geometrii – dokonale rovné čáry, přesné úhly, pravidelné rozestupy.
Přístup 1: Vektorové kresby (drawings)
drawings = page.get_drawings()
DŮLEŽITÉ – kontroluj OBOJÍ: color (stroke) i fill (výplň):
Některé PDF ukládají ruční anotace jako filled paths (výplň) místo stroked paths (obrys). Mnoho digitálních per generuje color=None, fill=(0,0,0).
import math
def is_hand_drawn(items):
"""Rozliš ruční tah od tištěného prvku.
Ruční tahy (digitální pero na tabletu):
- Mnoho bodů v krátkém úseku (pero sampluje polohu)
- Body NEJSOU na dokonalé přímce – odchylka od spojnice > 0
- Křivky (bezier curves) = téměř jistě ruční
- Celkový tvar je nepravidelný
Tištěné prvky (layout PDF):
- Málo bodů (typicky 2-4 pro čáry a obdélníky)
- Dokonale rovné čáry (odchylka = 0)
- Pravidelné obdélníky, kruhy
- Přesné horizontální/vertikální zarovnání
"""
has_curves = False
line_segments = []
point_count = 0
for item in items:
op = item[0] # typ operace: "l" (line), "c" (curve), "re" (rect), "qu" (quad)
if op == "c": # bezier křivka = téměř jistě ruční
has_curves = True
point_count += 4
elif op == "l": # úsečka
p1, p2 = item[1], item[2]
dx = abs(p2.x - p1.x)
dy = abs(p2.y - p1.y)
length = math.sqrt(dx*dx + dy*dy)
line_segments.append((p1, p2, length, dx, dy))
point_count += 2
elif op == "re": # obdélník = typicky tištěný layout
point_count += 4
elif op == "qu": # quad = typicky tištěný
point_count += 4
# Bezier křivky = ruční
if has_curves:
return True
# Samé obdélníky/quady bez čar = pravděpodobně layout
if not line_segments and not has_curves:
return False
# Mnoho krátkých úseček za sebou = samplovaný tah pera
if len(line_segments) > 5:
short_segments = sum(1 for _, _, l, _, _ in line_segments if l < 15)
if short_segments > len(line_segments) * 0.5:
return True
# Kontrola nepravidelnosti: pokud úsečky NEJSOU dokonale horizontální/vertikální
irregular_count = 0
for _, _, length, dx, dy in line_segments:
if length < 1:
continue
# Dokonale rovná čára: dx==0 nebo dy==0 (nebo téměř)
angle_from_axis = min(dx, dy) / max(dx, dy) if max(dx, dy) > 0 else 0
if angle_from_axis > 0.02: # > 1° odchylka od osy = nepravidelné
irregular_count += 1
if irregular_count > 0 and irregular_count >= len(line_segments) * 0.3:
return True
return False
for d in drawings:
color = d.get("color", None)
fill = d.get("fill", None)
items = d.get("items", [])
is_black_stroke = (color is not None and len(color) >= 3
and color[0] < 0.2 and color[1] < 0.2 and color[2] < 0.2)
is_black_fill = (fill is not None and len(fill) >= 3
and fill[0] < 0.2 and fill[1] < 0.2 and fill[2] < 0.2)
is_bg_rect = (fill is not None and len(fill) >= 3
and fill[0] > 0.9 and fill[1] > 0.9 and fill[2] > 0.9)
if is_bg_rect:
continue # šedé/bílé pozadí citátů – ignorovat
if (is_black_stroke or is_black_fill) and len(items) > 1:
# KLÍČOVÉ: ověř, že jde o ruční tah, ne tištěný prvek
if is_hand_drawn(items):
annotation_items += len(items)
Filtrování false positives – pravidla:
- VŽDY použij
is_hand_drawn()– nepoužívej jen počet items jako práh - Obdélníky (
re) = téměř vždy layout (rámečky, boxy) → ignorovat, pokud nejsou nepravidelné - Dokonale rovné čáry (horizontální/vertikální, odchylka < 1°) = tištěný prvek → ignorovat
- Bezier křivky = téměř jistě ruční → vždy zahrnout
- Mnoho krátkých úseček v řadě = samplovaný tah digitálního pera → zahrnout
- Nepravidelné úhly (odchylka > 1° od osy) = ruční tah → zahrnout
- Práh pro celou stranu: součet items z potvrzeně ručních kreseb > 5 = anotovaná strana
Přístup 2: Ink anotace (PDF annotation layer)
for annot in page.annots():
if annot.type[0] in [8, 15]: # Ink, Polyline
# Ink anotace = vždy ruční → zahrnout
pass
Dodatečné filtry pro snížení false positives:
- Ignoruj kresby uvnitř tabulek – tabulkové čáry jsou tištěné
- Ignoruj dekorativní prvky u nadpisů/zápatí (opakující se vzor na více stranách)
- Pokud se stejný drawing pattern opakuje na > 30 % stran, je to pravděpodobně layout → vyloučit
- Buď přesný – cíl je zachytit VŠECHNY ruční anotace a ŽÁDNÉ tištěné prvky; při pochybnosti pošli stranu na vizuální kontrolu subagentovi, který rozhodne
3c. Detekce vestavěných PDF anotací
annots = page.annots()
- Zkontroluj vestavěné PDF anotace (highlight, underline, strikeout, text notes, ink)
- Typy:
Highlight,Underline,StrikeOut,Text,FreeText,Ink,Square,Circle - Extrahuj barvu a obsah anotace
3d. Klasifikace pozice kreseb na stránce
Pro každou stranu s detekovanými vektorovými kresbami analyzuj POZICI kreseb:
def classify_drawing_position(drawing, page_width):
"""Určí, zda je kresba na okraji stránky nebo v těle textu."""
items = drawing.get("items", [])
xs, ys = [], []
for item in items:
for pt in item[1:]:
if hasattr(pt, 'x'):
xs.append(pt.x)
ys.append(pt.y)
if not xs:
return None, None, None, None
min_x, max_x = min(xs), max(xs)
min_y, max_y = min(ys), max(ys)
x_span = max_x - min_x
y_span = max_y - min_y
# Svislá čára na okraji = zatržení
if x_span < 30: # úzká kresba = svislá čára
if min_x < 60:
return "left_margin", min_x, min_y, max_y
elif min_x > page_width - 60:
return "right_margin", min_x, min_y, max_y
# Široká kresba na okraji
if max_x < 60:
return "left_margin", min_x, min_y, max_y
if min_x > page_width - 60:
return "right_margin", min_x, min_y, max_y
return "body", min_x, min_y, max_y
Pro každou stranu s potvrzeně ručními kresbami ulož:
- Seznam kreseb s jejich pozicí (left_margin / right_margin / body)
- Souřadnice y-rozsahu každé kresby
- Počet items v kresbě
3e. Kategorizace nalezených stran
Rozděl nalezené strany do tří skupin:
Jednoduché strany (BEZ vizuální kontroly):
- Mají POUZE vestavěné PDF anotace typu
Highlight,Underline,StrikeOut - Text pod anotací lze extrahovat přímo z PDF dat přes
page.get_text() - Zpracuj tyto strany přímo v hlavním kontextu (viz krok 4A-1)
Marginální strany (programatická extrakce, BEZ vizuální kontroly):
- Mají vektorové kresby POUZE na okrajích stránky (left_margin / right_margin)
- Žádné kresby v těle stránky (body)
- Text se extrahuje programaticky spárováním y-souřadnic kreseb s textovými bloky (viz krok 4A-2)
- DŮLEŽITÉ: Toto je spolehlivější než vizuální analýza! Fill-only paths (color=None, fill=(0,0,0)) se v PNG renderují jako extrémně tenké/neviditelné čáry a subagent je nevidí
Složité strany (VYŽADUJÍ vizuální kontrolu):
- Mají vektorové kresby v těle stránky, ink anotace, barevné pixelové anotace, nebo ruční text
- Obsahují ruční poznámky, šipky, symboly, schémata
- Deleguj na subagenty (viz krok 4B)
Vypiš uživateli přehled: kolik stran nalezeno, kolik jednoduchých vs. marginálních vs. složitých.
4A-1. Přímá extrakce jednoduchých stran (hlavní kontext)
Pro strany s POUZE vestavěnými PDF anotacemi (highlight, underline, strikeout):
for annot in page.annots():
annot_type = annot.type[1] # "Highlight", "Underline", etc.
annot_color = annot.colors.get("stroke", None) or annot.colors.get("fill", None)
# Získej text pod anotací
text = page.get_text("text", clip=annot.rect)
- Extrahuj text přímo z PDF – žádné PNG, žádná vizuální analýza
- Zapiš rovnou do výstupního markdown (buffer v paměti)
- Toto je extrémně levné na kontext
4A-2. Programatická extrakce marginálních stran (hlavní kontext)
Pro strany s vektorovými kresbami POUZE na okrajích stránky. Toto je spolehlivější než vizuální analýza pro zatržení/podtržení, protože fill-only paths se v PNG renderují jako neviditelné.
def get_text_in_y_range(page, y_min, y_max, margin=15):
"""Získej textové řádky v daném rozsahu y-souřadnic.
DŮLEŽITÉ: margin=15 (ne 5!) – kresby často začínají/končí
mírně mimo textový blok, větší margin zajistí správné párování.
"""
blocks = page.get_text("dict")["blocks"]
lines = []
for b in blocks:
if "lines" not in b:
continue
for line in b["lines"]:
ly = (line["bbox"][1] + line["bbox"][3]) / 2 # střed řádku
if y_min - margin <= ly <= y_max + margin:
text = " ".join(span["text"] for span in line["spans"])
if text.strip():
lines.append(text.strip())
return "\n".join(lines)
def merge_ranges(ranges, gap=10):
"""Slučuj překrývající se y-rozsahy.
KRITICKÉ: Řaď podle y_min (x[1]), NE podle position stringu (x[0])!
Špatné řazení způsobí nesprávné sloučení nepřekrývajících se rozsahů
a ztrátu anotací.
"""
if not ranges: return []
ranges.sort(key=lambda x: x[1]) # řaď podle y_min, NE podle position!
merged = [list(ranges[0])]
for pos, y_min, y_max in ranges[1:]:
if y_min <= merged[-1][2] + gap:
merged[-1][2] = max(merged[-1][2], y_max)
else:
merged.append([pos, y_min, y_max])
return merged
# Pro každou marginální stranu:
page = doc[page_num - 1]
pw = page.rect.width
# Seskup kresby podle pozice a y-rozsahu
margin_annotations = [] # [(position, y_min, y_max)]
for d in drawings:
# ... filtruj jen potvrzeně ruční černé kresby ...
pos, min_x, min_y, max_y = classify_drawing_position(d, pw)
if pos in ("left_margin", "right_margin") and (max_y - min_y) > 20:
margin_annotations.append((pos, min_y, max_y))
# Slučuj překrývající se rozsahy (POZOR: merge_ranges musí řadit dle y_min!)
merged = merge_ranges(margin_annotations)
# Pak pro každý rozsah:
for pos, y_min, y_max in merged:
text = get_text_in_y_range(page, y_min, y_max)
# Zapiš jako [ZATRŽENO] s poznámkou o pozici (left/right/oboustranné)
Pravidla pro marginální extrakci:
- Kresby s y_span < 20pt ignoruj (příliš malé = pravděpodobně tečky/artefakty)
- Pokud je kresba na OBOU okrajích (left + right) ve stejném y-rozsahu → "Oboustranné zatržení"
- Pokud je kresba pouze na jednom okraji → "[ZATRŽENO]" bez speciální poznámky
- Text extrahuj přes
get_text("dict")pro přesné řádky, NE přesget_text("text", clip=...)– clip je méně přesný - Toto je extrémně levné na kontext a spolehlivější než vizuální analýza pro okrajové anotace
4B. Vizuální analýza složitých stran (delegovaná na subagenty)
KRITICKÉ pro šetření kontextu: Vizuální analýzu NIKDY neděle v hlavním kontextu. Vždy deleguj na Agent subagenty.
4B-1. Příprava PNG souborů
Před spuštěním subagentů exportuj všechny složité strany jako PNG:
pix = page.get_pixmap(dpi=250) # 250 DPI – vyšší rozlišení pro spolehlivou detekci jemných tahů
pix.save(f"temp_pages/page_{page_num:04d}.png")
Také pro každou stranu extrahuj tištěný text a drawing metadata:
text = page.get_text()
with open(f"temp_pages/page_{page_num:04d}.txt", "w") as f:
f.write(text)
# Drawing metadata – pomůže subagentovi vědět KAM se dívat
with open(f"temp_pages/page_{page_num:04d}_hints.txt", "w") as f:
for d in page.get_drawings():
fill = d.get("fill", None)
color = d.get("color", None)
items = d.get("items", [])
is_black = (fill and fill[0] < 0.2) or (color and color[0] < 0.2)
if is_black and len(items) > 3:
pos, min_x, min_y, max_y = classify_drawing_position(d, page.rect.width)
if pos:
f.write(f"Drawing: {len(items)} items, pos={pos}, y=[{min_y:.0f}-{max_y:.0f}]\n")
4B-2. Spuštění subagentů po dávkách
Rozděl složité strany do dávek po max 15 stranách. Pro každou dávku spusť Agent subagenta:
Agent(
model: "opus", # 1M kontext – unese 15 stran s obrázky
description: "PDF extract batch X",
prompt: """
Jsi expert na extrakci ručních poznámek z PDF knih.
Zpracuj tyto strany: [seznam čísel stran]
Cesta k PNG: temp_pages/page_XXXX.png
Cesta k textu: temp_pages/page_XXXX.txt
Pro každou stranu:
1. Přečti soubor _hints.txt – obsahuje pozice detekovaných kreseb (kde hledat anotace)
2. Přečti PNG přes Read tool (vizuální kontrola)
3. Přečti textový soubor pro kontext tištěného textu
4. Identifikuj typy anotací (viz tabulka níže) – ZAMĚŘ SE na pozice z hints souboru
5. Pokud je na stránce označený obrázek/schéma, extrahuj ho
Typy anotací:
| Tag | Popis |
|-----|-------|
| [RUKOU PSÁNO] | Ruční text – poznámky, nadpisy, komentáře |
| [ZATRŽENO] | Svislá čára na okraji u tištěné pasáže |
| [ZVÝRAZNĚNO] | Highlight / rámeček kolem textu |
| [PODTRŽENO] | Čára pod tištěným textem |
| [OBRÁZEK] | Označený/orámovaný obrázek na stránce |
| [SCHÉMA] | Diagram, schéma, graf – VŽDY zachovat jako obrázek, NIKDY nepřevádět na text |
| [ŠIPKA] | Šipka ukazující na konkrétní místo |
| [SYMBOL] | Hvězdička, vykřičník, otazník, check |
| [ZÁLOŽKA] | Označení celé strany |
DŮLEŽITÉ – rozlišení ručních anotací vs. tištěný obsah:
- Uživatel anotuje digitálním perem na tabletu
- Jeho tahy jsou VŽDY nepravidelné (nikdy dokonale rovné)
- Tištěný text a layout prvky (čáry tabulek, rámečky, dekorativní prvky) jsou dokonale geometrické
- NEOZNAČUJ tištěné prvky jako anotace!
- Hledej: čárky u textu, ohraničení pasáží, podtržení, ruční poznámky na okrajích
- Pokud si nejsi jistý, jestli je prvek ruční nebo tištěný → ZAHRŇ ho do výstupu s poznámkou [nejisté]
SCHÉMATA A DIAGRAMY:
- Pokud strana obsahuje schéma/diagram/graf (tištěný i ručně kreslený), VŽDY ho zachovej jako obrázek
- NIKDY nepřeváděj schéma na textový popis
- Extrahuj oblast schématu jako samostatný PNG pomocí PyMuPDF s clip parametrem:
```python
import fitz
doc = fitz.open("<cesta_k_pdf>")
page = doc[page_num - 1]
clip = fitz.Rect(x0, y0, x1, y1) # oblast schématu z hints/vizuální analýzy
pix = page.get_pixmap(dpi=300, clip=clip)
pix.save(f"{nazev_knihy}_images/img_page{page_num}_{N}.png")
```
- Vlož do markdown jako obrázek: ``
VÝSTUP: Vrať POUZE strukturovaný markdown pro každou stranu v tomto formátu:
## Strana XX
### [TYP_ANOTACE] emoji_barvy
> text anotace
---
Pokud text nelze přečíst, napiš [nečitelné].
Nevymýšlej text – pokud ho nevidíš, nevymýšlej.
U zatržených pasáží cituj dostatečně velký blok tištěného textu.
U ručních poznámek přepsat text kurzívou.
Schémata a diagramy VŽDY jako obrázek, NIKDY jako text.
Obrázky ukládej jako: {nazev_knihy}_images/img_page{XX}_{N}.png
"""
)
Paralelizace: Pokud je stran hodně (30+), spusť 2–3 subagenty paralelně (nezávislé dávky).
4B-3. Extrakce označených obrázků v subagentovi
Subagent v rámci své dávky extrahuje označené obrázky:
images = page.get_images(full=True)
for img_info in images:
xref = img_info[0]
base_image = doc.extract_image(xref)
# Ulož obrázek do výstupní složky
- Ulož obrázek jako
img_page{XX}_{N}.pngdo složky{nazev_knihy}_images/ - V markdown odkazuj relativní cestou
4C. Programatická verifikace po subagentovi (hlavní kontext)
KRITICKÉ: Po dokončení subagentů porovnej jejich výsledky s detekčními daty z Fáze 1.
Pro každou stranu, kterou subagent označil jako "false positive" nebo "žádné anotace":
- Zkontroluj, zda Fáze 1 detekovala vektorové kresby s > 10 items na okrajích (left_margin / right_margin)
- Pokud ANO → subagent se mýlil (fill-only paths jsou v PNG neviditelné)
- Použij programatickou extrakci (stejný postup jako 4A-2) k získání zatržených textů
- Doplň tyto strany do výstupu
Důvod: Některé PDF ukládají ruční tahy jako color=None, fill=(0,0,0) (filled paths bez stroke). Při renderování do PNG se tyto kresby zobrazí jako extrémně tenké čáry (sub-pixel), které LLM v obrázku nevidí. Vektorová data z PDF jsou v tomto případě autoritativní.
5. Sestavení výstupního souboru (hlavní kontext)
Po dokončení všech subagentů sestav výstupní soubor z:
- Přímé extrakce jednoduchých stran (krok 4A)
- Markdown výstupů ze subagentů (krok 4B)
5a. Název souboru
- Formát:
Nazev_knihy (Autor).md - Příklad:
Thinking_Fast_and_Slow (Daniel Kahneman).md - Mezery v názvu knihy nahraď podtržítky
- Ulož do stejné složky jako zdrojové PDF
5b. Struktura markdown souboru
# Název knihy
**Autor:** Jméno Autora
**Extrahováno:** YYYY-MM-DD
**Zdroj:** název_souboru.pdf
**Počet anotovaných stran:** XX z YY
---
<!-- Uživatelské poznámky – prostor pro vlastní text nad extrakcí -->
---
## Strana 42
### [ZATRŽENO]
> Tištěný text pasáže, která byla zatržena svislou čárou na okraji.
> Může být víceřádková.
### [RUKOU PSÁNO]
> Přepis ručně psané poznámky kurzívou
### [ZVÝRAZNĚNO] 🟡
> Text, který byl zvýrazněn žlutým highlighterem
### [PODTRŽENO]
> Podtržená věta nebo fráze
### [OBRÁZEK]

> Poznámka k obrázku (pokud existuje)
---
## Strana 57
...
5c. Pravidla zápisu
- Řadit chronologicky podle čísla strany (sluč výsledky z jednoduchých stran a subagentů)
- U barevných anotací přidat emoji indikátor barvy: ⚫ černá, 🟢 zelená, 🟡 žlutá, 🔴 červená, 🔵 modrá, 🟠 oranžová
- Černé anotace (nejčastější) nemusí mít emoji – jsou výchozí; emoji přidávej jen u barevných
- U zatržených/zvýrazněných pasáží citovat relevantní tištěný text v bloku
> - U ručních poznámek přepsat text kurzívou v bloku
> - NEMAZAT existující obsah – pokud soubor již existuje, uživatel může mít vlastní poznámky na začátku
- Pokud soubor existuje, aktualizuj/doplň pouze sekce za oddělovačem
---
6. Úklid
rm -rf temp_pages/
- Smaž dočasný adresář s PNG exporty a textovými soubory
- Ponech složku s extrahovanými obrázky (
{nazev_knihy}_images/)
7. Shrnutí
Vypiš uživateli:
- Cestu k výstupnímu
.mdsouboru - Cestu ke složce s obrázky (pokud existuje)
- Počet zpracovaných stran / nalezených anotací
- Rozložení typů anotací (kolik zatržení, kolik poznámek, atd.)
- Stručný přehled nejčastěji anotovaných témat/kapitol
Pravidla kvality
Vždy:
- Ověř, že PDF existuje a je čitelný
- Zpracovávej po dávkách – nenahrávej celé PDF do paměti najednou
- U ručních poznámek se snaž o co nejpřesnější přepis
- Pokud text nelze přečíst, napiš
[nečitelné] - Zachovej kontext – u zatržených pasáží cituj dostatečně velký blok textu
- Informuj uživatele o průběhu (kolik stran zpracováno)
- Schémata/diagramy vždy zachovej jako obrázek (PNG), nepřeváděj na text
- Buď přesný – zachyť všechny ruční anotace, ale neoznačuj tištěné prvky; při pochybnosti pošli na vizuální kontrolu subagentovi
Nikdy:
- Nevynechávej nalezené anotace
- Nevymýšlej text – pokud ho nevidíš, nevymýšlej
- Nemazej existující obsah v cílovém souboru
- Neignoruj obrázky – pokud jsou označené, extrahuj je
- NIKDY nečti PNG obrázky stran v hlavním kontextu – vždy deleguj na subagenty
- NIKDY neoznačuj tištěné prvky (layout, tabulky, dekorace) jako anotace
- NIKDY nepřeváděj schémata/diagramy na textový popis – vždy jako obrázek
Tipy
- U knih s mnoha anotacemi (100+ stran) může zpracování trvat déle – informuj uživatele
- Některé PDF mají anotace jako vestavěné PDF annotations (ne jen barevné pixely) – kontroluj obojí
- Pokud je kvalita skenování nízká, zvyš DPI na 200 pro lepší detekci v subagentovi
- Pro knihy s převážně žlutým highlighterem uprav práh detekce
- Subagenty s model: "opus" mají 1M kontext – klidně jim dej 15 stran najednou
- Pokud má kniha < 10 složitých stran, stačí jeden subagent; pro 30+ stran spusť 2–3 paralelně