feat(kreuzberg): add multi-file processing and PaddleOCR backend
- Add extract_files() for processing multiple files one by one - Support comma-separated and JSON array input - Switch OCR backend from Tesseract to PaddleOCR (better accuracy) - Update tool description
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
1. **Admin Panel** → **Tools** → **Create Tool**
|
1. **Admin Panel** → **Tools** → **Create Tool**
|
||||||
2. **Name**: `Kreuzberg OCR`
|
2. **Name**: `Kreuzberg OCR`
|
||||||
3. **Description**: `Extract text from documents (PDF, images, scanned pages) using Kreuzberg OCR. Call `extract_file("filename")` on attached files.`
|
3. **Description**: `Extract text from documents using Kreuzberg OCR (PaddleOCR backend). Single: extract_file("file") or Multiple: extract_files("file1,file2")`
|
||||||
4. **Coller le code ci-dessous**
|
4. **Coller le code ci-dessous**
|
||||||
5. **Save and Activate**
|
5. **Save and Activate**
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class Tools:
|
|||||||
|
|
||||||
def extract_file(self, filename: str) -> str:
|
def extract_file(self, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Extract text from a file using Kreuzberg OCR.
|
Extract text from a single file using Kreuzberg OCR.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filename: The filename shown in the chat (e.g., "document.pdf", "image.jpg")
|
filename: The filename shown in the chat (e.g., "document.pdf", "image.jpg")
|
||||||
@@ -53,6 +53,58 @@ class Tools:
|
|||||||
Returns:
|
Returns:
|
||||||
Extracted text content with markdown formatting
|
Extracted text content with markdown formatting
|
||||||
"""
|
"""
|
||||||
|
return self._extract_single_file(filename)
|
||||||
|
|
||||||
|
def extract_files(self, filenames: str) -> str:
|
||||||
|
"""
|
||||||
|
Extract text from multiple files, one at a time.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filenames: Comma-separated list of filenames (e.g., "doc1.pdf,doc2.jpg")
|
||||||
|
or JSON array string (e.g., '["doc1.pdf","doc2.jpg"]')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Combined extracted text from all files, processed sequentially
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
|
||||||
|
filenames = filenames.strip()
|
||||||
|
|
||||||
|
if not filenames:
|
||||||
|
return "❌ No filenames provided. Usage: extract_files(\"file1.pdf,file2.jpg\")"
|
||||||
|
|
||||||
|
if filenames.startswith('['):
|
||||||
|
try:
|
||||||
|
file_list = json.loads(filenames)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return f"❌ Invalid JSON array: {filenames}"
|
||||||
|
else:
|
||||||
|
file_list = [f.strip() for f in filenames.split(',')]
|
||||||
|
|
||||||
|
if not file_list:
|
||||||
|
return "❌ No files to process"
|
||||||
|
|
||||||
|
if len(file_list) == 1:
|
||||||
|
return self._extract_single_file(file_list[0])
|
||||||
|
|
||||||
|
results = []
|
||||||
|
total = len(file_list)
|
||||||
|
|
||||||
|
for i, filename in enumerate(file_list, 1):
|
||||||
|
filename = filename.strip()
|
||||||
|
if not filename:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if total > 1:
|
||||||
|
results.append(f"--- Document {i}/{total}: `{filename}` ---")
|
||||||
|
|
||||||
|
result = self._extract_single_file(filename)
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
return "\n\n".join(results)
|
||||||
|
|
||||||
|
def _extract_single_file(self, filename: str) -> str:
|
||||||
|
"""Internal method to extract text from a single file"""
|
||||||
try:
|
try:
|
||||||
file_path = self._find_file(filename)
|
file_path = self._find_file(filename)
|
||||||
|
|
||||||
@@ -89,6 +141,7 @@ class Tools:
|
|||||||
files=files,
|
files=files,
|
||||||
data=data,
|
data=data,
|
||||||
timeout=300
|
timeout=300
|
||||||
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
result = response.json()
|
result = response.json()
|
||||||
@@ -96,10 +149,8 @@ class Tools:
|
|||||||
if 'document' in result:
|
if 'document' in result:
|
||||||
content = result['document'].get('md_content', '')
|
content = result['document'].get('md_content', '')
|
||||||
if content and len(content.strip()) > 10:
|
if content and len(content.strip()) > 10:
|
||||||
# Clean up the content
|
|
||||||
content = self._clean_content(content)
|
content = self._clean_content(content)
|
||||||
|
|
||||||
# Truncate if too long (LLM context limit)
|
|
||||||
if len(content) > 15000:
|
if len(content) > 15000:
|
||||||
content = content[:15000] + "\n\n... (document truncated - too long for context)"
|
content = content[:15000] + "\n\n... (document truncated - too long for context)"
|
||||||
|
|
||||||
@@ -290,7 +341,7 @@ class Tools:
|
|||||||
# OpenWebUI Tool Functions
|
# OpenWebUI Tool Functions
|
||||||
def extract_file(filename: str) -> str:
|
def extract_file(filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Extract text from a file using Kreuzberg OCR.
|
Extract text from a single file using Kreuzberg OCR.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filename: The filename or UUID from the chat (e.g., "document.pdf", "abc123_document.pdf")
|
filename: The filename or UUID from the chat (e.g., "document.pdf", "abc123_document.pdf")
|
||||||
@@ -301,6 +352,20 @@ def extract_file(filename: str) -> str:
|
|||||||
tools = Tools()
|
tools = Tools()
|
||||||
return tools.extract_file(filename)
|
return tools.extract_file(filename)
|
||||||
|
|
||||||
|
def extract_files(filenames: str) -> str:
|
||||||
|
"""
|
||||||
|
Extract text from multiple files, one at a time.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filenames: Comma-separated list (e.g., "doc1.pdf,doc2.jpg")
|
||||||
|
or JSON array (e.g., '["doc1.pdf","doc2.jpg"]')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Combined extracted text from all files
|
||||||
|
"""
|
||||||
|
tools = Tools()
|
||||||
|
return tools.extract_files(filenames)
|
||||||
|
|
||||||
def list_recent_files(count: int = 10) -> str:
|
def list_recent_files(count: int = 10) -> str:
|
||||||
"""List recent uploaded files"""
|
"""List recent uploaded files"""
|
||||||
tools = Tools()
|
tools = Tools()
|
||||||
@@ -316,13 +381,19 @@ def search_files(pattern: str) -> str:
|
|||||||
|
|
||||||
After installing and activating the tool:
|
After installing and activating the tool:
|
||||||
|
|
||||||
### Extract text from a file:
|
### Extract text from a single file:
|
||||||
```
|
```
|
||||||
extract_file("document.pdf")
|
extract_file("document.pdf")
|
||||||
extract_file("9af3d665-998b-4577-b893-340cb1c28385_document.pdf")
|
extract_file("9af3d665-998b-4577-b893-340cb1c28385_document.pdf")
|
||||||
extract_file("image.jpg")
|
extract_file("image.jpg")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Extract from multiple files (processed one by one):
|
||||||
|
```
|
||||||
|
extract_files("doc1.pdf,doc2.jpg")
|
||||||
|
extract_files('["page1.jpg","page2.jpg","page3.jpg"]')
|
||||||
|
```
|
||||||
|
|
||||||
### List recent files:
|
### List recent files:
|
||||||
```
|
```
|
||||||
list_recent_files()
|
list_recent_files()
|
||||||
@@ -337,4 +408,4 @@ search_files("polz")
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Updated 11 April 2026 - Added image preprocessing (grayscale + contrast) for better OCR quality*
|
*Updated 11 April 2026 - Added PaddleOCR backend + multi-file processing*
|
||||||
Reference in New Issue
Block a user