Files
openclaw-qqlobster-skills/skills/super-ocr/scripts/dependencies.py
T

343 lines
10 KiB
Python

#!/usr/bin/env python3
"""
Dependencies checker and auto-installer for Super OCR
This module handles:
- Dependency detection
- Auto-installation of missing packages
- Version checking
- Clear error messages with troubleshooting steps
"""
import importlib.util
import os
import subprocess
import sys
from typing import Dict, List, Optional, Tuple
# Dependency definitions
DEPENDENCIES = {
'paddleocr': {
'package': 'paddleocr',
'required': ['paddleocr'],
'optional': [],
'install_cmd': 'pip install paddleocr paddlepaddle',
'check_fn': 'check_paddleocr'
},
'pytesseract': {
'package': 'pytesseract',
'required': ['pytesseract', 'PIL', 'cv2', 'numpy'],
'optional': [],
'install_cmd': 'pip install pytesseract pillow opencv-python numpy',
'check_fn': 'check_pytesseract'
},
'common': {
'package': 'common',
'required': ['pathlib', 'argparse', 'logging'],
'optional': ['yaml'],
'install_cmd': None,
'check_fn': None
}
}
def _check_module(module_name: str) -> bool:
"""Check if a Python module is available"""
return importlib.util.find_spec(module_name) is not None
def check_paddleocr() -> Tuple[bool, List[str]]:
"""Check PaddleOCR and paddlepaddle availability"""
missing = []
if not _check_module('paddleocr'):
missing.append('paddleocr')
# Check paddlepaddle (the actual library)
if not _check_module('paddle'):
missing.append('paddlepaddle')
return len(missing) == 0, missing
def check_pytesseract() -> Tuple[bool, List[str]]:
"""Check Tesseract-related dependencies"""
missing = []
# Python packages
for pkg in ['pytesseract', 'PIL', 'cv2', 'numpy']:
if not _check_module(pkg):
missing.append(pkg)
return len(missing) == 0, missing
def check_tesseract_binary() -> Tuple[bool, str]:
"""Check if tesseract binary is installed"""
try:
result = subprocess.run(
['tesseract', '--version'],
capture_output=True,
text=True,
timeout=5
)
return True, result.stdout.strip()
except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError):
return False, ""
def check_dependency(dep_name: str) -> Tuple[bool, List[str], Optional[str]]:
"""
Check a specific dependency.
Returns:
(is_available, missing_items, installation_hint)
"""
if dep_name not in DEPENDENCIES:
return False, [], None
dep = DEPENDENCIES[dep_name]
# Check if we have a custom check function
if dep.get('check_fn'):
check_fn_name = dep['check_fn']
check_fns = {
'check_paddleocr': check_paddleocr,
'check_pytesseract': check_pytesseract,
'check_tesseract_binary': check_tesseract_binary
}
if check_fn_name in check_fns:
is_available, result = check_fns[check_fn_name]()
return is_available, result if isinstance(result, list) else [], None
# Generic check for required packages
missing = []
for pkg in dep.get('required', []):
if not _check_module(pkg):
missing.append(pkg)
return len(missing) == 0, missing, dep.get('install_cmd')
def auto_install(dependency: str) -> bool:
"""
Auto-install a dependency.
Returns:
True if installation succeeded, False otherwise
"""
if dependency not in DEPENDENCIES:
print(f"[ERROR] Unknown dependency: {dependency}")
return False
dep = DEPENDENCIES[dependency]
install_cmd = dep.get('install_cmd')
if not install_cmd:
print(f"[INFO] No auto-install command for {dependency}")
return False
print(f"[INFO] Installing {dependency}...")
print(f" Command: {install_cmd}")
try:
result = subprocess.run(
install_cmd.split(),
capture_output=True,
text=True,
timeout=120
)
if result.returncode == 0:
print(f"[OK] {dependency} installed successfully")
return True
else:
print(f"[ERROR] Installation failed:")
print(f" {result.stderr}")
return False
except Exception as e:
print(f"[ERROR] Auto-install failed: {e}")
return False
def print_installation_guide() -> None:
"""Print comprehensive installation instructions"""
print("\n" + "=" * 60)
print("Super OCR Dependencies Installation Guide")
print("=" * 60)
print("\n[OPTION 1] Install PaddleOCR (Recommended for Chinese)")
print("-" * 40)
print("pip install paddleocr paddlepaddle")
print()
print("For macOS/Linux (CPU only):")
print(" pip install paddleocr paddlepaddle")
print()
print("For Windows (CPU only):")
print(" pip install paddleocr paddlepaddle")
print()
print("For GPU support:")
print(" # CUDA 11.2")
print(" pip install paddlepaddle-gpu==2.4.0 -f https://www.paddlepaddle.org.cn/whl/stable.html")
print(" # CUDA 11.6")
print(" pip install paddlepaddle-gpu==2.4.0 -f https://www.paddlepaddle.org.cn/whl/lite.html")
print("\n[OPTION 2] Install Tesseract")
print("-" * 40)
print("macOS:")
print(" brew install tesseract")
print()
print("Ubuntu/Debian:")
print(" sudo apt update && sudo apt install tesseract-ocr")
print()
print("Windows:")
print(" Download from: https://github.com/UB-Mannheim/tesseract/wiki")
print("\n[OPTION 3] Install Tesseract Python bindings")
print("-" * 40)
print("pip install pytesseract pillow opencv-python numpy")
print("\n[OPTION 4] Install all at once")
print("-" * 40)
print("pip install paddleocr paddlepaddle pytesseract pillow opencv-python numpy")
print("\n" + "=" * 60)
def check_all_dependencies(interactive: bool = True) -> bool:
"""
Check all dependencies and optionally install missing ones.
Returns:
True if all dependencies are satisfied
"""
print("\n" + "=" * 60)
print("Checking Super OCR Dependencies")
print("=" * 60)
all_ok = True
missing = []
# Check PaddleOCR
print("\n[1/3] Checking PaddleOCR...")
ok, missing_pkgs = check_paddleocr()
if ok:
print("[OK] PaddleOCR is available")
else:
print(f"[MISSING] Missing: {', '.join(missing_pkgs)}")
all_ok = False
missing.extend(missing_pkgs)
# Check Tesseract binary
print("\n[2/3] Checking Tesseract binary...")
ok, info = check_tesseract_binary()
if ok:
print(f"[OK] Tesseract is available: {info.split()[2] if info else 'unknown'}")
else:
print("[MISSING] Tesseract binary not found")
print(" Install: brew install tesseract (macOS) or apt install tesseract-ocr (Ubuntu)")
all_ok = False
# Check Tesseract Python bindings
print("\n[3/3] Checking Tesseract Python bindings...")
ok, missing_pkgs = check_pytesseract()
if ok:
print("[OK] Tesseract Python bindings are available")
else:
print(f"[MISSING] Missing: {', '.join(missing_pkgs)}")
all_ok = False
# Summary
print("\n" + "=" * 60)
if all_ok:
print("[OK] All dependencies satisfied!")
return True
else:
print("[WARNING] Some dependencies are missing")
print(f"Missing: {', '.join(missing)}")
if interactive:
response = input("\nAuto-install missing dependencies? [y/N]: ")
if response.lower() == 'y':
# Install PaddleOCR if missing
if 'paddleocr' in missing or 'paddlepaddle' in missing:
print("\n[INSTALL] Installing PaddleOCR...")
auto_install('paddleocr')
# Install Tesseract packages if missing
if any(pkg in missing for pkg in ['pytesseract', 'PIL', 'cv2', 'numpy']):
print("\n[INSTALL] Installing Tesseract packages...")
auto_install('pytesseract')
print("\n" + "=" * 60)
print("Manual Installation:")
print("=" * 60)
print_installation_guide()
return False
def main():
import argparse
parser = argparse.ArgumentParser(
description='Super OCR Dependencies Checker and Installer'
)
parser.add_argument(
'--check', '-c',
action='store_true',
help='Check dependencies without installing'
)
parser.add_argument(
'--install', '-i',
action='store_true',
help='Auto-install missing dependencies'
)
parser.add_argument(
'--dependency', '-d',
choices=['paddleocr', 'pytesseract', 'all'],
default='all',
help='Specific dependency to check/install'
)
parser.add_argument(
'--guide', '-g',
action='store_true',
help='Show installation guide only'
)
parser.add_argument(
'--quiet', '-q',
action='store_true',
help='Suppress output'
)
args = parser.parse_args()
if args.guide:
print_installation_guide()
return 0
if args.check or args.install:
if args.dependency == 'all':
success = check_all_dependencies(interactive=not args.quiet and not args.install)
else:
ok, missing, cmd = check_dependency(args.dependency)
if ok:
print(f"[OK] {args.dependency} is available")
return 0
else:
print(f"[MISSING] {args.dependency}: {', '.join(missing)}")
if args.install:
success = auto_install(args.dependency)
return 0 if success else 1
return 1
else:
# Default: interactive check
success = check_all_dependencies(interactive=True)
return 0 if success else 1
if __name__ == '__main__':
sys.exit(main())