{
"event": "PreToolUse",
"tool_name": "mcp__mcp-tasks__tasks_create",
"tool_input": {
"title": "PDF-Rotationserkennung und -korrektur implementieren",
"description": "## KONTEXT\n\nPDF-Dokumente enthalten teilweise um 90°\/180°\/270° gedrehte Seiten. Die aktuelle Pipeline ignoriert die Rotation, was zu:\n- Fehlerhafter OCR-Extraktion\n- Unlesbaren Vision-Analysen\n- Korrupten Embeddings\n\nführt.\n\n---\n\n## CODE-ANALYSE\n\n### Betroffene Dateien\n\n| Datei | Funktion | Zeilen | Problem |\n|-------|----------|--------|---------|\n| `extract.py` | `extract_pdf()` | 13-45 | Keine Rotationserkennung |\n| `vision.py` | `pdf_to_images()` | 30-67 | Rotation wird ignoriert |\n| `config.py` | OCR-Settings | 74-76 | OCR_ENABLED=True |\n\n### Aktuelle Implementierung\n\n**extract.py:13-45**\n```python\ndef extract_pdf(file_path):\n import fitz # PyMuPDF\n doc = fitz.open(file_path)\n pages = []\n \n for page_num, page in enumerate(doc):\n text = page.get_text() # ← Ignoriert Rotation\n \n # OCR-Fallback (Zeile 24-40)\n if OCR_ENABLED and len(text.strip()) < 50:\n pix = page.get_pixmap(dpi=300) # ← Rotation nicht berücksichtigt\n img = Image.open(io.BytesIO(img_data))\n ocr_text = pytesseract.image_to_string(img, lang=OCR_LANGUAGE)\n # ← Keine Orientierungserkennung\n```\n\n**vision.py:30-67**\n```python\ndef pdf_to_images(file_path, dpi=IMAGE_DPI):\n import fitz\n doc = fitz.open(file_path)\n \n for page_num in range(len(doc)):\n page = doc[page_num]\n mat = fitz.Matrix(dpi \/ 72, dpi \/ 72)\n pix = page.get_pixmap(matrix=mat) # ← Rotation ignoriert\n```\n\n### Systemzustand\n\n| Komponente | Status |\n|------------|--------|\n| PyMuPDF | ✓ 1.26.7 installiert |\n| pytesseract | ✓ 0.3.13 installiert |\n| Pillow | ✓ 12.0.0 installiert |\n| **tesseract binary** | ❌ **NICHT INSTALLIERT** |\n| OCR_ENABLED | True (aber funktioniert nicht!) |\n\n---\n\n## LÖSUNG: Mehrstufige Orientierungserkennung\n\n### Architektur\n\n```\n┌─────────────────────────────────────────────────────────┐\n│ Stufe 1: PDF-Metadaten (page.rotation) │\n│ PyMuPDF liest \/Rotate Flag aus PDF │\n│ → Schnell, kostenlos, 0ms │\n└─────────────────────┬───────────────────────────────────┘\n │ Falls rotation == 0\n ▼\n┌─────────────────────────────────────────────────────────┐\n│ Stufe 2: Tesseract OSD (Orientation Script Detection) │\n│ pytesseract.image_to_osd(img) │\n│ → Erkennt 0°\/90°\/180°\/270°, Confidence-Score │\n│ → ~50-100ms pro Seite │\n└─────────────────────┬───────────────────────────────────┘\n │ Falls Confidence < 2.0\n ▼\n┌─────────────────────────────────────────────────────────┐\n│ Stufe 3: Vision-LLM Fallback (optional) │\n│ \"Ist diese Seite korrekt orientiert?\" │\n│ → Für Bilder ohne Text │\n└─────────────────────────────────────────────────────────┘\n```\n\n### Implementierung\n\n#### 1. Voraussetzung: Tesseract installieren\n\n```bash\napt-get install tesseract-ocr tesseract-ocr-deu\n```\n\n#### 2. Neue Datei: `\/var\/www\/scripts\/pipeline\/orientation.py`\n\n```python\n\"\"\"\nPage Orientation Detection Module\nDetects and corrects rotated PDF pages.\n\"\"\"\n\nimport io\nfrom PIL import Image\nimport pytesseract\nimport fitz # PyMuPDF\n\nfrom db import db\n\n\ndef detect_orientation(image_bytes: bytes) -> dict:\n \"\"\"\n Detect page orientation using Tesseract OSD.\n \n Args:\n image_bytes: PNG\/JPEG image as bytes\n \n Returns:\n dict: {\n 'rotation': int (0, 90, 180, 270),\n 'confidence': float,\n 'script': str,\n 'method': str ('osd' or 'fallback')\n }\n \"\"\"\n try:\n img = Image.open(io.BytesIO(image_bytes))\n osd = pytesseract.image_to_osd(img, output_type=pytesseract.Output.DICT)\n \n return {\n 'rotation': osd.get('rotate', 0),\n 'confidence': osd.get('orientation_conf', 0.0),\n 'script': osd.get('script', 'Unknown'),\n 'method': 'osd'\n }\n except Exception as e:\n db.log(\"WARNING\", f\"OSD detection failed: {e}\")\n return {\n 'rotation': 0,\n 'confidence': 0.0,\n 'script': 'Unknown',\n 'method': 'fallback'\n }\n\n\ndef get_page_rotation(page) -> int:\n \"\"\"\n Get effective rotation for a PDF page.\n \n Combines PDF metadata rotation with detected orientation.\n \n Args:\n page: PyMuPDF page object\n \n Returns:\n int: Total rotation needed (0, 90, 180, 270)\n \"\"\"\n # Stufe 1: PDF-Metadaten\n pdf_rotation = page.rotation # 0, 90, 180, 270\n \n if pdf_rotation != 0:\n return pdf_rotation\n \n # Stufe 2: Tesseract OSD\n pix = page.get_pixmap(dpi=150) # Lower DPI for speed\n img_bytes = pix.tobytes(\"png\")\n \n detection = detect_orientation(img_bytes)\n \n if detection['confidence'] >= 2.0:\n return detection['rotation']\n \n return 0\n\n\ndef rotate_image(image_bytes: bytes, rotation: int) -> bytes:\n \"\"\"\n Rotate image by specified degrees.\n \n Args:\n image_bytes: Original image\n rotation: Degrees to rotate (90, 180, 270)\n \n Returns:\n bytes: Rotated image as PNG\n \"\"\"\n if rotation == 0:\n return image_bytes\n \n img = Image.open(io.BytesIO(image_bytes))\n \n # PIL rotation is counter-clockwise, PDF is clockwise\n rotated = img.rotate(-rotation, expand=True)\n \n output = io.BytesIO()\n rotated.save(output, format='PNG')\n return output.getvalue()\n```\n\n#### 3. Integration in extract.py\n\n**Änderung in `extract_pdf()` (Zeile 20-27 einfügen):**\n\n```python\ndef extract_pdf(file_path):\n import fitz\n from orientation import get_page_rotation, rotate_image\n \n doc = fitz.open(file_path)\n pages = []\n \n for page_num, page in enumerate(doc):\n # NEU: Rotation erkennen\n rotation = get_page_rotation(page)\n \n # Text mit korrekter Rotation extrahieren\n if rotation != 0:\n # Seite vor Extraktion rotieren\n page.set_rotation(rotation)\n \n text = page.get_text()\n \n # OCR-Fallback mit rotiertem Bild\n if OCR_ENABLED and len(text.strip()) < 50:\n pix = page.get_pixmap(dpi=300)\n img_data = pix.tobytes(\"png\")\n \n # NEU: Bild rotieren falls nötig\n if rotation != 0:\n img_data = rotate_image(img_data, rotation)\n \n img = Image.open(io.BytesIO(img_data))\n ocr_text = pytesseract.image_to_string(img, lang=OCR_LANGUAGE)\n```\n\n#### 4. Integration in vision.py\n\n**Änderung in `pdf_to_images()` (Zeile 46-54):**\n\n```python\ndef pdf_to_images(file_path, dpi=IMAGE_DPI):\n import fitz\n from orientation import get_page_rotation, rotate_image\n \n doc = fitz.open(file_path)\n pages = []\n \n for page_num in range(len(doc)):\n page = doc[page_num]\n \n # NEU: Rotation erkennen\n rotation = get_page_rotation(page)\n \n mat = fitz.Matrix(dpi \/ 72, dpi \/ 72)\n pix = page.get_pixmap(matrix=mat)\n img_bytes = pix.tobytes(IMAGE_FORMAT)\n \n # NEU: Bild rotieren falls nötig\n if rotation != 0:\n img_bytes = rotate_image(img_bytes, rotation)\n db.log(\"INFO\", f\"Page {page_num+1} rotated by {rotation}°\")\n```\n\n---\n\n## KONFIGURATION\n\n**config.py erweitern:**\n\n```python\n# Rotation Detection Settings\nROTATION_DETECTION_ENABLED = True\nROTATION_OSD_CONFIDENCE_THRESHOLD = 2.0\nROTATION_USE_VISION_FALLBACK = False # Für Bilder ohne Text\n```\n\n---\n\n## TESTPLAN\n\n1. [ ] Tesseract installieren: `apt-get install tesseract-ocr tesseract-ocr-deu`\n2. [ ] Tesseract verifizieren: `tesseract --version`\n3. [ ] orientation.py erstellen\n4. [ ] Unit-Tests für detect_orientation()\n5. [ ] extract.py integrieren\n6. [ ] vision.py integrieren\n7. [ ] Test mit gedrehtem PDF:\n - 90° gedrehte Seite → korrekt erkannt\n - 180° gedrehte Seite → korrekt erkannt\n - OCR-Text lesbar\n - Vision-Analyse korrekt\n8. [ ] Performance-Test: <100ms overhead pro Seite\n\n---\n\n## VALIDIERUNG\n\n```bash\n# Tesseract OSD Test\necho \"Test\" | tesseract stdin stdout --psm 0\n\n# Python-Test\npython3 -c \"\nimport pytesseract\nfrom PIL import Image\nimg = Image.new('RGB', (100, 100), 'white')\nprint(pytesseract.image_to_osd(img))\n\"\n```\n\n---\n\n## ABHÄNGIGKEITEN\n\n| Paket | Version | Status |\n|-------|---------|--------|\n| tesseract-ocr | >= 4.0 | ❌ INSTALLIEREN |\n| tesseract-ocr-deu | - | ❌ INSTALLIEREN |\n| PyMuPDF | 1.26.7 | ✓ |\n| pytesseract | 0.3.13 | ✓ |\n| Pillow | 12.0.0 | ✓ |\n\n---\n\n## GESCHÄTZTER AUFWAND\n\n| Schritt | Zeit |\n|---------|------|\n| Tesseract installieren | 5 min |\n| orientation.py erstellen | 30 min |\n| extract.py anpassen | 15 min |\n| vision.py anpassen | 15 min |\n| config.py erweitern | 5 min |\n| Tests | 30 min |\n| **Gesamt** | **~100 min** |",
"type": "ai_task"
}
}
{
"tool_response": [
{
"type": "text",
"text": "{\n \"success\": true,\n \"task\": {\n \"id\": 442,\n \"uuid\": \"b22debfc-fde0-4a34-bf6d-08a0bd96110e\",\n \"title\": \"PDF-Rotationserkennung und -korrektur implementieren\",\n \"description\": \"## KONTEXT\\n\\nPDF-Dokumente enthalten teilweise um 90°\/180°\/270° gedrehte Seiten. Die aktuelle Pipeline ignoriert die Rotation, was zu:\\n- Fehlerhafter OCR-Extraktion\\n- Unlesbaren Vision-Analysen\\n- Korrupten Embeddings\\n\\nführt.\\n\\n---\\n\\n## CODE-ANALYSE\\n\\n### Betroffene Dateien\\n\\n| Datei | Funktion | Zeilen | Problem |\\n|-------|----------|--------|---------|\\n| `extract.py` | `extract_pdf()` | 13-45 | Keine Rotationserkennung |\\n| `vision.py` | `pdf_to_images()` | 30-67 | Rotation wird ignoriert |\\n| `config.py` | OCR-Settings | 74-76 | OCR_ENABLED=True |\\n\\n### Aktuelle Implementierung\\n\\n**extract.py:13-45**\\n```python\\ndef extract_pdf(file_path):\\n import fitz # PyMuPDF\\n doc = fitz.open(file_path)\\n pages = []\\n \\n for page_num, page in enumerate(doc):\\n text = page.get_text() # ← Ignoriert Rotation\\n \\n # OCR-Fallback (Zeile 24-40)\\n if OCR_ENABLED and len(text.strip()) < 50:\\n pix = page.get_pixmap(dpi=300) # ← Rotation nicht berücksichtigt\\n img = Image.open(io.BytesIO(img_data))\\n ocr_text = pytesseract.image_to_string(img, lang=OCR_LANGUAGE)\\n # ← Keine Orientierungserkennung\\n```\\n\\n**vision.py:30-67**\\n```python\\ndef pdf_to_images(file_path, dpi=IMAGE_DPI):\\n import fitz\\n doc = fitz.open(file_path)\\n \\n for page_num in range(len(doc)):\\n page = doc[page_num]\\n mat = fitz.Matrix(dpi \/ 72, dpi \/ 72)\\n pix = page.get_pixmap(matrix=mat) # ← Rotation ignoriert\\n```\\n\\n### Systemzustand\\n\\n| Komponente | Status |\\n|------------|--------|\\n| PyMuPDF | ✓ 1.26.7 installiert |\\n| pytesseract | ✓ 0.3.13 installiert |\\n| Pillow | ✓ 12.0.0 installiert |\\n| **tesseract binary** | ❌ **NICHT INSTALLIERT** |\\n| OCR_ENABLED | True (aber funktioniert nicht!) |\\n\\n---\\n\\n## LÖSUNG: Mehrstufige Orientierungserkennung\\n\\n### Architektur\\n\\n```\\n┌─────────────────────────────────────────────────────────┐\\n│ Stufe 1: PDF-Metadaten (page.rotation) │\\n│ PyMuPDF liest \/Rotate Flag aus PDF │\\n│ → Schnell, kostenlos, 0ms │\\n└─────────────────────┬───────────────────────────────────┘\\n │ Falls rotation == 0\\n ▼\\n┌─────────────────────────────────────────────────────────┐\\n│ Stufe 2: Tesseract OSD (Orientation Script Detection) │\\n│ pytesseract.image_to_osd(img) │\\n│ → Erkennt 0°\/90°\/180°\/270°, Confidence-Score │\\n│ → ~50-100ms pro Seite │\\n└─────────────────────┬───────────────────────────────────┘\\n │ Falls Confidence < 2.0\\n ▼\\n┌─────────────────────────────────────────────────────────┐\\n│ Stufe 3: Vision-LLM Fallback (optional) │\\n│ \\\"Ist diese Seite korrekt orientiert?\\\" │\\n│ → Für Bilder ohne Text │\\n└─────────────────────────────────────────────────────────┘\\n```\\n\\n### Implementierung\\n\\n#### 1. Voraussetzung: Tesseract installieren\\n\\n```bash\\napt-get install tesseract-ocr tesseract-ocr-deu\\n```\\n\\n#### 2. Neue Datei: `\/var\/www\/scripts\/pipeline\/orientation.py`\\n\\n```python\\n\\\"\\\"\\\"\\nPage Orientation Detection Module\\nDetects and corrects rotated PDF pages.\\n\\\"\\\"\\\"\\n\\nimport io\\nfrom PIL import Image\\nimport pytesseract\\nimport fitz # PyMuPDF\\n\\nfrom db import db\\n\\n\\ndef detect_orientation(image_bytes: bytes) -> dict:\\n \\\"\\\"\\\"\\n Detect page orientation using Tesseract OSD.\\n \\n Args:\\n image_bytes: PNG\/JPEG image as bytes\\n \\n Returns:\\n dict: {\\n 'rotation': int (0, 90, 180, 270),\\n 'confidence': float,\\n 'script': str,\\n 'method': str ('osd' or 'fallback')\\n }\\n \\\"\\\"\\\"\\n try:\\n img = Image.open(io.BytesIO(image_bytes))\\n osd = pytesseract.image_to_osd(img, output_type=pytesseract.Output.DICT)\\n \\n return {\\n 'rotation': osd.get('rotate', 0),\\n 'confidence': osd.get('orientation_conf', 0.0),\\n 'script': osd.get('script', 'Unknown'),\\n 'method': 'osd'\\n }\\n except Exception as e:\\n db.log(\\\"WARNING\\\", f\\\"OSD detection failed: {e}\\\")\\n return {\\n 'rotation': 0,\\n 'confidence': 0.0,\\n 'script': 'Unknown',\\n 'method': 'fallback'\\n }\\n\\n\\ndef get_page_rotation(page) -> int:\\n \\\"\\\"\\\"\\n Get effective rotation for a PDF page.\\n \\n Combines PDF metadata rotation with detected orientation.\\n \\n Args:\\n page: PyMuPDF page object\\n \\n Returns:\\n int: Total rotation needed (0, 90, 180, 270)\\n \\\"\\\"\\\"\\n # Stufe 1: PDF-Metadaten\\n pdf_rotation = page.rotation # 0, 90, 180, 270\\n \\n if pdf_rotation != 0:\\n return pdf_rotation\\n \\n # Stufe 2: Tesseract OSD\\n pix = page.get_pixmap(dpi=150) # Lower DPI for speed\\n img_bytes = pix.tobytes(\\\"png\\\")\\n \\n detection = detect_orientation(img_bytes)\\n \\n if detection['confidence'] >= 2.0:\\n return detection['rotation']\\n \\n return 0\\n\\n\\ndef rotate_image(image_bytes: bytes, rotation: int) -> bytes:\\n \\\"\\\"\\\"\\n Rotate image by specified degrees.\\n \\n Args:\\n image_bytes: Original image\\n rotation: Degrees to rotate (90, 180, 270)\\n \\n Returns:\\n bytes: Rotated image as PNG\\n \\\"\\\"\\\"\\n if rotation == 0:\\n return image_bytes\\n \\n img = Image.open(io.BytesIO(image_bytes))\\n \\n # PIL rotation is counter-clockwise, PDF is clockwise\\n rotated = img.rotate(-rotation, expand=True)\\n \\n output = io.BytesIO()\\n rotated.save(output, format='PNG')\\n return output.getvalue()\\n```\\n\\n#### 3. Integration in extract.py\\n\\n**Änderung in `extract_pdf()` (Zeile 20-27 einfügen):**\\n\\n```python\\ndef extract_pdf(file_path):\\n import fitz\\n from orientation import get_page_rotation, rotate_image\\n \\n doc = fitz.open(file_path)\\n pages = []\\n \\n for page_num, page in enumerate(doc):\\n # NEU: Rotation erkennen\\n rotation = get_page_rotation(page)\\n \\n # Text mit korrekter Rotation extrahieren\\n if rotation != 0:\\n # Seite vor Extraktion rotieren\\n page.set_rotation(rotation)\\n \\n text = page.get_text()\\n \\n # OCR-Fallback mit rotiertem Bild\\n if OCR_ENABLED and len(text.strip()) < 50:\\n pix = page.get_pixmap(dpi=300)\\n img_data = pix.tobytes(\\\"png\\\")\\n \\n # NEU: Bild rotieren falls nötig\\n if rotation != 0:\\n img_data = rotate_image(img_data, rotation)\\n \\n img = Image.open(io.BytesIO(img_data))\\n ocr_text = pytesseract.image_to_string(img, lang=OCR_LANGUAGE)\\n```\\n\\n#### 4. Integration in vision.py\\n\\n**Änderung in `pdf_to_images()` (Zeile 46-54):**\\n\\n```python\\ndef pdf_to_images(file_path, dpi=IMAGE_DPI):\\n import fitz\\n from orientation import get_page_rotation, rotate_image\\n \\n doc = fitz.open(file_path)\\n pages = []\\n \\n for page_num in range(len(doc)):\\n page = doc[page_num]\\n \\n # NEU: Rotation erkennen\\n rotation = get_page_rotation(page)\\n \\n mat = fitz.Matrix(dpi \/ 72, dpi \/ 72)\\n pix = page.get_pixmap(matrix=mat)\\n img_bytes = pix.tobytes(IMAGE_FORMAT)\\n \\n # NEU: Bild rotieren falls nötig\\n if rotation != 0:\\n img_bytes = rotate_image(img_bytes, rotation)\\n db.log(\\\"INFO\\\", f\\\"Page {page_num+1} rotated by {rotation}°\\\")\\n```\\n\\n---\\n\\n## KONFIGURATION\\n\\n**config.py erweitern:**\\n\\n```python\\n# Rotation Detection Settings\\nROTATION_DETECTION_ENABLED = True\\nROTATION_OSD_CONFIDENCE_THRESHOLD = 2.0\\nROTATION_USE_VISION_FALLBACK = False # Für Bilder ohne Text\\n```\\n\\n---\\n\\n## TESTPLAN\\n\\n1. [ ] Tesseract installieren: `apt-get install tesseract-ocr tesseract-ocr-deu`\\n2. [ ] Tesseract verifizieren: `tesseract --version`\\n3. [ ] orientation.py erstellen\\n4. [ ] Unit-Tests für detect_orientation()\\n5. [ ] extract.py integrieren\\n6. [ ] vision.py integrieren\\n7. [ ] Test mit gedrehtem PDF:\\n - 90° gedrehte Seite → korrekt erkannt\\n - 180° gedrehte Seite → korrekt erkannt\\n - OCR-Text lesbar\\n - Vision-Analyse korrekt\\n8. [ ] Performance-Test: <100ms overhead pro Seite\\n\\n---\\n\\n## VALIDIERUNG\\n\\n```bash\\n# Tesseract OSD Test\\necho \\\"Test\\\" | tesseract stdin stdout --psm 0\\n\\n# Python-Test\\npython3 -c \\\"\\nimport pytesseract\\nfrom PIL import Image\\nimg = Image.new('RGB', (100, 100), 'white')\\nprint(pytesseract.image_to_osd(img))\\n\\\"\\n```\\n\\n---\\n\\n## ABHÄNGIGKEITEN\\n\\n| Paket | Version | Status |\\n|-------|---------|--------|\\n| tesseract-ocr | >= 4.0 | ❌ INSTALLIEREN |\\n| tesseract-ocr-deu | - | ❌ INSTALLIEREN |\\n| PyMuPDF | 1.26.7 | ✓ |\\n| pytesseract | 0.3.13 | ✓ |\\n| Pillow | 12.0.0 | ✓ |\\n\\n---\\n\\n## GESCHÄTZTER AUFWAND\\n\\n| Schritt | Zeit |\\n|---------|------|\\n| Tesseract installieren | 5 min |\\n| orientation.py erstellen | 30 min |\\n| extract.py anpassen | 15 min |\\n| vision.py anpassen | 15 min |\\n| config.py erweitern | 5 min |\\n| Tests | 30 min |\\n| **Gesamt** | **~100 min** |\",\n \"type\": \"ai_task\",\n \"status\": \"pending\",\n \"created_by\": \"mcp-tasks\",\n \"created_by_type\": \"ai\",\n \"parent_task_id\": null,\n \"due_date\": null,\n \"created_at\": \"2025-12-27T11:37:05.363073\",\n \"updated_at\": \"2025-12-27T11:37:05.363074\",\n \"completed_at\": null,\n \"metadata\": {}\n },\n \"message\": \"Task #442 created\"\n}"
}
]
}