#!/usr/bin/env bash
set -euo pipefail
device_type='nvidia-gpu'
build_for_offline='false'
paddleocr_version='3.4.0'
paddlex_version='3.4.0'
platform='linux/amd64'
action='load'
registry='ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle'
builder=''
show_usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Options:
--device-type <type> Device type (nvidia-gpu|nvidia-gpu-sm120|hygon-dcu|kunlunxin-xpu|metax-gpu|iluvatar-gpu|huawei-npu) [default: ${device_type}]
--offline Build offline version
--ppocr-version <ver> PaddleOCR version [default: ${paddleocr_version}]
--pdx-version <ver> PaddleX version [default: ${paddlex_version}]
--platform <platform> Build platform [default: ${platform}]
--action <action> Post-build action: load|push|tar|none [default: ${action}]
load: Load to local Docker
push: Push to image registry
tar: Export as tar file
none: Build only, no output
--registry <registry> Custom image registry [default: ${registry}]
--builder <name> Buildx builder name (override default)
-h, --help Show this help message
Examples:
$0 --device-type nvidia-gpu --action push
$0 --device-type nvidia-gpu --platform linux/amd64,linux/arm64 --action push
$0 --device-type nvidia-gpu --action tar --platform linux/amd64
EOF
}
while [[ $# -gt 0 ]]; do
case $1 in
--device-type)
[ -z "$2" ] && {
echo "Error: '--device-type' requires a value" >&2
exit 2
}
device_type="$2"
shift
shift
case "${device_type}" in
nvidia-gpu|nvidia-gpu-sm120|hygon-dcu|kunlunxin-xpu|metax-gpu|iluvatar-gpu|huawei-npu)
;;
*)
echo "Error: Unknown device type: ${device_type}" >&2
exit 2
;;
esac
;;
--offline)
build_for_offline='true'
shift
;;
--ppocr-version)
[ -z "$2" ] && {
echo "Error: '--ppocr-version' requires a value" >&2
exit 2
}
paddleocr_version="$2"
shift
shift
;;
--pdx-version)
[ -z "$2" ] && {
echo "Error: '--pdx-version' requires a value" >&2
exit 2
}
paddlex_version="$2"
shift
shift
;;
--platform)
[ -z "$2" ] && {
echo "Error: '--platform' requires a value" >&2
exit 2
}
platform="$2"
shift
shift
;;
--action)
[ -z "$2" ] && {
echo "Error: '--action' requires a value" >&2
exit 2
}
action="$2"
shift
shift
case "${action}" in
load|push|tar|none)
;;
*)
echo "Error: Unknown action: ${action}. Use load|push|tar|none" >&2
exit 2
;;
esac
;;
--registry)
[ -z "$2" ] && {
echo "Error: '--registry' requires a value" >&2
exit 2
}
registry="$2"
shift
shift
;;
--builder)
[ -z "${2-}" ] && {
echo "Error: '--builder' requires a value" >&2
exit 2
}
builder="$2"
shift 2
;;
-h|--help)
show_usage
exit 0
;;
*)
echo "Error: Unknown option: $1" >&2
echo "Use $0 --help for usage information" >&2
exit 2
;;
esac
done
# Validate platform compatibility for load action
if [[ "${action}" == 'load' ]] && [[ "${platform}" == *','* ]]; then
echo "Error: Cannot use --action load with multiple platforms" >&2
echo "Platform: ${platform}" >&2
echo "Please specify a single platform or use other actions" >&2
exit 2
fi
# Build tag suffix
tag_suffix="latest-${device_type}"
if [ "${build_for_offline}" = 'true' ]; then
tag_suffix="${tag_suffix}-offline"
fi
dockerfile="accelerators/${device_type}/pipeline.Dockerfile"
if [ ! -f "${dockerfile}" ]; then
echo "Error: Dockerfile not found: ${dockerfile}" >&2
exit 1
fi
dockerfile_hash="$(sha256sum "${dockerfile}" | cut -c1-12)"
image_version="${paddleocr_version}-${paddlex_version}-${dockerfile_hash}"
# Image name
base_image_name='paddleocr-vl'
# Main tags
main_tag="${registry}/${base_image_name}:${tag_suffix}"
version_tag="${registry}/${base_image_name}:${tag_suffix/latest/${image_version}}"
paddleocr_version_tag="${registry}/${base_image_name}:${tag_suffix/latest/paddleocr${paddleocr_version%.*}}"
# Build arguments array
build_args=(
'--platform' "${platform}"
'-f' "${dockerfile}"
'-t' "${main_tag}"
'-t' "${version_tag}"
'-t' "${paddleocr_version_tag}"
'--build-arg' "BUILD_FOR_OFFLINE=${build_for_offline}"
'--build-arg' "PADDLEOCR_VERSION===${paddleocr_version}"
'--build-arg' "PADDLEX_VERSION===${paddlex_version}"
'--build-arg' "http_proxy=${http_proxy:-}"
'--build-arg' "https_proxy=${https_proxy:-}"
'--build-arg' "no_proxy=${no_proxy:-}"
'--label' "org.opencontainers.image.version.paddleocr=${paddleocr_version}"
'--label' "org.opencontainers.image.version.paddlex=${paddlex_version}"
'--label' "org.opencontainers.image.version.dockerfile.sha=${dockerfile_hash}"
'.'
)
if [[ -n "${builder}" ]]; then
build_args=('--builder' "${builder}" "${build_args[@]}")
fi
echo "========================================="
echo "Build Configuration:"
echo " Device Type: ${device_type}"
echo " Offline Mode: ${build_for_offline}"
echo " PaddleOCR: ${paddleocr_version}"
echo " PaddleX: ${paddlex_version}"
echo " Platform: ${platform}"
echo " Action: ${action}"
echo " Registry: ${registry}"
echo " Builder: ${builder:-<default>}"
echo " Dockerfile: ${dockerfile}"
echo " Tags:"
echo " - ${main_tag}"
echo " - ${version_tag}"
echo "========================================="
# Add action-specific build options
case "${action}" in
load)
echo "Building and loading to local Docker..."
build_args+=('--load')
;;
push)
echo "Building and pushing to registry..."
build_args+=('--push')
if ! docker info 2>/dev/null | grep -q "Username"; then
echo "Warning: Docker login not detected. Push may fail."
echo "Tip: Run 'docker login ${registry%%/*}' to login"
fi
;;
tar)
echo "Building and exporting as tar file..."
output_dir=./build-output
mkdir -p "${output_dir}"
tar_file="${output_dir}/${base_image_name}-${tag_suffix}-${platform//\//_}.tar"
build_args+=("--output" "type=docker,dest=${tar_file}")
echo " Output file: ${tar_file}"
;;
none)
echo "Building only (image stays in BuildKit cache)..."
echo "Note: Image will be lost if BuildKit cache is cleared"
;;
esac
# Execute build command
echo "Executing: docker buildx build ${build_args[*]}"
docker buildx build "${build_args[@]}"
# Post-build actions
case "${action}" in
load)
echo "✅ Image loaded to local Docker"
echo " View: docker images | grep ${base_image_name}"
;;
push)
echo "✅ Image pushed to registry"
echo " Pull: docker pull ${main_tag}"
echo " Inspect: docker buildx imagetools inspect ${main_tag}"
;;
tar)
echo "✅ Image exported as tar file"
echo " File size: $(du -h "${tar_file}" | cut -f1)"
echo " Load to Docker: docker load -i ${tar_file}"
;;
none)
echo "ℹ️ Image saved in BuildKit cache only"
echo " Use --action load to rebuild and load quickly"
echo " Or use --action push to push directly"
;;
esac