#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="${SCRIPT_DIR}" TIMESTAMP="$(date +"%Y%m%d_%H%M%S")" BUILD_TYPE="" VERSION="" OUTPUT_ROOT="${PROJECT_ROOT}/build-file" REGISTRY="unis" IMAGE_NAME="qwen3-asr" INCLUDE_MODELS="true" METAX_BASE_IMAGE="${METAX_BASE_IMAGE:-}" ILUVATAR_BASE_IMAGE="${ILUVATAR_BASE_IMAGE:-}" MTHREADS_BASE_IMAGE="${MTHREADS_BASE_IMAGE:-}" METAX_PYTHON_BIN="${METAX_PYTHON_BIN:-/opt/conda/bin/python}" ILUVATAR_PYTHON_BIN="${ILUVATAR_PYTHON_BIN:-python3}" MTHREADS_PYTHON_BIN="${MTHREADS_PYTHON_BIN:-python3}" info() { echo "[INFO] $1"; } die() { echo "[ERROR] $1" >&2; exit 1; } show_help() { cat </dev/null 2>&1; then uv run python -m app.utils.download_models --export-dir "$model_export_dir" else python -m app.utils.download_models --export-dir "$model_export_dir" fi ) info "压缩模型目录: $(basename "$model_archive")" tar -C "$bundle_dir" -czf "$model_archive" models rm -rf "$model_export_dir" } prompt_build_type() { local choice echo "请选择离线交付类型:" echo " 1) GPU" echo " 2) CPU" echo " 3) MetaX GPU" echo " 4) Iluvatar GPU" echo " 5) Moore Threads GPU" echo " 6) ALL" read -r -p "请输入选项 [6]: " choice choice="${choice:-6}" case "$choice" in 1) BUILD_TYPE="gpu" ;; 2) BUILD_TYPE="cpu" ;; 3) BUILD_TYPE="metax" ;; 4) BUILD_TYPE="iluvatar" ;; 5) BUILD_TYPE="mthreads" ;; 6) BUILD_TYPE="all" ;; *) die "无效选项: $choice" ;; esac } validate() { case "$BUILD_TYPE" in cpu|gpu|metax|iluvatar|mthreads|all) ;; "") if [[ -t 0 ]]; then prompt_build_type; else BUILD_TYPE="all"; fi ;; *) die "不支持的构建类型: ${BUILD_TYPE}" ;; esac if [[ "$BUILD_TYPE" == "metax" && -z "$METAX_BASE_IMAGE" ]]; then die "--type metax 需要指定 --metax-base,值为已 docker load/pull 的沐曦官方 vLLM 镜像" fi if [[ "$BUILD_TYPE" == "iluvatar" && -z "$ILUVATAR_BASE_IMAGE" ]]; then die "--type iluvatar 需要指定 --iluvatar-base,值为已 docker load/pull 的天数官方 vLLM 镜像" fi if [[ "$BUILD_TYPE" == "mthreads" && -z "$MTHREADS_BASE_IMAGE" ]]; then die "--type mthreads 需要指定 --mthreads-base,值为已 docker load/pull 的摩尔线程官方 vLLM 镜像" fi VERSION="${VERSION:-$TIMESTAMP}" } export_compressor() { command -v pigz >/dev/null 2>&1 && echo "pigz -f" || echo "gzip -f" } build_and_export_image() { local target="$1" local dockerfile="$2" local tag="$3" local bundle_dir="$4" local tar_path="${bundle_dir}/${IMAGE_NAME}-${target}-${VERSION}-amd64.tar" info "构建 ${target} 镜像: ${tag}" ( cd "$PROJECT_ROOT" case "$target" in metax) docker build -f "$dockerfile" -t "$tag" \ --build-arg "METAX_BASE_IMAGE=${METAX_BASE_IMAGE}" \ --build-arg "PYTHON_BIN=${METAX_PYTHON_BIN}" . ;; iluvatar) docker build -f "$dockerfile" -t "$tag" \ --build-arg "ILUVATAR_BASE_IMAGE=${ILUVATAR_BASE_IMAGE}" \ --build-arg "PYTHON_BIN=${ILUVATAR_PYTHON_BIN}" . ;; mthreads) docker build -f "$dockerfile" -t "$tag" \ --build-arg "MTHREADS_BASE_IMAGE=${MTHREADS_BASE_IMAGE}" \ --build-arg "PYTHON_BIN=${MTHREADS_PYTHON_BIN}" . ;; *) docker build -f "$dockerfile" -t "$tag" . ;; esac ) info "导出 ${target} 镜像归档" docker save -o "$tar_path" "$tag" info "压缩 ${target} 镜像归档" $(export_compressor) "$tar_path" } build_offline_images() { local bundle_dir="$1" local cpu_tag="${REGISTRY}/${IMAGE_NAME}:cpu-${VERSION}" local gpu_tag="${REGISTRY}/${IMAGE_NAME}:gpu-${VERSION}" local metax_tag="${REGISTRY}/${IMAGE_NAME}:metax-${VERSION}" local iluvatar_tag="${REGISTRY}/${IMAGE_NAME}:iluvatar-${VERSION}" local mthreads_tag="${REGISTRY}/${IMAGE_NAME}:mthreads-${VERSION}" case "$BUILD_TYPE" in cpu) build_and_export_image "cpu" "Dockerfile.cpu" "$cpu_tag" "$bundle_dir" ;; gpu) build_and_export_image "gpu" "Dockerfile.gpu" "$gpu_tag" "$bundle_dir" ;; metax) build_and_export_image "metax" "Dockerfile.metax" "$metax_tag" "$bundle_dir" ;; iluvatar) build_and_export_image "iluvatar" "Dockerfile.iluvatar" "$iluvatar_tag" "$bundle_dir" ;; mthreads) build_and_export_image "mthreads" "Dockerfile.mthreads" "$mthreads_tag" "$bundle_dir" ;; all) build_and_export_image "cpu" "Dockerfile.cpu" "$cpu_tag" "$bundle_dir" build_and_export_image "gpu" "Dockerfile.gpu" "$gpu_tag" "$bundle_dir" ;; esac } append_bundle_image_env() { local bundle_dir="$1" local env_file="${bundle_dir}/.env.example" local image_tag="" local note="" case "$BUILD_TYPE" in gpu) image_tag="${REGISTRY}/${IMAGE_NAME}:gpu-${VERSION}" note="GPU" ;; metax) image_tag="${REGISTRY}/${IMAGE_NAME}:metax-${VERSION}" note="MetaX GPU" ;; iluvatar) image_tag="${REGISTRY}/${IMAGE_NAME}:iluvatar-${VERSION}" note="Iluvatar GPU" ;; mthreads) image_tag="${REGISTRY}/${IMAGE_NAME}:mthreads-${VERSION}" note="Moore Threads GPU" ;; cpu) image_tag="${REGISTRY}/${IMAGE_NAME}:cpu-${VERSION}" note="CPU" ;; all) image_tag="${REGISTRY}/${IMAGE_NAME}:gpu-${VERSION}" note="GPU by default; switch to ${REGISTRY}/${IMAGE_NAME}:cpu-${VERSION} when using docker-compose-cpu.yml" ;; esac cat >> "$env_file" < "${bundle_dir}/BUNDLE_INFO.txt" <> "${bundle_dir}/BUNDLE_INFO.txt" done echo "Compose Files:" >> "${bundle_dir}/BUNDLE_INFO.txt" while IFS= read -r compose_file; do [[ -n "$compose_file" ]] || continue echo " ${compose_file}" >> "${bundle_dir}/BUNDLE_INFO.txt" done < <(bundle_compose_files) cat >> "${bundle_dir}/BUNDLE_INFO.txt" <> "${bundle_dir}/BUNDLE_INFO.txt" < "${bundle_dir}/README.md" <