#!/usr/bin/env python3 """ Dependency installer for OCR PDF to DOCX converter This script helps install the necessary dependencies for the OCR application. """ import os import sys import subprocess import platform import argparse def print_step(message): """Print a formatted step message""" print(f"\n\033[1;34m==>\033[0m \033[1m{message}\033[0m") def print_success(message): """Print a success message""" print(f"\033[1;32m✓\033[0m \033[1m{message}\033[0m") def print_error(message): """Print an error message""" print(f"\033[1;31m✗\033[0m \033[1;31m{message}\033[0m") def print_info(message): """Print an info message""" print(f"\033[1;33mℹ\033[0m {message}") def run_command(command, shell=False, check=True): """Run a command and return its output""" try: result = subprocess.run( command, shell=shell, check=check, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) return True, result.stdout except subprocess.CalledProcessError as e: return False, f"Command failed with error code {e.returncode}: {e.stderr}" except Exception as e: return False, str(e) def check_python_version(): """Check if Python version is compatible""" print_step("Checking Python version") version = sys.version_info if (version.major, version.minor) < (3, 11): print_error( f"Python 3.11+ is required; the pinned requirements do not resolve on older " f"versions. Detected {sys.version.split()[0]}" ) return False print_success(f"Python version is compatible: {sys.version.split()[0]}") return True def check_pip(): """Check if pip is installed""" print_step("Checking pip installation") success, output = run_command([sys.executable, "-m", "pip", "--version"], check=False) if not success: print_error("pip is not installed or not working properly") return False print_success(f"pip is installed: {output.strip()}") return True def install_core_requirements(): """Install core Python dependencies""" print_step("Installing core Python dependencies") # Everything comes from the pinned file, in one call. Installing # pdf2image and pytesseract first with floating bounds, as this used to, # pulls unpinned versions that the pins then have to correct. print_info("Installing pinned core dependencies from requirements.txt...") if not os.path.exists("requirements.txt"): print_error("requirements.txt not found — run this script from the repository root") return False success, output = run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]) if not success: print_error(f"Failed to install core requirements: {output}") return False print_success("Core Python dependencies installed successfully") return True def check_tesseract(): """Check if Tesseract OCR is installed""" print_step("Checking Tesseract OCR installation") success, output = run_command(["tesseract", "--version"], check=False) if not success: print_error("Tesseract OCR is not installed or not in PATH") system = platform.system().lower() if system == "darwin": print_info("Install Tesseract on macOS with: brew install tesseract") elif system == "linux": print_info("Install Tesseract on Linux with: sudo apt-get install tesseract-ocr") elif system == "windows": print_info("Install Tesseract on Windows from: https://github.com/UB-Mannheim/tesseract/wiki") return False print_success(f"Tesseract OCR is installed: {output.splitlines()[0] if output else 'Unknown version'}") return True def check_poppler(): """Check if Poppler is installed""" print_step("Checking Poppler installation") # Different commands for different platforms if platform.system().lower() == "windows": success, output = run_command(["where", "pdftoppm.exe"], check=False) else: success, output = run_command(["which", "pdftoppm"], check=False) if not success: print_error("Poppler is not installed or not in PATH") system = platform.system().lower() if system == "darwin": print_info("Install Poppler on macOS with: brew install poppler") elif system == "linux": print_info("Install Poppler on Linux with: sudo apt-get install poppler-utils") elif system == "windows": print_info("Install Poppler on Windows from: https://github.com/oschwartz10612/poppler-windows/releases") return False print_success("Poppler is installed") return True def install_specific_ocr_engine(engine): """Install a specific OCR engine""" print_step(f"Installing {engine} OCR engine") req_file = f"requirements-{engine}.txt" if os.path.exists(req_file): print_info(f"Installing from {req_file}...") success, output = run_command([sys.executable, "-m", "pip", "install", "-r", req_file]) if not success: print_error(f"Failed to install {engine} requirements: {output}") return False else: # Install based on engine name if requirements file doesn't exist packages = [] if engine == "easyocr": # Note: PyTorch might need separate installation depending on the system/CUDA packages = ["easyocr>=1.5.0"] elif engine == "pyocr": # The only engine without a requirements file: it is a single # package that wraps the tesseract binary. packages = ["pyocr>=0.8.0"] if packages: for pkg in packages: print_info(f"Installing {pkg}...") success, output = run_command([sys.executable, "-m", "pip", "install", pkg]) if not success: print_error(f"Failed to install {pkg}: {output}") # Optionally, add a note about manual installation (e.g., for PyTorch) if engine == "easyocr" and "torch" in pkg.lower(): print_info("EasyOCR requires PyTorch. If installation fails, please install PyTorch manually following instructions at https://pytorch.org/get-started/locally/") return False else: print_error(f"No installation method defined or requirements file found for {engine}") return False print_success(f"{engine} OCR engine dependencies installed successfully") return True def main(): """Main function""" parser = argparse.ArgumentParser(description="Install dependencies for OCR PDF to DOCX converter") # Updated choices to reflect supported engines parser.add_argument('--engine', choices=['tesseract', 'easyocr', 'pyocr', 'paddleocr', 'all'], default='tesseract', help="Specify OCR engine to install dependencies for (tesseract is core)") args = parser.parse_args() print("\n\033[1;36mOCR PDF to DOCX Converter - Dependency Installer\033[0m") print("="*60) # Check Python version if not check_python_version(): return 1 # Check pip if not check_pip(): return 1 # Install core requirements (including pdf2image) if not install_core_requirements(): return 1 # Check system dependencies check_tesseract() check_poppler() # Install specific OCR engine if requested if args.engine == 'all': for engine in ['easyocr', 'pyocr', 'paddleocr']: install_specific_ocr_engine(engine) elif args.engine != 'tesseract': # tesseract dependencies (pytesseract) are installed as core install_specific_ocr_engine(args.engine) print("\n\033[1;32m✓ Installation completed\033[0m") print("You can now run the application with: python app.py") return 0 if __name__ == "__main__": sys.exit(main())