Protokoll #21922

ID21922
Zeitstempel2025-12-27 11:37:05.332622
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens4,982 (Input: 2,380, Output: 2,602)
Dauer100 ms
Request-Zeit2025-12-27 11:37:05.332622
Response-Zeit2025-12-27 11:37:05.432389

Request

{
    "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"
    }
}

Response

{
    "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}"
        }
    ]
}
← Vorheriger Zur Liste Nächster →