Files
crm.clientright.ru/ticket_form/N8N_PDF_COMPRESS.md
Fedor de011efba9 fix: исправлен конфликт имён переменных в loadDraft (claimId -> finalClaimId)
- Исправлена ошибка ReferenceError при загрузке черновиков
- Переименована локальная переменная claimId в finalClaimId для избежания конфликта с параметром функции
- Обновлена логика извлечения claim_id из разных источников (claim.claim_id, payload.claim_id, body.claim_id, claim.id)
- Добавлен fallback на параметр claimId функции для надёжности
2025-11-19 23:33:52 +03:00

257 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🗜️ PDF Compression в n8n
## 📋 Проблема
Пользователь загружает PDF 5-10 MB → долгая обработка OCR
## ✅ Решение: 2-уровневая система
---
## 🎯 Уровень 1: Frontend (React)
**Что делаем:**
- JPG/PNG → сжатие до 2MB → конвертация в PDF
- PDF < 5MB пропускаем
- PDF > 10MB → **отклоняем** с сообщением
**Код:** `frontend/src/utils/pdfConverter.ts` ✅ УЖЕ ГОТОВО
---
## 🎯 Уровень 2: Backend (n8n)
### Workflow для сжатия PDF > 5MB
```
Webhook (file upload)
IF Node: file_size > 5 MB?
├─ FALSE → S3 Upload (оригинал)
└─ TRUE → Python Code Node (compress)
S3 Upload (compressed)
```
---
## 🐍 Python Code Node - PDF Compression
### Установка библиотеки в n8n
```bash
# В контейнере n8n
docker exec -it <n8n_container_name> sh
apk add --no-cache python3 py3-pip
pip3 install pypdf
```
### Code Node конфигурация
**Language:** Python
**Mode:** Run Once for All Items
**Code:**
```python
import io
from pypdf import PdfReader, PdfWriter
# Получаем binary data из предыдущей ноды
input_data = items[0].binary['data']
pdf_bytes = input_data
# Читаем PDF
reader = PdfReader(io.BytesIO(pdf_bytes))
writer = PdfWriter()
# Копируем страницы с оптимизацией
for page in reader.pages:
# Удаляем неиспользуемые объекты
page.compress_content_streams()
writer.add_page(page)
# Применяем сжатие
writer.compress_identical_objects()
writer.remove_duplication()
# Сжимаем изображения (если есть)
for page in writer.pages:
for img in page.images:
img.replace(img.image, quality=70)
# Выводим в bytes
output = io.BytesIO()
writer.write(output)
compressed_bytes = output.getvalue()
# Логируем результат
original_size = len(pdf_bytes) / (1024 * 1024)
compressed_size = len(compressed_bytes) / (1024 * 1024)
compression_ratio = ((original_size - compressed_size) / original_size) * 100
print(f"✅ Compressed: {original_size:.2f}MB → {compressed_size:.2f}MB ({compression_ratio:.1f}% reduction)")
# Возвращаем binary data
return {
'binary': {
'data': compressed_bytes
},
'json': {
'original_size_mb': round(original_size, 2),
'compressed_size_mb': round(compressed_size, 2),
'compression_ratio': round(compression_ratio, 1),
'success': True
}
}
```
---
## 🔧 Вариант 2: Execute Command (Ghostscript)
**Требует:** `ghostscript` установлен в системе
### Execute Command Node:
```bash
#!/bin/bash
INPUT="/tmp/input_{{ $json.file_id }}.pdf"
OUTPUT="/tmp/output_{{ $json.file_id }}.pdf"
# Сохраняем binary в файл
echo "{{ $binary.data }}" | base64 -d > "$INPUT"
# Сжимаем через Ghostscript
gs -sDEVICE=pdfwrite \
-dCompatibilityLevel=1.4 \
-dPDFSETTINGS=/ebook \
-dNOPAUSE \
-dQUIET \
-dBATCH \
-sOutputFile="$OUTPUT" \
"$INPUT"
# Выводим compressed PDF
cat "$OUTPUT" | base64
# Cleanup
rm -f "$INPUT" "$OUTPUT"
```
**Параметры `-dPDFSETTINGS`:**
- `/screen` - 72 DPI (минимальное качество, максимальное сжатие)
- `/ebook` - 150 DPI ⭐ **рекомендуется**
- `/printer` - 300 DPI
- `/prepress` - 300 DPI (максимальное качество)
---
## 🔄 Полный Workflow
### 1. Webhook (File Upload)
**Input:**
```json
{
"claim_id": "CLM-2025-10-26-ABC123",
"file_type": "policy_scan",
"filename": "policy.pdf",
"voucher": "E1000-302372730",
"session_id": "sess-xyz-456"
}
```
**Binary Data:** `data` (PDF file)
---
### 2. IF Node: Check File Size
**Condition:**
```
{{ $binary.data.length }} > 5242880
```
(5MB = 5 * 1024 * 1024 bytes)
---
### 3a. FALSE → Direct Upload
**S3 Upload Node** → PostgreSQL
---
### 3b. TRUE → Compress First
```
Python Code (compress)
Set Binary Data
S3 Upload (compressed)
PostgreSQL (update file_size)
```
---
## 📊 Результаты сжатия
| Метод | Скорость | Сжатие | Качество |
|-------|----------|--------|----------|
| **pypdf** | Быстро | 30-50% | Хорошее ⭐ |
| **Ghostscript /ebook** | Средне | 50-70% | Среднее |
| **Ghostscript /screen** | Средне | 70-85% | Низкое |
| **Frontend (jspdf)** | Моментально | 60-80% | Хорошее ✅ |
---
## 🎯 Итоговая стратегия
```
📱 Пользователь загружает файл
🔍 Frontend проверка:
├─ JPG/PNG → compress + convert → PDF (✅ готово)
├─ PDF < 5MB → отправить как есть
├─ PDF 5-10MB → отправить (n8n сожмёт)
└─ PDF > 10MB → ❌ отклонить
🚀 n8n workflow:
├─ file_size < 5MB → S3 + OCR
└─ file_size > 5MB → Python compress → S3 + OCR
```
---
## 🧪 Тестирование
### curl пример:
```bash
# Создаём большой PDF для теста
curl -o large.pdf https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf
# Отправляем в n8n
curl -X POST \
-F "claim_id=CLM-TEST-001" \
-F "file_type=policy_scan" \
-F "fileInput=@large.pdf" \
-F "voucher=TEST-123" \
-F "session_id=sess-test" \
https://n8n.clientright.pro/webhook/7e2abc64-eaca-4671-86e4-12786700fe95
```
---
## ✅ Готово!
**Frontend:** ✅ Ограничение 10MB + предупреждение
**n8n:** ⏳ Нужно добавить Python Code Node
**Следующий шаг:** Добавить Python Code Node в workflow для файлов > 5MB