Add environment variable support for API key and max workers in OCR API; implement API key verification for secure access
Build and Push Docker Images / build-and-push (push) Successful in 19s

This commit is contained in:
2025-07-17 19:26:11 +02:00
parent a7d832c894
commit a97392f421
4 changed files with 71 additions and 5 deletions
+5
View File
@@ -7,6 +7,11 @@ services:
- "8000:8000" - "8000:8000"
environment: environment:
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
- DEFAULT_MAX_WORKERS=${DEFAULT_MAX_WORKERS:-4}
- API_KEY=${API_KEY:-}
- REQUIRE_API_KEY=${REQUIRE_API_KEY:-true}
env_file:
- .env
volumes: volumes:
# Optional: mount a directory for testing with sample files # Optional: mount a directory for testing with sample files
- ./test_files:/app/test_files:ro - ./test_files:/app/test_files:ro
+13
View File
@@ -0,0 +1,13 @@
# OCR API Configuration
# API Authentication
API_KEY=your-secret-api-key-here
REQUIRE_API_KEY=true
# Performance Configuration
DEFAULT_MAX_WORKERS=4
# Optional: Override default settings
# LOG_LEVEL=INFO
# HOST=0.0.0.0
# PORT=8000
+47 -5
View File
@@ -7,18 +7,31 @@ from pathlib import Path
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
import time import time
from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks, Depends, Header
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel from pydantic import BaseModel
import pytesseract import pytesseract
from PIL import Image from PIL import Image
from pdf2image import convert_from_path from pdf2image import convert_from_path
import uvicorn import uvicorn
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Configure logging # Configure logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Environment variables
DEFAULT_MAX_WORKERS = int(os.getenv("DEFAULT_MAX_WORKERS", "4"))
API_KEY = os.getenv("API_KEY")
REQUIRE_API_KEY = os.getenv("REQUIRE_API_KEY", "true").lower() == "true"
# Security
security = HTTPBearer(auto_error=False)
app = FastAPI( app = FastAPI(
title="OCR API", title="OCR API",
description="API for extracting text from PDF files using OCR", description="API for extracting text from PDF files using OCR",
@@ -35,6 +48,33 @@ class ErrorResponse(BaseModel):
error: str error: str
detail: str detail: str
async def verify_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
"""
Verify API key authentication
"""
if not REQUIRE_API_KEY:
return True
if not API_KEY:
logger.warning("API_KEY not set in environment variables")
return True
if not credentials:
raise HTTPException(
status_code=401,
detail="API key required",
headers={"WWW-Authenticate": "Bearer"},
)
if credentials.credentials != API_KEY:
raise HTTPException(
status_code=401,
detail="Invalid API key",
headers={"WWW-Authenticate": "Bearer"},
)
return True
@app.get("/") @app.get("/")
async def root(): async def root():
return {"message": "OCR API is running. Use /docs for API documentation."} return {"message": "OCR API is running. Use /docs for API documentation."}
@@ -100,7 +140,7 @@ async def process_pdf_with_ocr(pdf_path: str, max_workers: int = None) -> OCRRes
# Determine optimal number of workers # Determine optimal number of workers
if max_workers is None: if max_workers is None:
max_workers = min(len(images), os.cpu_count() or 4) max_workers = min(len(images), DEFAULT_MAX_WORKERS)
logger.info(f"Processing {len(images)} pages with {max_workers} workers") logger.info(f"Processing {len(images)} pages with {max_workers} workers")
@@ -152,13 +192,14 @@ async def process_pdf_with_ocr(pdf_path: str, max_workers: int = None) -> OCRRes
async def extract_text_from_pdf( async def extract_text_from_pdf(
file: UploadFile = File(...), file: UploadFile = File(...),
max_workers: int = None, max_workers: int = None,
background_tasks: BackgroundTasks = None background_tasks: BackgroundTasks = None,
_: bool = Depends(verify_api_key)
): ):
""" """
Extract text from a PDF file using OCR with concurrent processing 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)) - **max_workers**: Maximum number of concurrent workers (default: from DEFAULT_MAX_WORKERS env var)
- Returns extracted text with metadata - Returns extracted text with metadata
""" """
@@ -206,7 +247,8 @@ async def extract_text_from_pdf(
@app.post("/ocr/image", response_model=OCRResponse) @app.post("/ocr/image", response_model=OCRResponse)
async def extract_text_from_image( async def extract_text_from_image(
file: UploadFile = File(...), file: UploadFile = File(...),
background_tasks: BackgroundTasks = None background_tasks: BackgroundTasks = None,
_: bool = Depends(verify_api_key)
): ):
""" """
Extract text from an image file using OCR Extract text from an image file using OCR
+6
View File
@@ -7,10 +7,16 @@ This script demonstrates how to use the OCR API endpoints
import requests import requests
import json import json
import sys import sys
import os
from pathlib import Path from pathlib import Path
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# API base URL # API base URL
BASE_URL = "http://localhost:8000" BASE_URL = "http://localhost:8000"
API_KEY = os.getenv("API_KEY")
def test_health(): def test_health():
"""Test the health endpoint""" """Test the health endpoint"""