Files
wehub-resource-sync e904b667c6
PaddleOCR PR Tests GPU / test-pr-gpu (push) Blocked by required conditions
PaddleOCR PR Tests / test-pr (push) Blocked by required conditions
PaddleOCR PR Tests / test-pr-python (3.8) (push) Waiting to run
Build/Publish Develop Docs / deploy (push) Failing after 1s
PaddleOCR Code Style Check / check-code-style (push) Failing after 1s
PaddleOCR PR Tests GPU / detect-changes (push) Failing after 1s
PaddleOCR PR Tests GPU / test-pr-gpu-impl (push) Waiting to run
PaddleOCR PR Tests / detect-changes (push) Failing after 1s
PaddleOCR PR Tests / test-pr-python (3.13) (push) Waiting to run
PaddleOCR PR Tests / test-pr-python (3.9) (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 11:59:26 +08:00

358 lines
11 KiB
Python

# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import sys
from .._utils.cli import str2bool
from .client import PaddleOCRClient
from .models import (
Model,
OCROptions,
PaddleOCRVLOptions,
PPStructureV3Options,
is_ocr_model,
is_vl_model,
)
def register_api_command(subparsers):
"""Register the 'api' subcommand into paddleocr CLI."""
subparser = subparsers.add_parser(
"api",
help="Call PaddleOCR cloud API for OCR or document parsing",
)
subparser.add_argument(
"--model_type",
type=str,
required=True,
choices=["ocr", "doc_parsing"],
help="Task type: ocr or doc_parsing",
)
subparser.add_argument(
"--model",
type=str,
default=None,
choices=[m.value for m in Model],
help="Model name.",
)
subparser.add_argument(
"--file_url",
type=str,
default=None,
help="URL of the file to process",
)
subparser.add_argument(
"--file_path",
type=str,
default=None,
help="Local file path to process",
)
subparser.add_argument(
"--base_url",
type=str,
default=None,
help="Base URL of the PaddleOCR API service",
)
subparser.add_argument(
"--token",
type=str,
default=None,
help="Access token (or set PADDLEOCR_ACCESS_TOKEN env variable)",
)
subparser.add_argument(
"--client_platform",
type=str,
default=None,
help="Value for the Client-Platform request header",
)
subparser.add_argument(
"--output",
type=str,
default=None,
help="Output JSON file path (prints to stdout if omitted)",
)
subparser.add_argument(
"--request_timeout",
type=float,
default=300.0,
help="Timeout in seconds for one HTTP request",
)
subparser.add_argument(
"--poll_timeout",
type=float,
default=600.0,
help="Total timeout in seconds while waiting for the remote job",
)
subparser.add_argument(
"--save_resources",
type=str,
default=None,
help="Directory for saving resources referenced by the result",
)
subparser.add_argument(
"--overwrite_resources",
action="store_true",
help="Overwrite existing files when saving resources",
)
subparser.add_argument(
"--page_ranges",
type=str,
default=None,
help='Page ranges to parse, for example "2,4-6"',
)
subparser.add_argument(
"--batch_id",
type=str,
default=None,
help="Optional batch identifier for querying related jobs",
)
# --- Preprocessing ---
subparser.add_argument(
"--use_doc_orientation_classify",
type=str2bool,
default=None,
help="Enable document orientation classification (True/False)",
)
subparser.add_argument(
"--use_doc_unwarping",
type=str2bool,
default=None,
help="Enable document unwarping (True/False)",
)
# --- Text detection ---
subparser.add_argument(
"--use_textline_orientation",
type=str2bool,
default=None,
help="Enable textline orientation detection for OCR (True/False)",
)
subparser.add_argument(
"--text_det_limit_side_len",
type=int,
default=None,
help="Image side length limit for text detection",
)
subparser.add_argument(
"--text_det_limit_type",
type=str,
default=None,
choices=["min", "max"],
help="Side length limit type: min or max",
)
# --- Text recognition ---
subparser.add_argument(
"--text_rec_score_thresh",
type=float,
default=None,
help="Score threshold for text recognition results",
)
# --- Layout and feature toggles (doc_parsing only) ---
subparser.add_argument(
"--use_layout_detection",
type=str2bool,
default=None,
help="Enable layout detection for document parsing (True/False)",
)
subparser.add_argument(
"--use_seal_recognition",
type=str2bool,
default=None,
help="Enable seal recognition for document parsing (True/False)",
)
subparser.add_argument(
"--use_table_recognition",
type=str2bool,
default=None,
help="Enable table recognition for PP-StructureV3 (True/False)",
)
subparser.add_argument(
"--use_formula_recognition",
type=str2bool,
default=None,
help="Enable formula recognition for PP-StructureV3 (True/False)",
)
subparser.add_argument(
"--use_chart_recognition",
type=str2bool,
default=None,
help="Enable chart recognition for document parsing (True/False)",
)
# --- Output ---
subparser.add_argument(
"--visualize",
type=str2bool,
default=None,
help="Enable result visualization images (True/False)",
)
subparser.add_argument(
"--prettify_markdown",
type=str2bool,
default=None,
help="Enable markdown prettification for document parsing (True/False)",
)
subparser.set_defaults(executor=_execute_api)
def _execute_api(args):
kwargs = {}
if args.token:
kwargs["token"] = args.token
if args.base_url:
kwargs["base_url"] = args.base_url
kwargs["request_timeout"] = args.request_timeout
kwargs["poll_timeout"] = args.poll_timeout
if args.client_platform:
kwargs["client_platform"] = args.client_platform
try:
client = PaddleOCRClient(**kwargs)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
try:
model = _resolve_model(args.model) if args.model else None
if args.model_type == "ocr":
if model is not None and not is_ocr_model(model):
print(
f"Error: OCR task does not support {model.value}.",
file=sys.stderr,
)
sys.exit(2)
options = OCROptions(
use_doc_orientation_classify=args.use_doc_orientation_classify,
use_doc_unwarping=args.use_doc_unwarping,
use_textline_orientation=args.use_textline_orientation,
text_det_limit_side_len=args.text_det_limit_side_len,
text_det_limit_type=args.text_det_limit_type,
text_rec_score_thresh=args.text_rec_score_thresh,
visualize=args.visualize,
)
result = client.ocr(
file_url=args.file_url,
file_path=args.file_path,
options=options,
page_ranges=args.page_ranges,
batch_id=args.batch_id,
model=model or Model.PP_OCRV6,
)
output = _ocr_result_to_dict(result)
save_resources = client.save_ocr_result_resources
else:
if model is None:
model = Model.PADDLE_OCR_VL_16
if is_vl_model(model):
options = PaddleOCRVLOptions(
use_doc_orientation_classify=args.use_doc_orientation_classify,
use_doc_unwarping=args.use_doc_unwarping,
use_chart_recognition=args.use_chart_recognition,
use_seal_recognition=args.use_seal_recognition,
use_layout_detection=args.use_layout_detection,
prettify_markdown=args.prettify_markdown,
visualize=args.visualize,
)
else:
options = PPStructureV3Options(
use_doc_orientation_classify=args.use_doc_orientation_classify,
use_doc_unwarping=args.use_doc_unwarping,
use_textline_orientation=args.use_textline_orientation,
use_chart_recognition=args.use_chart_recognition,
use_seal_recognition=args.use_seal_recognition,
use_table_recognition=args.use_table_recognition,
use_formula_recognition=args.use_formula_recognition,
use_layout_detection=args.use_layout_detection,
text_det_limit_side_len=args.text_det_limit_side_len,
text_det_limit_type=args.text_det_limit_type,
text_rec_score_thresh=args.text_rec_score_thresh,
prettify_markdown=args.prettify_markdown,
visualize=args.visualize,
)
result = client.parse_document(
model=model,
file_url=args.file_url,
file_path=args.file_path,
options=options,
page_ranges=args.page_ranges,
batch_id=args.batch_id,
)
output = _doc_parsing_result_to_dict(result)
save_resources = client.save_document_parsing_result_resources
json_str = json.dumps(output, ensure_ascii=False, indent=2)
if args.save_resources:
saved_paths = save_resources(
result,
args.save_resources,
overwrite=args.overwrite_resources,
)
print(
f"Resources saved to: {args.save_resources} ({len(saved_paths)} files)",
file=sys.stderr,
)
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(json_str)
print(f"Result saved to: {args.output}")
else:
print(json_str)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
finally:
client.close()
def _resolve_model(model_str: str) -> Model:
try:
return Model(model_str)
except ValueError:
print(
f"Error: Unknown model '{model_str}'. "
f"Choose from: {', '.join(m.value for m in Model)}",
file=sys.stderr,
)
sys.exit(1)
def _ocr_result_to_dict(result) -> dict:
return {
"jobId": result.job_id,
"pages": [
{
"prunedResult": page.pruned_result,
"ocrImageUrl": page.ocr_image_url,
}
for page in result.pages
],
}
def _doc_parsing_result_to_dict(result) -> dict:
return {
"jobId": result.job_id,
"pages": [
{
"markdownText": page.markdown_text,
"markdownImages": page.markdown_images,
"outputImages": page.output_images,
}
for page in result.pages
],
}