ocr concurrently
Build and Push Docker Images / build-and-push (push) Successful in 24s

This commit is contained in:
2025-07-17 19:20:55 +02:00
parent fd6555dc7f
commit a7d832c894
+78 -22
View File
@@ -1,8 +1,11 @@
import os import os
import tempfile import tempfile
import logging import logging
import asyncio
from typing import List, Optional from typing import List, Optional
from pathlib import Path from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import time
from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
@@ -40,11 +43,51 @@ async def root():
async def health_check(): async def health_check():
return {"status": "healthy", "service": "OCR API"} return {"status": "healthy", "service": "OCR API"}
async def process_pdf_with_ocr(pdf_path: str) -> OCRResponse: def process_single_page(args):
""" """
Process a PDF file and extract text using OCR Process a single page with OCR (runs in thread pool)
"""
page_num, image = args
try:
logger.info(f"Processing page {page_num + 1}")
# Perform OCR on the image
ocr_data = pytesseract.image_to_data(image, output_type=pytesseract.Output.DICT)
# Extract text and confidence scores
page_text = []
total_confidence = 0
confidence_count = 0
for j in range(len(ocr_data['text'])):
if int(ocr_data['conf'][j]) > 0: # Filter out low confidence results
page_text.append(ocr_data['text'][j])
total_confidence += float(ocr_data['conf'][j])
confidence_count += 1
page_text = ' '.join(page_text).strip()
avg_confidence = total_confidence / confidence_count if confidence_count > 0 else 0
return {
'page_num': page_num,
'text': page_text,
'confidence': avg_confidence,
'success': True
}
except Exception as e:
logger.error(f"Error processing page {page_num + 1}: {str(e)}")
return {
'page_num': page_num,
'text': '',
'confidence': 0,
'success': False,
'error': str(e)
}
async def process_pdf_with_ocr(pdf_path: str, max_workers: int = None) -> OCRResponse:
"""
Process a PDF file and extract text using OCR with concurrent page processing
""" """
import time
start_time = time.time() start_time = time.time()
try: try:
@@ -55,34 +98,45 @@ async def process_pdf_with_ocr(pdf_path: str) -> OCRResponse:
if not images: if not images:
raise HTTPException(status_code=400, detail="Could not extract images from PDF") raise HTTPException(status_code=400, detail="Could not extract images from PDF")
# Extract text from each page # Determine optimal number of workers
if max_workers is None:
max_workers = min(len(images), os.cpu_count() or 4)
logger.info(f"Processing {len(images)} pages with {max_workers} workers")
# Process pages concurrently using ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# Create tasks for each page
page_tasks = [(i, image) for i, image in enumerate(images)]
# Submit all tasks and wait for completion
results = list(executor.map(process_single_page, page_tasks))
# Sort results by page number and combine
results.sort(key=lambda x: x['page_num'])
all_text = [] all_text = []
total_confidence = 0 total_confidence = 0
confidence_count = 0 confidence_count = 0
successful_pages = 0
for i, image in enumerate(images): for result in results:
logger.info(f"Processing page {i+1}/{len(images)}") if result['success']:
successful_pages += 1
# Perform OCR on the image if result['text']:
ocr_data = pytesseract.image_to_data(image, output_type=pytesseract.Output.DICT) all_text.append(f"--- Page {result['page_num'] + 1} ---\n{result['text']}")
total_confidence += result['confidence']
# Extract text and confidence scores
page_text = []
for j in range(len(ocr_data['text'])):
if int(ocr_data['conf'][j]) > 0: # Filter out low confidence results
page_text.append(ocr_data['text'][j])
total_confidence += float(ocr_data['conf'][j])
confidence_count += 1 confidence_count += 1
else:
page_text = ' '.join(page_text).strip() logger.warning(f"Page {result['page_num'] + 1} failed: {result.get('error', 'Unknown error')}")
if page_text:
all_text.append(f"--- Page {i+1} ---\n{page_text}")
# Calculate average confidence # Calculate average confidence
avg_confidence = total_confidence / confidence_count if confidence_count > 0 else None avg_confidence = total_confidence / confidence_count if confidence_count > 0 else None
processing_time = time.time() - start_time processing_time = time.time() - start_time
logger.info(f"Completed processing {successful_pages}/{len(images)} pages in {processing_time:.2f}s")
return OCRResponse( return OCRResponse(
text='\n\n'.join(all_text), text='\n\n'.join(all_text),
pages=len(images), pages=len(images),
@@ -97,12 +151,14 @@ async def process_pdf_with_ocr(pdf_path: str) -> OCRResponse:
@app.post("/ocr/pdf", response_model=OCRResponse) @app.post("/ocr/pdf", response_model=OCRResponse)
async def extract_text_from_pdf( async def extract_text_from_pdf(
file: UploadFile = File(...), file: UploadFile = File(...),
max_workers: int = None,
background_tasks: BackgroundTasks = None background_tasks: BackgroundTasks = None
): ):
""" """
Extract text from a PDF file using OCR Extract text from a PDF file using OCR with concurrent processing
- **file**: PDF file to process - **file**: PDF file to process
- **max_workers**: Maximum number of concurrent workers (default: min(pages, CPU cores))
- Returns extracted text with metadata - Returns extracted text with metadata
""" """
@@ -130,7 +186,7 @@ async def extract_text_from_pdf(
try: try:
# Process the PDF # Process the PDF
result = await process_pdf_with_ocr(temp_file_path) result = await process_pdf_with_ocr(temp_file_path, max_workers)
# Clean up temporary file # Clean up temporary file
background_tasks.add_task(os.unlink, temp_file_path) background_tasks.add_task(os.unlink, temp_file_path)