| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import argparse |
| import logging |
| import subprocess |
| import sys |
| import time |
| import warnings |
| from threading import Thread |
|
|
| import requests |
|
|
| from ._models import ( |
| ChartParsing, |
| DocImgOrientationClassification, |
| DocVLM, |
| FormulaRecognition, |
| LayoutDetection, |
| SealTextDetection, |
| TableCellsDetection, |
| TableClassification, |
| TableStructureRecognition, |
| TextDetection, |
| TextImageUnwarping, |
| TextLineOrientationClassification, |
| TextRecognition, |
| ) |
| from ._pipelines import ( |
| DocPreprocessor, |
| DocUnderstanding, |
| FormulaRecognitionPipeline, |
| PaddleOCR, |
| PaddleOCRVL, |
| PPChatOCRv4Doc, |
| PPDocTranslation, |
| PPStructureV3, |
| SealRecognition, |
| TableRecognitionPipelineV2, |
| ) |
| from ._version import version |
| from ._utils.deprecation import CLIDeprecationWarning |
| from ._utils.logging import logger |
|
|
|
|
| def _register_pipelines(subparsers): |
| for cls in [ |
| DocPreprocessor, |
| DocUnderstanding, |
| FormulaRecognitionPipeline, |
| PaddleOCR, |
| PaddleOCRVL, |
| PPChatOCRv4Doc, |
| PPDocTranslation, |
| PPStructureV3, |
| SealRecognition, |
| TableRecognitionPipelineV2, |
| ]: |
| subcommand_executor = cls.get_cli_subcommand_executor() |
| subparser = subcommand_executor.add_subparser(subparsers) |
| subparser.set_defaults(executor=subcommand_executor.execute_with_args) |
|
|
|
|
| def _register_models(subparsers): |
| for cls in [ |
| ChartParsing, |
| DocImgOrientationClassification, |
| DocVLM, |
| FormulaRecognition, |
| LayoutDetection, |
| SealTextDetection, |
| TableCellsDetection, |
| TableClassification, |
| TableStructureRecognition, |
| TextDetection, |
| TextImageUnwarping, |
| TextLineOrientationClassification, |
| TextRecognition, |
| ]: |
| subcommand_executor = cls.get_cli_subcommand_executor() |
| subparser = subcommand_executor.add_subparser(subparsers) |
| subparser.set_defaults(executor=subcommand_executor.execute_with_args) |
|
|
|
|
| def _register_install_hpi_deps_command(subparsers): |
| def _install_hpi_deps(args): |
| hpip = f"hpi-{args.variant}" |
| try: |
| subprocess.check_call(["paddlex", "--install", hpip]) |
| subprocess.check_call(["paddlex", "--install", "paddle2onnx"]) |
| except subprocess.CalledProcessError: |
| sys.exit("Failed to install dependencies") |
|
|
| subparser = subparsers.add_parser("install_hpi_deps") |
| subparser.add_argument("variant", type=str, choices=["cpu", "gpu", "npu"]) |
| subparser.set_defaults(executor=_install_hpi_deps) |
|
|
|
|
| def _register_install_genai_server_deps_command(subparsers): |
| def _install_genai_server_deps(args): |
| try: |
| subprocess.check_call( |
| ["paddlex", "--install", f"genai-{args.variant}-server"] |
| ) |
| except subprocess.CalledProcessError: |
| sys.exit("Failed to install dependencies") |
|
|
| subparser = subparsers.add_parser("install_genai_server_deps") |
| subparser.add_argument( |
| "variant", type=str, choices=["vllm", "sglang", "fastdeploy"] |
| ) |
| subparser.set_defaults(executor=_install_genai_server_deps) |
|
|
|
|
| def _register_genai_server_command(subparsers): |
| |
| try: |
| from paddlex.inference.genai.server import get_arg_parser, run_genai_server |
| except RuntimeError: |
| return |
|
|
| def _show_prompt_when_server_is_running(host, port, backend): |
| if host == "0.0.0.0": |
| host = "localhost" |
| while True: |
| try: |
| resp = requests.get(f"http://{host}:{port}/health", timeout=1) |
| if resp.status_code == 200: |
| break |
| except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): |
| pass |
| time.sleep(1) |
| prompt = f"""The PaddleOCR GenAI server has been started. You can either: |
| 1. Set the server URL in the module or pipeline configuration and call the PaddleOCR CLI or Python API. For example: |
| paddleocr doc_parser --input demo.png --vl_rec_backend {backend}-server --vl_rec_server_url http://{host}:{port}/v1 |
| 2. Make HTTP requests directly, or using the OpenAI client library.""" |
| logger.info(prompt) |
|
|
| def _run_genai_server(args): |
| Thread( |
| target=_show_prompt_when_server_is_running, |
| args=(args.host, args.port, args.backend), |
| daemon=True, |
| ).start() |
| try: |
| run_genai_server(args) |
| except subprocess.CalledProcessError: |
| sys.exit("Failed to run the server") |
|
|
| paddlex_parser = get_arg_parser() |
| subparser = subparsers.add_parser( |
| "genai_server", parents=[paddlex_parser], conflict_handler="resolve" |
| ) |
| subparser.set_defaults(executor=_run_genai_server) |
|
|
|
|
| def _register_doc2md_command(subparsers): |
| """Register the doc2md subcommand.""" |
|
|
| def _execute_doc2md(args): |
| if args.formats: |
| from ._doc2md import supported_formats |
|
|
| fmts = supported_formats() |
| print("Supported formats: " + ", ".join(f".{f}" for f in fmts)) |
| return |
|
|
| if not args.input: |
| logger.error("--input is required when --formats is not set") |
| sys.exit(2) |
|
|
| from ._doc2md import convert |
| from pathlib import Path |
|
|
| output = args.output |
| quiet = args.quiet |
|
|
| |
| converter_kwargs = {} |
| if args.no_drawings: |
| converter_kwargs["extract_drawings"] = False |
| if args.no_headers_footers: |
| converter_kwargs["extract_headers_footers"] = False |
| if args.sheet_name is not None: |
| converter_kwargs["sheet_name"] = args.sheet_name |
| if args.max_rows is not None: |
| converter_kwargs["max_rows"] = args.max_rows |
|
|
| t1 = time.time() |
| try: |
| result = convert(args.input, output=output, **converter_kwargs) |
| except Exception as e: |
| logger.error(f"Conversion failed: {e}") |
| sys.exit(1) |
|
|
| elapsed = (time.time() - t1) * 1000 |
| if not quiet: |
| logger.info(f"Conversion done in {elapsed:.0f} ms") |
|
|
| if output: |
| if not quiet: |
| logger.info(f"Saved to: {output}") |
| if result.images: |
| logger.info(f"Images saved to: {Path(output).parent / 'images'}/") |
| else: |
| print(result.markdown) |
|
|
| subparser = subparsers.add_parser( |
| "doc2md", |
| help="Convert office documents (docx/xlsx/pptx) to Markdown", |
| ) |
| subparser.add_argument( |
| "-i", |
| "--input", |
| type=str, |
| default=None, |
| help="Input file path (.docx/.xlsx/.pptx)", |
| ) |
| subparser.add_argument( |
| "-o", |
| "--output", |
| type=str, |
| default=None, |
| help="Output Markdown file path (prints to stdout if omitted)", |
| ) |
| subparser.add_argument( |
| "-q", |
| "--quiet", |
| action="store_true", |
| help="Suppress informational output", |
| ) |
| subparser.add_argument( |
| "--formats", |
| action="store_true", |
| help="List supported formats and exit", |
| ) |
| |
| subparser.add_argument( |
| "--no-drawings", |
| action="store_true", |
| help="[docx/xlsx] Skip text box / drawing layer content extraction", |
| ) |
| subparser.add_argument( |
| "--no-headers-footers", |
| action="store_true", |
| help="[docx] Skip header and footer content extraction", |
| ) |
| |
| subparser.add_argument( |
| "--sheet-name", |
| type=str, |
| default=None, |
| help="[xlsx] Convert only the specified sheet (by name)", |
| ) |
| subparser.add_argument( |
| "--max-rows", |
| type=int, |
| default=None, |
| help="[xlsx] Maximum number of rows to convert per sheet", |
| ) |
| subparser.set_defaults(executor=_execute_doc2md) |
|
|
|
|
| def _register_api_command(subparsers): |
| from ._api_client.cli import register_api_command |
|
|
| register_api_command(subparsers) |
|
|
|
|
| def _get_parser(): |
| parser = argparse.ArgumentParser(prog="paddleocr") |
| parser.add_argument( |
| "-v", "--version", action="version", version=f"%(prog)s {version}" |
| ) |
| subparsers = parser.add_subparsers(dest="subcommand", metavar="COMMAND") |
| _register_pipelines(subparsers) |
| _register_models(subparsers) |
| _register_install_hpi_deps_command(subparsers) |
| _register_install_genai_server_deps_command(subparsers) |
| _register_genai_server_command(subparsers) |
| _register_doc2md_command(subparsers) |
| _register_api_command(subparsers) |
| return parser |
|
|
|
|
| def _execute(args): |
| args.executor(args) |
|
|
|
|
| def main(): |
| logger.setLevel(logging.INFO) |
| warnings.filterwarnings("default", category=CLIDeprecationWarning) |
| parser = _get_parser() |
| args = parser.parse_args() |
| if args.subcommand is None: |
| parser.print_usage(sys.stderr) |
| sys.exit(2) |
| _execute(args) |
|
|