CoPilot用Claude Sonnet 4模型调试多平台自动安装python训练模型或机器学习环境

文心一言调试多平台自动安装python训练模型或机器学习环境

PHPer 2025-09-05 3 0 0

torch,torchvision,torchaudio 已经安装了。

运行./setup_train_env.sh --core-packages torch,torchvision,torchaudio 还是是会下载安装torch ,"--core-packages torch,torchvision,torchaudio"CLI的含义是保护这些核心包不被重复安装或被其他安装的包依赖安装。终端输出的部分内容:Requirement already satisfied: mpmath<1.4,>=1.1.0 in g:\programdata\miniconda3_win11\lib\site-packages (from sympy>=1.13.3->torch) (1.3.0)

Requirement already satisfied: MarkupSafe>=2.0 in g:\programdata\miniconda3_win11\lib\site-packages (from jinja2->torch) (3.0.2)

📥 [9s] Downloading torch-2.8.0-cp313-cp313-win_amd64.whl (241.3 MB)

⏳ 正在下载大型 PyTorch 文件 (241.3 MB),请耐心等待...

⏳ 大型包下载中... (已等待 1 分钟,请继续等待或按 Ctrl+C 跳过此镜像)

🚀 [75s] ---------------------------------------- 241.3/241.3 MB 2.8 MB/s eta 0:00:00

📥 [76s] Downloading torchaudio-2.8.0-cp313-cp313-win_amd64.whl (2.5 MB)

⏳ 正在下载大型 PyTorch 文件 (2.5 MB),请耐心等待...

🚀 [76s] ---------------------------------------- 2.5/2.5 MB 4.5 MB/s eta 0:00:00

📥 [76s] Downloading torchvision-0.23.0-cp313-cp313-win_amd64.whl (1.6 MB)

⏳ 正在下载大型 PyTorch 文件 (1.6 MB),请耐心等待...

🚀 [77s] ---------------------------------------- 1.6/1.6 MB 4.2 MB/s eta 0:00:00

📦 [78s] Installing collected packages: torch, torchvision, torchaudio

⏳ 大型包下载中... (已等待 2 分钟,请继续等待或按 Ctrl+C 跳过此镜像)


#!/bin/bash
# 在原有脚本的core包检查逻辑后添加以下强制跳过代码
# 修改确保核心包安装的函数
ensure_core_package_installed() {
    local core_package="$1"
    shift
    local conflict_packages=("$@")
    # 强制跳过已安装的核心包
    if pip show "$core_package" &> /dev/null; then
        ok "✅ 强制跳过已安装的核心包: $core_package"
        return 0
    fi
    # 原有安装逻辑...
    # ...
}
# 在调用安装核心包前添加环境检查
if [ -n "$VIRTUAL_ENV" ]; then
    info "🔍 检测到虚拟环境: $VIRTUAL_ENV"
    # 强制使用虚拟环境中的pip
    alias pip="python -m pip"
fi
# 执行核心包安装时添加额外检查
install_essential_large_packages() {
    # 原有逻辑...
    # 在安装前强制检查包是否已安装
    for pkg in "${large_packages_needed[@]}"; do
        if pip show "$pkg" &> /dev/null; then
            ok "✅ 跳过已安装的包: $pkg"
            continue
        fi
        # 安装逻辑...
    done
}

操作建议

  1. 手动验证安装状态:
bash

# 在脚本执行前运行pip list | grep -E 'torch|torchvision|torchaudio'

  1. 强制使用指定版本(在脚本开头添加):

bash

# 添加环境变量定义export TORCH_VERSION="2.8.0+cu128"export TORCHVISION_VERSION="0.23.0"

  1. 修复脚本执行方式:

bash

# 修改后执行bash setup_train_env.sh --core-packages torch,torchvision,torchaudio --force-skip-installed

关键修改说明

  1. 增强包检查逻辑:在ensure_core_package_installed函数开头添加对已安装包的强制跳过逻辑,确保即使后续逻辑异常也不会重复安装。
  2. 环境隔离加固:通过VIRTUAL_ENV检测确保在虚拟环境中使用正确的pip,避免系统环境干扰。
  3. 版本锁定:通过环境变量明确指定PyTorch相关包的版本和CUDA版本,避免自动检测导致的版本不匹配。

修改后的脚本将优先跳过已安装的核心包,仅在确实需要时才执行安装,同时通过环境变量明确版本要求,避免因版本检测错误导致的重复下载。

20250905 0443

脚本代码

#!/bin/bash
set -o pipefail
# 使用说明函数(中文),在脚本头部即可调用
usage() {
    # 将帮助输出到终端(/dev/tty),避免被外部管道如 | tee 捕获到日志
    if [ -w /dev/tty ]; then
        cat > /dev/tty <<'USAGE'
用法: bash setup_train_env.sh [选项] [包...]

选项:
    -h, --help                     显示本帮助并退出
    -d, --debug                    启用调试模式(set -x),打印执行跟踪
    --core-packages PACKAGES       指定核心包列表(逗号分隔,默认: torch,torchvision,torchaudio)

环境变量(可选):
    ENV_NAME          虚拟环境名(默认: train_ss)
    WORKSPACE         工作目录(默认: /mnt/workspace 或 Windows 下 D:/workspace)
    PLATFORM          平台检测覆盖,默认自动检测
    TORCH_INDEX       指定 PyTorch wheel 的 index-url

说明:
    - 脚本内部会尽量把所有时间显示为中国上海时间。
    - 若希望同时在控制台显示并写入日志,推荐在运行脚本时使用外部管道:
        bash setup_train_env.sh 2>&1 | tee -a ./logs/setup_env_$(date +%Y%m%d_%H%M%S).log
        或者在 Windows (Git Bash) 下:
        bash setup_train_env.sh 2>&1 | tee -a D:/logs/setup_env_$(date +%Y%m%d_%H%M%S).log

示例:
    # 启用调试并指定环境名
    bash setup_train_env.sh --debug ENV_NAME=myenv

    # 指定自定义核心包
    bash setup_train_env.sh --core-packages "tensorflow,keras"
    
    # 指定多个核心包
    bash setup_train_env.sh --core-packages "torch,torchvision,numpy"

    # 使用外部 tee 将输出同时写日志并显示
    bash setup_train_env.sh 2>&1 | tee -a ./logs/setup_env_$(date +%Y%m%d_%H%M%S).log
USAGE
    else
        cat <<'USAGE'
用法: bash setup_train_env.sh [选项] [包...]

选项:
    -h, --help                     显示本帮助并退出
    -d, --debug                    启用调试模式(set -x),打印执行跟踪
    --core-packages PACKAGES       指定核心包列表(逗号分隔,默认: torch,torchvision,torchaudio)

环境变量(可选):
    ENV_NAME          虚拟环境名(默认: train_ss)
    WORKSPACE         工作目录(默认: /mnt/workspace 或 Windows 下 D:/workspace)
    PLATFORM          平台检测覆盖,默认自动检测
    TORCH_INDEX       指定 PyTorch wheel 的 index-url

说明:
    - 脚本内部会尽量把所有时间显示为中国上海时间。
    - 若希望同时在控制台显示并写入日志,推荐在运行脚本时使用外部管道:
        bash setup_train_env.sh 2>&1 | tee -a ./logs/setup_env_$(date +%Y%m%d_%H%M%S).log
        或者在 Windows (Git Bash) 下:
        bash setup_train_env.sh 2>&1 | tee -a D:/logs/setup_env_$(date +%Y%m%d_%H%M%S).log

示例:
    # 启用调试并指定环境名
    bash setup_train_env.sh --debug ENV_NAME=myenv

    # 使用外部 tee 将输出同时写日志并显示
    bash setup_train_env.sh 2>&1 | tee -a ./logs/setup_env_$(date +%Y%m%d_%H%M%S).log
USAGE
    fi
    exit 0
}

# 支持通过命令行参数开启 DEBUG:--debug 或 -d;同时支持 --help/-h 和 --core-packages
CORE_PACKAGES_ARG=""

for _arg in "$@"; do
        case "$_arg" in
                --debug|-d)
                        export DEBUG=1
                        ;;
                --help|-h)
                        usage
                        ;;
                --core-packages)
                        CORE_PACKAGES_NEXT=true
                        ;;
                --core-packages=*)
                        CORE_PACKAGES_ARG="${_arg#*=}"
                        ;;
                *)
                        if [[ "$CORE_PACKAGES_NEXT" == "true" ]]; then
                                CORE_PACKAGES_ARG="$_arg"
                                CORE_PACKAGES_NEXT=""
                        fi
                        ;;
        esac
done

# ========================================
# 🔍 CLI参数验证
# ========================================

# 检查 --core-packages 参数是否有值
if [[ "$CORE_PACKAGES_NEXT" == "true" ]]; then
    echo "❌ 错误: --core-packages 参数缺少参数值" >&2
    echo "" >&2
    echo "💡 正确用法:" >&2
    echo "   ./setup_train_env.sh --core-packages torch,torchvision,torchaudio" >&2
    echo "   ./setup_train_env.sh --core-packages=\"torch,torchvision,torchaudio\"" >&2
    echo "" >&2
    echo "📋 示例核心包列表:" >&2
    echo "   • PyTorch生态: torch,torchvision,torchaudio" >&2
    echo "   • TensorFlow生态: tensorflow,keras" >&2
    echo "   • 混合方案: torch,tensorflow,numpy" >&2
    echo "" >&2
    echo "🔍 查看完整帮助: ./setup_train_env.sh --help" >&2
    exit 1
fi

# 如果指定了核心包参数,验证格式
if [[ -n "$CORE_PACKAGES_ARG" ]]; then
    # 检查是否为空字符串
    if [[ "$CORE_PACKAGES_ARG" == "" ]]; then
        echo "❌ 错误: --core-packages 参数值不能为空" >&2
        echo "💡 请提供有效的包列表,例如: torch,torchvision,torchaudio" >&2
        exit 1
    fi
    
    # 基本格式验证(检查是否包含有效字符)
    if [[ ! "$CORE_PACKAGES_ARG" =~ ^[a-zA-Z0-9_,-]+$ ]]; then
        echo "❌ 错误: --core-packages 参数值包含无效字符" >&2
        echo "💡 只允许字母、数字、下划线、连字符和逗号" >&2
        echo "💡 当前值: '$CORE_PACKAGES_ARG'" >&2
        exit 1
    fi
    
    echo "✅ 核心包参数验证通过: $CORE_PACKAGES_ARG" >&2
fi

# ========================================
# � 智能环境检测和命令兼容性处理
# ========================================

# 检测当前shell环境
detect_shell_environment() {
    local env_result=""
    local platform=""
    
    # 检测平台和环境
    if [[ "${OSTYPE:-}" == "msys" ]] || [[ "${MSYSTEM:-}" =~ ^(MINGW|MSYS) ]]; then
        platform="windows"
        env_result="GIT_BASH"
        export DETECTED_PLATFORM="windows"
        export DETECTED_SHELL="git_bash"
        export COMMANDS_AVAILABLE=true
    elif [[ "${OS:-}" == "Windows_NT" ]] || command -v powershell.exe >/dev/null 2>&1; then
        platform="windows"
        env_result="WINDOWS_POWERSHELL"
        export DETECTED_PLATFORM="windows"
        export DETECTED_SHELL="powershell"
        export COMMANDS_AVAILABLE=false
    elif [[ "${OSTYPE:-}" == "linux"* ]]; then
        platform="linux"
        # Linux下检查关键命令是否可用
        local missing_commands=()
        for cmd in grep sed cut awk; do
            if ! command -v "$cmd" >/dev/null 2>&1; then
                missing_commands+=("$cmd")
            fi
        done
        
        if [ ${#missing_commands[@]} -eq 0 ]; then
            env_result="LINUX_BASH"
            export COMMANDS_AVAILABLE=true
        else
            env_result="LINUX_MINIMAL"
            export COMMANDS_AVAILABLE=false
            export MISSING_COMMANDS=("${missing_commands[@]}")
        fi
        export DETECTED_PLATFORM="linux"
        export DETECTED_SHELL="bash"
    elif [[ "${OSTYPE:-}" == "darwin"* ]]; then
        platform="macos"
        env_result="MACOS_BASH"
        export DETECTED_PLATFORM="macos"
        export DETECTED_SHELL="bash"
        export COMMANDS_AVAILABLE=true
    else
        # 未知环境,通过命令可用性判断
        if command -v grep >/dev/null 2>&1 && command -v sed >/dev/null 2>&1 && command -v cut >/dev/null 2>&1; then
            env_result="UNIX_COMPATIBLE"
            export COMMANDS_AVAILABLE=true
        else
            env_result="LIMITED_SHELL"
            export COMMANDS_AVAILABLE=false
        fi
        export DETECTED_PLATFORM="unknown"
        export DETECTED_SHELL="unknown"
    fi
    
    echo "$env_result"
}

# 🔧 Linux系统自动安装缺失命令
install_missing_commands_linux() {
    local missing_commands=("$@")
    
    echo "🔧 尝试自动安装缺失命令: ${missing_commands[*]}" >&2
    
    # 检测包管理器并安装
    if command -v apt-get >/dev/null 2>&1; then
        echo "📦 使用 apt-get 安装..." >&2
        sudo apt-get update >/dev/null 2>&1
        sudo apt-get install -y gawk sed grep coreutils >/dev/null 2>&1
    elif command -v yum >/dev/null 2>&1; then
        echo "📦 使用 yum 安装..." >&2
        sudo yum install -y gawk sed grep coreutils >/dev/null 2>&1
    elif command -v dnf >/dev/null 2>&1; then
        echo "📦 使用 dnf 安装..." >&2
        sudo dnf install -y gawk sed grep coreutils >/dev/null 2>&1
    elif command -v pacman >/dev/null 2>&1; then
        echo "📦 使用 pacman 安装..." >&2
        sudo pacman -S --noconfirm gawk sed grep coreutils >/dev/null 2>&1
    elif command -v apk >/dev/null 2>&1; then
        echo "📦 使用 apk 安装..." >&2
        sudo apk add gawk sed grep coreutils >/dev/null 2>&1
    elif command -v zypper >/dev/null 2>&1; then
        echo "📦 使用 zypper 安装..." >&2
        sudo zypper install -y gawk sed grep coreutils >/dev/null 2>&1
    else
        echo "❌ 无法识别包管理器,请手动安装: ${missing_commands[*]}" >&2
        echo "" >&2
        echo "💡 常见安装命令:" >&2
        echo "   Ubuntu/Debian: sudo apt-get install gawk sed grep coreutils" >&2
        echo "   CentOS/RHEL:   sudo yum install gawk sed grep coreutils" >&2
        echo "   Fedora:        sudo dnf install gawk sed grep coreutils" >&2
        echo "   Arch Linux:    sudo pacman -S gawk sed grep coreutils" >&2
        echo "   Alpine:        sudo apk add gawk sed grep coreutils" >&2
        return 1
    fi
    
    # 验证安装结果
    local still_missing=()
    for cmd in "${missing_commands[@]}"; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            still_missing+=("$cmd")
        fi
    done
    
    if [ ${#still_missing[@]} -eq 0 ]; then
        echo "✅ 所有命令安装成功" >&2
        return 0
    else
        echo "⚠️ 部分命令安装失败: ${still_missing[*]}" >&2
        return 1
    fi
}

# 智能命令调用:根据环境选择最佳实现
smart_grep() {
    local pattern="$1"
    shift
    local args=("$@")
    
    if [ "${COMMANDS_AVAILABLE:-false}" = true ] && command -v grep >/dev/null 2>&1; then
        # 使用原生grep
        grep "$pattern" "${args[@]}"
    else
        # 使用纯bash实现
        pure_bash_grep "$pattern" "${args[@]}"
    fi
}

smart_cut() {
    local delimiter=""
    local field=""
    local input=""
    
    # 解析参数
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -d) delimiter="$2"; shift 2 ;;
            -f) field="$2"; shift 2 ;;
            *) input="$1"; shift ;;
        esac
    done
    
    if [ "${COMMANDS_AVAILABLE:-false}" = true ] && command -v cut >/dev/null 2>&1; then
        # 使用原生cut
        if [ -n "$input" ]; then
            echo "$input" | cut -d"$delimiter" -f"$field"
        else
            cut -d"$delimiter" -f"$field"
        fi
    else
        # 使用纯bash实现
        pure_bash_cut -d "$delimiter" -f "$field" "$input"
    fi
}

smart_sed() {
    local expression="$1"
    shift
    
    if [ "${COMMANDS_AVAILABLE:-false}" = true ] && command -v sed >/dev/null 2>&1; then
        # 使用原生sed
        sed "$expression" "$@"
    else
        # 使用纯bash实现(简化版)
        pure_bash_sed "$expression" "$@"
    fi
}

# 纯bash实现的文本处理函数(备用)
pure_bash_grep() {
    local pattern="$1"
    local file="$2"
    local line
    
    if [ -f "$file" ]; then
        while IFS= read -r line; do
            case "$line" in
                *"$pattern"*) echo "$line" ;;
            esac
        done < "$file"
    else
        # 从stdin读取
        while IFS= read -r line; do
            case "$line" in
                *"$pattern"*) echo "$line" ;;
            esac
        done
    fi
}

pure_bash_cut() {
    local options="$1"
    local input="$2"
    local delimiter=" "
    local field=1
    
    # 解析cut参数
    case "$options" in
        *-d*)
            delimiter="${options#*-d}"
            if [ -z "$delimiter" ]; then
                delimiter=" "
            fi
            ;;
        *-f*)
            field="${options#*-f}"
            ;;
    esac
    
    # 处理输入
    if [ -n "$input" ]; then
        echo "$input" | while IFS="$delimiter" read -ra parts; do
            if [ ${#parts[@]} -ge "$field" ]; then
                echo "${parts[$((field-1))]}"
            fi
        done
    else
        while IFS="$delimiter" read -ra parts; do
            if [ ${#parts[@]} -ge "$field" ]; then
                echo "${parts[$((field-1))]}"
            fi
        done
    fi
}

# 环境检测和初始化
SHELL_ENV=$(detect_shell_environment)

case "$SHELL_ENV" in
    "WINDOWS_POWERSHELL")
        echo "⚠️ 检测到 Windows PowerShell 环境" >&2
        echo "💡 建议使用 Git Bash 运行此脚本以获得最佳体验:" >&2
        echo "   1. 安装 Git for Windows (如果未安装): https://git-scm.com/download/win" >&2
        echo "   2. 右键点击文件夹,选择 'Git Bash Here'" >&2
        echo "   3. 运行命令:./setup_train_env.sh" >&2
        echo "" >&2
        echo "🔧 当前环境的限制:" >&2
        echo "   • 缺少 grep, sed, cut 等命令" >&2
        echo "   • 某些功能可能较慢或不可用" >&2
        echo "" >&2
        read -p "❓ 是否继续在当前环境中运行?(y/N): " continue_powershell
        if [[ ! "$continue_powershell" =~ ^[Yy]$ ]]; then
            echo "🔄 请在 Git Bash 中运行脚本以获得最佳体验" >&2
            exit 1
        fi
        echo "🔧 启用兼容模式继续运行..." >&2
        ;;
    "LINUX_MINIMAL")
        echo "⚠️ 检测到精简 Linux 环境,缺少必要命令" >&2
        echo "💡 缺失命令: ${MISSING_COMMANDS[*]}" >&2
        echo "" >&2
        echo "🔧 自动安装选项:" >&2
        read -p "❓ 是否尝试自动安装缺失命令?(y/N): " install_missing
        if [[ "$install_missing" =~ ^[Yy]$ ]]; then
            if install_missing_commands_linux "${MISSING_COMMANDS[@]}"; then
                echo "✅ 命令安装成功,重新检测环境..." >&2
                SHELL_ENV=$(detect_shell_environment)
                if [ "$COMMANDS_AVAILABLE" = true ]; then
                    echo "✅ 环境准备完成" >&2
                else
                    echo "⚠️ 某些命令可能未正确安装,使用兼容模式" >&2
                fi
            else
                echo "❌ 自动安装失败,使用兼容模式" >&2
            fi
        else
            echo "🔧 使用内置兼容模式继续运行..." >&2
        fi
        ;;
    "LIMITED_SHELL")
        echo "⚠️ 检测到受限shell环境" >&2
        echo "💡 建议在支持标准命令的环境中运行此脚本" >&2
        echo "" >&2
        read -p "❓ 是否继续在当前环境中运行?(y/N): " continue_limited
        if [[ ! "$continue_limited" =~ ^[Yy]$ ]]; then
            echo "🔄 请在支持的环境中运行脚本" >&2
            exit 1
        fi
        echo "🔧 使用兼容模式继续运行..." >&2
        ;;
    "GIT_BASH")
        echo "✅ Git Bash 环境检测成功,使用完整功能" >&2
        ;;
    "LINUX_BASH"|"MACOS_BASH"|"UNIX_COMPATIBLE")
        echo "✅ Unix 兼容环境检测成功,使用完整功能" >&2
        ;;
    *)
        echo "ℹ️ 未知shell环境,尝试自动适配" >&2
        ;;
esac

# ========================================
# 🛠️  全局变量(可从外部传入或默认)
# ========================================

# 开启调试跟踪(set -x)仅在显式需要时打开,避免把执行跟踪写入控制台/日志
# 可通过环境变量或命令行参数启用,如: DEBUG=1 bash setup_train_env.sh  或  bash setup_train_env.sh --debug
if [[ "${DEBUG:-0}" -eq 1 ]]; then
    set -x
fi

# 确保终端环境正常
export TERM="${TERM:-xterm-256color}"
export PYTHONIOENCODING=utf-8

# ========================================
# 🕒 脚本开始:记录开始时间
# ========================================
# 使用中国上海时区时间(兼容不同环境)
export TZ='Asia/Shanghai'
# sh_date: 使用 TZ=Asia/Shanghai 调用 date,保证在不同平台下输出为上海时间
sh_date() {
    # 优先使用系统时区数据(如果存在)
    if [ -r "/usr/share/zoneinfo/Asia/Shanghai" ]; then
        TZ='Asia/Shanghai' date "$@"
        return
    fi

    # 回退:如果系统缺少 zoneinfo,尝试使用 python/python3 将 UTC 时间 +8h 来格式化
    local args=("$@")
    local fmt=""
    local epoch=""
    local i
    for ((i=0;i<${#args[@]};i++)); do
        case "${args[i]}" in
            -d)
                # 支持 -d @EPOCH 或 -d @ EPOCH 两种形式
                if [ $((i+1)) -lt ${#args[@]} ]; then
                    val="${args[i+1]}"
                    if [ "${val}" = "@" ] && [ $((i+2)) -lt ${#args[@]} ]; then
                        epoch="@${args[i+2]}"
                        i=$((i+2))
                    else
                        epoch="${val}"
                        i=$((i+1))
                    fi
                fi
                ;;
            @*)
                epoch="${args[i]}"
                ;;
            +*)
                fmt="${args[i]}"
                ;;
            *)
                ;;
        esac
    done

    if [ -z "$fmt" ]; then
        fmt='+%Y-%m-%d %H:%M:%S'
    fi
    local pyfmt="${fmt#+}"

    # 选择 python 可执行文件
    local pycmd=python
    if ! command -v "$pycmd" >/dev/null 2>&1; then
        pycmd=python3
    fi
    if ! command -v "$pycmd" >/dev/null 2>&1; then
    # 无 python 可用,回退到系统 date(使用 sh_date 回退到上海时间或尽力保持一致)
    sh_date "$@"
        return
    fi

    if [ -n "$epoch" ]; then
        epoch="${epoch#@}"
        if [ -z "$epoch" ]; then
            # epoch 为空,回退到 sh_date(避免 python int('') 错误)
            sh_date "$@"
            return
        fi
        "$pycmd" - "$pyfmt" "$epoch" <<'PY'
import sys,datetime
try:
    fmt = sys.argv[1]
    epoch = int(sys.argv[2])
    # 使用时区感知的 UTC 时间并转换为上海时区(UTC+8)
    dt = datetime.datetime.fromtimestamp(epoch, datetime.timezone.utc).astimezone(datetime.timezone(datetime.timedelta(hours=8)))
    print(dt.strftime(fmt))
except Exception:
    pass
PY
    else
        "$pycmd" - "$pyfmt" <<'PY'
import sys,datetime
try:
    fmt = sys.argv[1]
    dt = datetime.datetime.now(datetime.timezone.utc).astimezone(datetime.timezone(datetime.timedelta(hours=8)))
    print(dt.strftime(fmt))
except Exception:
    pass
PY
    fi
}

# 记录脚本开始时间(epoch)
START_TIME=$(sh_date +%s)

# 在函数顶部添加:
local extra_index_url=""
local trusted_hosts=()

# 在参数解析循环中:
for arg in "$@"; do
    if [[ "$arg" == --index-url ]]; then
        index_url_next=true
    elif [[ "$arg" == --extra-index-url ]]; then
        extra_index_url_next=true
    elif [[ "$arg" == --trusted-host ]]; then
        trusted_host_next=true
    elif $index_url_next; then
        index_url="$arg"
        index_url_next=false
    elif $extra_index_url_next; then
        extra_index_url="$arg"
        extra_index_url_next=false
    elif $trusted_host_next; then
        trusted_hosts+=("$arg")
        trusted_host_next=false
    elif [[ "$arg" == --* ]]; then
        extra_args+=("$arg")
    else
        packages+=("$arg")
    fi
done

# ========================================
# 🛠️  全局变量(可从外部传入或默认)
# ========================================    
ENV_NAME="${ENV_NAME:-train_ss}"         # 虚拟环境名称
WORKSPACE="${WORKSPACE:-/mnt/workspace}" # 工作空间根目录(可外部传入)

# --- 修改 2: PLATFORM 优先外部传入 ---
PLATFORM="${PLATFORM:-auto}"             # 平台类型   
if [[ "$PLATFORM" == "auto" ]]; then
    PLATFORM=$(detect_platform)
fi

# ========================================
# 🛠️  跨平台虚拟环境检测函数
# ========================================
check_virtual_env_support() {
    local has_venv=false
    local has_virtualenv=false
    local has_conda=false
    local python_cmd=""
    
    echo "🔍 检测虚拟环境支持..."
    
    # 1. 检测 Python 命令
    if command -v python3 >/dev/null 2>&1; then
        python_cmd="python3"
    elif command -v python >/dev/null 2>&1; then
        python_cmd="python"
    fi
    
    if [ -z "$python_cmd" ]; then
        echo "❌ 未检测到 Python"
        return 1
    fi
    
    echo "✅ 检测到 Python: $python_cmd ($($python_cmd --version 2>&1))"
    
    # 2. 检测 venv 模块(Python 3.3+ 内置)
    if $python_cmd -m venv --help >/dev/null 2>&1; then
        has_venv=true
        echo "✅ 支持 venv 模块"
    else
        echo "❌ 不支持 venv 模块"
    fi
    
    # 3. 检测 virtualenv(第三方包)
    if command -v virtualenv >/dev/null 2>&1; then
        has_virtualenv=true
        echo "✅ 支持 virtualenv: $(virtualenv --version 2>&1)"
    elif $python_cmd -m virtualenv --help >/dev/null 2>&1; then
        has_virtualenv=true
        echo "✅ 支持 virtualenv (通过 python -m)"
    else
        echo "❌ 不支持 virtualenv"
    fi
    
    # 4. 检测 conda
    if command -v conda >/dev/null 2>&1; then
        has_conda=true
        echo "✅ 支持 conda: $(conda --version 2>&1)"
    else
        echo "❌ 不支持 conda"
    fi
    
    # 5. 总结
    echo ""
    echo "📋 虚拟环境支持总结:"
    if $has_conda; then
        echo "  🐍 Conda: 可用 (推荐)"
    fi
    if $has_venv; then
        echo "  📦 venv: 可用 (Python 内置)"
    fi
    if $has_virtualenv; then
        echo "  🔧 virtualenv: 可用 (第三方)"
    fi
    
    if ! $has_venv && ! $has_virtualenv && ! $has_conda; then
        echo "  ❌ 无可用的虚拟环境工具"
        echo ""
        echo "💡 建议安装方法:"
        if [[ "$OSTYPE" == "linux-gnu"* ]]; then
            echo "  Ubuntu/Debian: sudo apt update && sudo apt install python3-venv"
            echo "  CentOS/RHEL: sudo yum install python3-venv 或 sudo dnf install python3-venv"
        elif [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
            echo "  Windows: pip install virtualenv 或安装 Anaconda/Miniconda"
        fi
        echo "  通用方法: pip install virtualenv"
        return 1
    fi
    
    return 0
}

# ========================================
# 🛠️  封装函数:get_activate_cmd 获取环境激活cmd命令
# ========================================
get_activate_cmd() {
    local ENV_NAME="${1:-train_ss}"
    local VENV_PATH="${2:-/mnt/workspace/envs/${ENV_NAME}}"

    local ACTIVATE_CMD=""
    local ENV_TYPE=""
    local OS_TYPE="linux"

    # 1. 判断操作系统
    if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "win32" ]]; then
        OS_TYPE="windows"
    elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
        OS_TYPE="linux"
    else
        OS_TYPE="linux"
    fi
    echo "🔍 检测到操作系统: $OS_TYPE"

    # 2. 判断环境类型
    if command -v conda &> /dev/null; then
        if conda env list 2>/dev/null | smart_grep -q "^\s*${ENV_NAME}\s*" ; then
            ENV_TYPE="conda"
            echo "📦 检测到 Conda 环境: ${ENV_NAME}"
        fi
    fi

    if [[ -z "$ENV_TYPE" ]] && [ -f "${VENV_PATH}/bin/activate" ]; then
        ENV_TYPE="venv"
        echo "📦 检测到 venv 环境: ${VENV_PATH}"
    fi

    if [[ -z "$ENV_TYPE" ]]; then
        echo "❌ 错误:未找到环境 '${ENV_NAME}',既不是 conda 也不是 venv。"
        export ACTIVATE_CMD="NOT_FOUND"
        export DETECTED_ENV_TYPE="unknown"
        return 1
    fi

    # 3. 生成激活命令
    case "${ENV_TYPE}_${OS_TYPE}" in
        "conda_linux"|"conda_windows")
            if conda --version &> /dev/null; then
                local CONDA_VERSION=$(conda --version | smart_extract_field 2)
                if version_compare "4.4" "$CONDA_VERSION"; then
                    ACTIVATE_CMD="conda activate ${ENV_NAME}"
                else
                    ACTIVATE_CMD="source activate ${ENV_NAME}"
                fi
            else
                ACTIVATE_CMD="source activate ${ENV_NAME}"
            fi
            ;;

        "venv_linux")
            ACTIVATE_CMD="source ${VENV_PATH}/bin/activate"
            ;;

        "venv_windows")
            ACTIVATE_CMD="${VENV_PATH}\\Scripts\\activate.bat"
            ;;

        *)
            ACTIVATE_CMD="UNKNOWN"
            ;;
    esac

    # 导出变量供外部使用
    export ACTIVATE_CMD
    export DETECTED_ENV_TYPE="$ENV_TYPE"
    echo "✅ ACTIVATE_CMD: ${ACTIVATE_CMD}"
}


# ========================================
# 🛠️  定义 log_success 函数
# ========================================
log_success() {
    local PLATFORM="$1"
    local ENV_NAME="$2"
    local LOG_FILE_PATH="$3"
    local WORKSPACE="$4"
    local ACTIVATE_CMD="$5"
    local DETECTED_ENV_TYPE="$6"

    # 获取 GPU 信息
    local GPU_INFO
    GPU_INFO=$(python -c '
import torch
if torch.cuda.is_available():
    print(f"✅ {torch.cuda.get_device_name(0)} (CUDA {torch.version.cuda})")
else:
    print("❌ 未启用")
' 2>/dev/null) || GPU_INFO="❌ 导入 PyTorch 失败"

    local CURRENT_TIME=$(sh_date '+%Y-%m-%d %H:%M:%S %Z')
    local END_TIME=$(sh_date +%s)
    local ELAPSED_TIME=$((END_TIME - START_TIME))
    local DURATION="$((ELAPSED_TIME / 60))m$((ELAPSED_TIME % 60))s"

    # 💡 1. 输出到终端(彩色,仅 stderr)
    {
    echo
    echo -e "✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨"
    echo -e "🎉 \033[1;33m环境配置成功!All Set!\033[0m 🎉"
    echo
    echo -e "📍 平台: \033[1;36m$PLATFORM\033[0m"
    echo -e "📍 环境: \033[1;32m$ENV_NAME\033[0m"
    echo -e "📍 环境类型: \033[1;35m${DETECTED_ENV_TYPE^}\033[0m"  # 首字母大写
    echo -e "📍 日志: \033[3;37m$LOG_FILE\033[0m"
    echo
    echo -e "💡 激活命令: \033[1;33m$ACTIVATE_CMD\033[0m"  # ✅ 使用动态命令
    echo -e "💡 GPU 支持: \033[1;32m$GPU_INFO\033[0m"
    echo
    echo -e "✅ 当前环境已就绪,可直接运行训练脚本。"
    echo -e "🕒 完成时间: $CURRENT_TIME"
    echo -e "⏱️  执行耗时: $DURATION (开始: $(sh_date -d "@${START_TIME}" '+%H:%M:%S'))"
    echo -e ""
    echo -e "支持的 CLI 参数(可直接用于命令行)"
    echo -e "--help, -h  说明:显示中文帮助(直接输出到终端,不写入日志),随后脚本退出。"
    echo -e "用法示例:bash setup_train_env.sh --help  或./setup_train_env.sh --help"
    echo -e "--debug, -d  说明:启用调试模式(等同于设置 DEBUG=1),脚本会执行 set -x 输出命令跟踪(用于排查)。"
    echo -e "用法示例:bash setup_train_env.sh --debug 或./setup_train_env.sh --debug "
    echo -e "✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨"
    echo
    } >&2

    # 📄 2. 写入日志(纯文本,结构化)
    {
    echo "----------------------------------------"
    echo "✅ ENV_SETUP_SUCCESS"
    echo "PLATFORM: $PLATFORM"
    echo "ENV_NAME: $ENV_NAME"
    echo "ENV_TYPE: $DETECTED_ENV_TYPE"
    echo "LOG_FILE: $LOG_FILE"
    echo "ACTIVATE_CMD: $ACTIVATE_CMD"
    echo "GPU_INFO: $GPU_INFO"
    echo "START_TIME: $(sh_date -d "@${START_TIME}" '+%Y-%m-%d %H:%M:%S')"
    echo "COMPLETION_TIME: $CURRENT_TIME"
    echo "ELAPSED_SECONDS: $ELAPSED_TIME"
    echo "EXECUTION_DURATION: $DURATION"
    echo "STATUS: OK"
    echo "----------------------------------------"
    } >> "$LOG_FILE" 2>&1
}


# 函数:记录带时间戳的日志
log() {
    echo "[$(sh_date '+%Y-%m-%d %H:%M:%S %Z')] $1" | tee -a "$LOG_FILE"
}



# 错误处理函数
on_error() {
    local exit_code=$?
    cat >&2 << EOF

💥 脚本执行失败!
   行号: $1
   命令: $2
   退出码: $exit_code
   日志: ${LOG_FILE:-未定义}

🔧 建议:
   - 检查 conda 是否可用: conda --version
   - 检查 D:/logs 是否可写
   - 手动运行失败命令

EOF
    exit "$exit_code"
}
trap 'on_error $LINENO "$BASH_COMMAND"' ERR

# 工具函数
info()  { echo "ℹ️  $1"; }
warn()  { echo "⚠️  $1"; }

# 增强的错误函数:自动输出详细错误信息并保存到日志
error() {
    local error_msg="$*"
    local error_time=$(sh_date '+%Y-%m-%d %H:%M:%S %Z')
    local error_details=""
    
    # 构建详细错误信息
    error_details="
====================================
❌ 错误发生时间: $error_time
❌ 错误信息: $error_msg
❌ 错误位置: ${BASH_SOURCE[1]:-未知}:${BASH_LINENO[0]:-未知}
❌ 当前工作目录: $(pwd)
❌ 环境信息:
   - PLATFORM: ${PLATFORM:-未设置}
   - ENV_NAME: ${ENV_NAME:-未设置}
   - WORKSPACE: ${WORKSPACE:-未设置}
   - Python可用性: $(command -v python >/dev/null 2>&1 && echo "python: $(python --version 2>&1)" || echo "python: 不可用")$(command -v python3 >/dev/null 2>&1 && echo " | python3: $(python3 --version 2>&1)" || echo " | python3: 不可用")
   - Conda可用性: $(command -v conda >/dev/null 2>&1 && echo "conda: $(conda --version 2>&1)" || echo "conda: 不可用")
   - 当前激活环境: ${CONDA_DEFAULT_ENV:-无}
====================================
"
    
    # 输出到控制台
    echo "$error_details" >&2
    
    # 保存到日志文件(如果已设置)
    if [[ -n "${LOG_FILE:-}" && -w "$(dirname "$LOG_FILE")" ]]; then
        echo "$error_details" >> "$LOG_FILE" 2>/dev/null || true
    fi
    
    exit 1
}

# 增强的错误追踪函数:用于关键操作失败时的详细诊断
trace_error() {
    local operation="$1"
    local cmd_output="$2"
    local exit_code="${3:-$?}"
    local error_time=$(sh_date '+%Y-%m-%d %H:%M:%S %Z')
    
    local trace_details="
🔍 ========== 错误追踪报告 ==========
⏰ 时间: $error_time
🎯 操作: $operation
💥 退出码: $exit_code
📍 位置: ${BASH_SOURCE[1]:-未知}:${BASH_LINENO[0]:-未知}
📂 工作目录: $(pwd)

📝 命令输出:
$cmd_output

🔧 环境诊断:
   - PLATFORM: ${PLATFORM:-未设置}
   - ENV_NAME: ${ENV_NAME:-未设置}
   - WORKSPACE: ${WORKSPACE:-未设置}
   - LOG_FILE: ${LOG_FILE:-未设置}
   
🐍 Python 环境:
   - which python: $(which python 2>/dev/null || echo "未找到")
   - which python3: $(which python3 2>/dev/null || echo "未找到")
   - PYTHONPATH: ${PYTHONPATH:-未设置}
   
🅰️ Anaconda/Miniconda:
   - which conda: $(which conda 2>/dev/null || echo "未找到")
   - CONDA_DEFAULT_ENV: ${CONDA_DEFAULT_ENV:-未设置}
   - CONDA_PREFIX: ${CONDA_PREFIX:-未设置}
   
💾 磁盘空间:
$(df -h . 2>/dev/null | tail -1 || echo "无法获取磁盘信息")

🌐 网络连接测试:
$(ping -c 1 8.8.8.8 >/dev/null 2>&1 && echo "✅ 网络连接正常" || echo "❌ 网络连接异常")
==================================================
"
    
    # 输出到控制台
    echo "$trace_details" >&2
    
    # 保存到日志文件
    if [[ -n "${LOG_FILE:-}" ]]; then
        echo "$trace_details" >> "$LOG_FILE" 2>/dev/null || true
    fi
}

ok()    { echo "✅ $1"; }


# 平台检测 + 变量初始化
# === 在变量定义后,立即设置日志并重定向 ===
# 先通过平台检测确定 LOG_DIR
detect_platform() {
    case "$OSTYPE" in
        msys*|mingw*|cygwin*)
            echo "local-windows"
            return
            ;;
    esac
    [[ -d "/home/aistudio" ]] && echo "aistudio" && return
    [[ -n "${MODELSCOPE_CACHE:-}" ]] && echo "modelscope" && return
    [[ -n "${SSH_CLIENT:-}" ]] && echo "server" && return
    [[ -d "/mnt/workspace" ]] && echo "server" && return
    echo "local-linux"
}

setup_paths() {
    case "$PLATFORM" in
        "local-windows")
            DEFAULT_DRIVE="D:/"
            if [[ -w "$DEFAULT_DRIVE" ]]; then
                WORKSPACE="$DEFAULT_DRIVE/workspace"
                LOG_DIR="$DEFAULT_DRIVE/logs"
            else
                WORKSPACE="./workspace"
                LOG_DIR="./logs"
            fi
            ;;
        "aistudio")
            WORKSPACE="/home/aistudio"
            LOG_DIR="/home/aistudio/logs"
            ;;
        "modelscope")
            WORKSPACE="/mnt/workspace"
            LOG_DIR="/mnt/workspace/logs"
            ;;
        "server"|"local-linux")
            WORKSPACE="./workspace"
            LOG_DIR="./logs"
            ;;
        *)
            warn "未知平台: $PLATFORM,使用默认配置"
            WORKSPACE="./workspace"
            LOG_DIR="./logs"
            ;;
    esac
}

# 🌐 检测平台
PLATFORM=$(detect_platform)
info "🌍 检测到平台: $PLATFORM"

# 🛠 设置路径
setup_paths

# ✅ 创建目录
mkdir -p "$WORKSPACE" || {
    error "无法创建 WORKSPACE: $WORKSPACE"
    error "💡 请检查该路径是否存在且有写权限"
}

mkdir -p "$LOG_DIR" || {
    error "无法创建日志目录: $LOG_DIR"
    error "💡 请检查该路径是否存在且有写权限"
}

# ✅ 定义日志文件(使用上海时区时间)
LOG_FILE="$LOG_DIR/setup_env_$(sh_date +%Y%m%d_%H%M%S).log"

# 规范化路径工具:将连续的多个 '/' 合并为一个(保留 UNC 前缀 '//')
normalize_path() {
    local p="$1"
    # 针对 Windows 下(MSYS/Cygwin)路径做专门处理
    if [[ "${PLATFORM:-}" == "local-windows" || "$p" =~ ^[A-Za-z]: ]]; then
        # 将反斜杠转换为正斜杠
        local out="${p//\\//}"
        # 把连续多个 '/' 合并为一个
        while [[ "$out" == *//* ]]; do out="${out//\/\//\/}"; done
        # 确保驱动器后为单个斜杠,例如 D:/logs 而非 D:logs 或 D://logs
        if [[ "$out" =~ ^([A-Za-z]):/*(.*) ]]; then
            local drive="${BASH_REMATCH[1]}"
            local rest="${BASH_REMATCH[2]}"
            printf '%s' "${drive}:/${rest}"
            return
        fi
        printf '%s' "$out"
        return
    fi

    # 默认行为:合并重复斜杠(保留 UNC 前缀 '//')
    if [[ "$p" == '//*' ]]; then
        local lead='//'
        local rest="${p#//}"
        while [[ "$rest" == *//* ]]; do rest="${rest//\/\//\/}"; done
        printf '%s' "$lead$rest"
    else
        local out="$p"
        while [[ "$out" == *//* ]]; do out="${out//\/\//\/}"; done
        printf '%s' "$out"
    fi
}

# 🎯 智能包检查:效率优先,准确保障
# 
# � 验证策略分析:
#   - pip show 未找到 → 99.9% 准确(直接返回未安装)
#   - pip show 找到 + 关键包 → 需要 import 验证(torch, numpy等)
#   - pip show 找到 + 大型包 → 检查 Location 存在性(轻量级)
#   - pip show 找到 + 普通包 → 直接信任(高效)
#
# 🚀 性能优化:
#   - 90% 包只用 pip show(1-2ms)
#   - 5% 包加 Location 检查(+1ms)  
#   - 5% 关键包用 import 验证(+50ms)
check_package_installed() {
    local package="$1"
    local package_name=""
    
    # 提取包名(去除版本号和其他修饰符)
    if [[ "$package" =~ ^([a-zA-Z0-9_-]+) ]]; then
        package_name="${BASH_REMATCH[1]}"
    else
        package_name="$package"
    fi
    
    # 特殊处理一些包名映射
    case "$package_name" in
        "torch")
            package_name="torch"
            # 对于torch,需要特别检查是否为GPU版本
            if pip show "$package_name" >/dev/null 2>&1; then
                # 检查是否为GPU版本
                local torch_gpu_check=""
                torch_gpu_check=$(python -c "
try:
    import torch
    version = torch.__version__
    is_gpu = '+cu' in version or torch.cuda.is_available()
    
    # 检查CUDA版本兼容性
    if is_gpu and '+cu' in version:
        # 提取CUDA版本号 (如 +cu118, +cu128)
        cuda_parts = version.split('+cu')
        if len(cuda_parts) > 1:
            cuda_version = cuda_parts[1]
            print('INSTALLED_CUDA_' + cuda_version)
        else:
            print('GPU_VERSION_OK')
    elif is_gpu:
        print('GPU_VERSION_OK')
    else:
        print('CPU_VERSION_ON***')
except:
    print('IMPORT_FAILED')
" 2>/dev/null)
                
                # 检查是否需要CUDA版本升级
                if echo "$torch_gpu_check" | smart_grep -q "GPU_VERSION_OK"; then
                    return 0  # GPU版本已安装且CUDA可用
                elif echo "$torch_gpu_check" | smart_grep -q "INSTALLED_CUDA_"; then
                    # 检查CUDA版本是否匹配当前环境需求
                    local installed_cuda=$(echo "$torch_gpu_check" | smart_sed 's/INSTALLED_CUDA_//')
                    local required_cuda=""
                    
                    # 从TORCH_INDEX提取需求的CUDA版本
                    if echo "$TORCH_INDEX" | smart_grep -q "cu118"; then
                        required_cuda="118"
                    elif echo "$TORCH_INDEX" | smart_grep -q "cu128"; then
                        required_cuda="128"
                    elif echo "$TORCH_INDEX" | smart_grep -q "cu117"; then
                        required_cuda="117"
                    fi
                    
                    if [ "$installed_cuda" = "$required_cuda" ]; then
                        return 0  # CUDA版本匹配,无需重装
                    else
                        info "🔄 检测到CUDA版本不匹配: 已安装cu$installed_cuda, 需要cu$required_cuda"
                        return 1  # 需要升级CUDA版本
                    fi
                elif echo "$torch_gpu_check" | smart_grep -q "CPU_VERSION_ON***"; then
                    # CPU版本已安装,但我们需要GPU版本
                    return 1  # 需要重新安装GPU版本
                else
                    return 1  # 安装有问题,需要重新安装
                fi
            else
                return 1  # 未安装
            fi
            ;;
        "torchvision")
            package_name="torchvision"
            ;;
        "torchaudio") 
            package_name="torchaudio"
            ;;
        "opencv-python"|"opencv-contrib-python")
            package_name="cv2"
            ;;
        "pillow")
            package_name="PIL"
            ;;
        "scikit-learn")
            package_name="sklearn"
            ;;
        "beautifulsoup4")
            package_name="bs4"
            ;;
        "pyyaml")
            package_name="yaml"
            ;;
    esac
    
    # 🚀 高效的包检查策略:平衡效率和准确性
    
    # Step 1: 快速检查 - pip show (高效,覆盖99%的情况)
    local pip_show_result=""
    pip_show_result=$(pip show "$package_name" 2>/dev/null)
    local pip_show_exit_code=$?
    
    # 如果 pip show 显示未安装,直接返回未安装(这个结果是可靠的)
    if [ $pip_show_exit_code -ne 0 ]; then
        return 1  # 未安装,pip show未找到包
    fi
    
    # Step 2: pip show 显示已安装,但需要额外验证的情况
    local need_import_check=false
    
    # 检查是否需要额外验证(仅在这些情况下)
    case "$package_name" in
        # 关键包:安装错误代价高,需要双重验证
        torch|tensorflow|numpy|scipy)
            need_import_check=true
            ;;
        # 大型包:安装时间长,需要确保真正可用
        torchvision|torchaudio|opencv*|pillow)
            # 检查包的Location是否存在(轻量级验证)
            local package_location=""
            package_location=$(echo "$pip_show_result" | smart_grep "Location:" | smart_cut -d' ' -f2)
            if [ -n "$package_location" ] && [ -d "$package_location" ]; then
                need_import_check=false  # 位置存在,trust pip show
            else
                need_import_check=true   # 位置不存在,需要import验证
            fi
            ;;
        # 普通包:pip show结果可信,不需要额外验证
        *)
            need_import_check=false
            ;;
    esac
    
    # Step 3: 仅在必要时进行 import 验证(保持高效)
    if [ "$need_import_check" = true ]; then
        # 对关键包进行实际导入测试
        if python -c "import $package_name" >/dev/null 2>&1; then
            return 0  # 双重验证通过,确实已安装
        else
            return 1  # pip show说已安装,但实际导入失败(包损坏)
        fi
    else
        # pip show 结果可信,直接信任
        return 0  # 已安装
    fi
}

# 🚀 智能包安装函数:过滤已安装的包
filter_installed_packages() {
    local packages=("$@")
    local uninstalled_packages=()
    local installed_packages=()
    
    # 将信息输出重定向到stderr,避免污染返回值
    echo "🔍 正在检查包安装状态..." >&2
    
    for package in "${packages[@]}"; do
        if check_package_installed "$package"; then
            installed_packages+=("$package")
            echo "ℹ️  ✅ $package - 已安装,跳过" >&2
        else
            uninstalled_packages+=("$package")
            echo "ℹ️  📦 $package - 需要安装" >&2
        fi
    done
    
    # 显示统计信息 - 重定向到stderr
    if [ ${#installed_packages[@]} -gt 0 ]; then
        echo "ℹ️  📊 跳过已安装的包 (${#installed_packages[@]}个): ${installed_packages[*]}" >&2
    fi
    
    if [ ${#uninstalled_packages[@]} -gt 0 ]; then
        echo "ℹ️  ⬇️  需要安装的包 (${#uninstalled_packages[@]}个): ${uninstalled_packages[*]}" >&2
    else
        echo "ℹ️  🎉 所有包都已安装,无需下载!" >&2
    fi
    
    # 返回未安装的包列表(仅包名,无额外输出)
    for pkg in "${uninstalled_packages[@]}"; do
        echo "$pkg"
    done
}

# 规范化 LOG_DIR 和 LOG_FILE,避免出现 D://logs 这样的路径
LOG_DIR=$(normalize_path "$LOG_DIR")
LOG_FILE=$(normalize_path "$LOG_FILE")

# ✅ 开始重定向(从现在开始,所有输出都进日志)
# 优先使用 tee 将输出同时写到日志和控制台(需要 bash 的 process substitution)
if command -v tee >/dev/null 2>&1; then
    # 将 stdout/stderr 都通过 tee 追加到日志文件,并继续在控制台显示
    if ! exec > >(tee -a "$LOG_FILE") 2> >(tee -a "$LOG_FILE" >&2); then
        echo "❌ 无法通过 tee 重定向到日志文件: $LOG_FILE" >&2
        exit 1
    fi
else
    # 如果系统没有 tee,提醒用户并保持在控制台输出(推荐:安装 tee 或使用外部管道运行脚本)
    cat >&2 <<'EOF'
⚠️  未检测到系统命令 "tee"。

为保证同时在控制台显示并写入日志,建议执行以下任一操作:
 1) 在系统上安装 tee(Ubuntu/Debian: sudo apt update && sudo apt install coreutils -y)。
 2) 或在运行脚本时使用外部管道:
      bash setup_train_env.sh 2>&1 | tee -a "${LOG_FILE}"

脚本将继续在控制台输出(不再自动把所有输出重定向到日志文件),
如果你选择使用外部管道运行,日志会被完整保存到上面的文件。
EOF
    # 不执行 exec 重定向,保留控制台输出,按用户要求不自动改为 FIFO 回退
fi

# 🌟 此后所有输出都记录在日志中
echo "----------------------------------------"
info "✅ 日志重定向已生效"
info "✅ 日志文件已创建: $LOG_FILE"
info "🔧 开始执行后续安装步骤..."
echo "----------------------------------------"
log "安装脚本开始执行"

# 🔍 检测虚拟环境支持情况
echo "----------------------------------------"
check_virtual_env_support
if [ $? -ne 0 ]; then
    warn "⚠️  虚拟环境支持不完整,脚本可能无法正常创建环境"
    warn "💡 建议先安装虚拟环境工具再继续"
fi
echo "----------------------------------------"

PYTHON_VERSIONS=("3.10.13" "3.9" "3.8" "3.7")

# -----------------------------
# 🔍 检查 Conda 是否可用,否则使用 venv
# -----------------------------
create_or_use_env() {
    local env_name=$1
    local py_versions=("${@:2}")

    # 定义统一路径(用于 venv 和 Linux 上的 Conda)
    ENV_ROOT="$WORKSPACE/envs"
    ENV_PATH="$ENV_ROOT/$env_name"

    # -----------------------------
    # 1. 检查 Conda 是否可用
    # -----------------------------
    if command -v conda &> /dev/null; then
        # 判断是否是 Linux 系统
        if [[ "$OSTYPE" == "linux-gnu"* ]]; then
            info "✅ Linux + Conda:使用统一路径 $ENV_PATH"

            # 检查指定路径的环境是否存在且完整
            if [ -d "$ENV_PATH" ] && [ -f "$ENV_PATH/bin/python" ]; then
                ok "Conda 环境已存在: $ENV_PATH"
            else
                # 清理残缺环境
                if [ -d "$ENV_PATH" ]; then
                    warn "⚠️  环境目录不完整,正在清理: $ENV_PATH"
                    rm -rf "$ENV_PATH"
                fi

                info "🆕 创建 Conda 环境: $ENV_PATH"
                local creation_output=""
                local creation_failed=false
                for py_ver in "${py_versions[@]}"; do
                    creation_output=$(conda create -p "$ENV_PATH" python="$py_ver" --yes -v 2>&1)
                    if [ $? -eq 0 ]; then
                        ok "✅ Conda 环境创建成功"
                        creation_failed=false
                        break
                    else
                        creation_failed=true
                    fi
                done

                if [ "$creation_failed" = true ] || [ ! -f "$ENV_PATH/bin/python" ]; then
                    trace_error "Conda 环境创建失败" "$creation_output"
                    error "Conda 环境创建失败: $ENV_PATH"
                    exit 1
                fi
            fi

            # 激活 Conda 环境(使用完整路径)
            local activation_output=""
            eval "$(conda shell.bash hook)" 2>/dev/null || true
            activation_output=$(conda activate "$ENV_PATH" 2>&1)
            local activation_exit_code=$?
            if [ $activation_exit_code -ne 0 ]; then
                trace_error "Conda 环境激活失败" "$activation_output" "$activation_exit_code"
                error "Conda 环境激活失败: $ENV_PATH"
            fi
            return $activation_exit_code

        else
            # ✅ 非 Linux(如 Windows),使用 Conda 默认路径
            info "✅ Conda 可用(非 Linux),使用默认路径: $env_name"

            if conda env list | smart_grep -E "^$env_name[[:space:]]" > /dev/null; then
                ok "Conda 环境已存在: $env_name"
            else
                info "🆕 创建 Conda 环境: $env_name"
                local conda_creation_output=""
                conda_creation_output=$(conda create -n "$env_name" python="${py_versions[0]}" --yes 2>&1)
                local conda_creation_exit_code=$?
                if [ $conda_creation_exit_code -ne 0 ]; then
                    trace_error "Conda 环境创建失败 (非Linux)" "$conda_creation_output" "$conda_creation_exit_code"
                    error "Conda 环境创建失败: $env_name"
                fi
            fi

            local conda_activation_output=""
            eval "$(conda shell.bash hook)" 2>/dev/null || true
            conda_activation_output=$(conda activate "$env_name" 2>&1)
            local conda_activation_exit_code=$?
            if [ $conda_activation_exit_code -ne 0 ]; then
                trace_error "Conda 环境激活失败 (非Linux)" "$conda_activation_output" "$conda_activation_exit_code"
                error "Conda 环境激活失败: $env_name"
            fi
            return $conda_activation_exit_code
        fi

    # -----------------------------
    # 2. Conda 不可用,使用 venv(Linux 和 Windows 都用统一路径)
    # -----------------------------
    else
        info "⚠️  Conda 未安装,使用 venv: $ENV_PATH"

        if [ -d "$ENV_PATH" ]; then
            if [ -f "$ENV_PATH/bin/activate" ] && [ -f "$ENV_PATH/bin/python" ]; then
                ok "✅ venv 环境已存在且完整"
            else
                warn "⚠️  venv 不完整,正在清理"
                rm -rf "$ENV_PATH"
            fi
        fi

        if [ ! -d "$ENV_PATH" ]; then
            mkdir -p "$ENV_ROOT"
            local success=false
            local venv_creation_output=""

            for py_ver in "${py_versions[@]}"; do
                if command -v "python$py_ver" &> /dev/null; then
                    venv_creation_output=$(python"$py_ver" -m venv "$ENV_PATH" 2>&1)
                    if [ $? -eq 0 ]; then
                        success=true
                        break
                    fi
                elif command -v "python${py_ver%.*}" &> /dev/null; then
                    venv_creation_output=$(python"${py_ver%.*}" -m venv "$ENV_PATH" 2>&1)
                    if [ $? -eq 0 ]; then
                        success=true
                        break
                    fi
                fi
            done

            if [ "$success" = false ]; then
                trace_error "标准 venv 创建失败" "$venv_creation_output"
                info "⚠️  标准 venv 创建失败,使用 --without-pip + 手动安装 pip"
                local without_pip_output=""
                without_pip_output=$(python3 -m venv "$ENV_PATH" --without-pip 2>&1)
                local without_pip_exit_code=$?
                
                if [ $without_pip_exit_code -ne 0 ]; then
                    trace_error "venv --without-pip 创建失败" "$without_pip_output" "$without_pip_exit_code"
                    error "❌ 虚拟环境创建完全失败:$ENV_PATH"
                fi

                if [ -f "$ENV_PATH/bin/python" ]; then
                    info "📥 正在手动安装 pip..."

                    # ✅ 使用清华镜像,避免网络问题
                    GET_PIP_URL="https://pypi.tuna.tsinghua.edu.cn/bootstrap/pip/get-pip.py"
                    GET_PIP_PY="/tmp/get-pip-$$.py"

                    # ✅ 添加超时,防止卡死
                    local curl_output=""
                    curl_output=$(curl -fsSL --connect-timeout 10 --max-time 30 "$GET_PIP_URL" -o "$GET_PIP_PY" 2>&1)
                    local curl_exit_code=$?
                    
                    if [ $curl_exit_code -eq 0 ]; then
                        local pip_install_output=""
                        pip_install_output=$("$ENV_PATH/bin/python" "$GET_PIP_PY" --quiet --no-warn-script-location 2>&1)
                        local pip_exit=$?
                        rm -f "$GET_PIP_PY"
                        if [ $pip_exit -eq 0 ]; then
                            ok "✅ pip 安装成功"
                        else
                            trace_error "pip 手动安装失败" "$pip_install_output" "$pip_exit"
                            error "❌ pip 安装失败"
                            exit 1
                        fi
                    else
                        trace_error "下载 get-pip.py 失败" "$curl_output" "$curl_exit_code"
                        error "❌ 下载 get-pip.py 失败(URL: $GET_PIP_URL)"
                        error "💡 建议检查网络或更换镜像源"
                        exit 1
                    fi
                else
                    trace_error "虚拟环境创建失败" "无法创建 $ENV_PATH/bin/python"
                    error "❌ 虚拟环境创建失败:$ENV_PATH/bin/python 不存在"
                    exit 1
                fi
            fi
        fi

        # 激活 venv
        if [ -f "$ENV_PATH/bin/activate" ]; then
            local venv_activation_output=""
            venv_activation_output=$(source "$ENV_PATH/bin/activate" 2>&1)
            local venv_activation_exit_code=$?
            if [ $venv_activation_exit_code -eq 0 ]; then
                ok "✅ venv 环境激活成功: $ENV_PATH"
            else
                trace_error "venv 环境激活失败" "$venv_activation_output" "$venv_activation_exit_code"
                error "❌ venv 激活失败: $ENV_PATH/bin/activate 存在但激活失败"
                exit 1
            fi
        else
            trace_error "venv 激活文件缺失" "activate 脚本不存在: $ENV_PATH/bin/activate"
            error "❌ venv 激活失败: $ENV_PATH/bin/activate 不存在"
            exit 1
        fi
    fi
}

# -----------------------------
# 多源容错安装函数
# -----------------------------
# robust_pip_install()调用举例
# # 安装普通包
# robust_pip_install "requests" "flask"

# # 安装 PyTorch(带 extra-index-url)
# robust_pip_install "torch" "torchvision" \
#     --index-url "https://download.pytorch.org/whl/cu118" \
#     --extra-index-url "https://pypi.org/simple" \
#     --trusted-host "pypi.org"

# # 安装私有包
# robust_pip_install "mypackage" \
#     --index-url "https://private-pypi.example.com/simple" \
#     --trusted-host "private-pypi.example.com"

robust_pip_install() {
    local packages=()
    local extra_args=()
    local index_url=""
    local extra_index_url=""
    local trusted_hosts=()
    
    local index_url_next=false
    local extra_index_url_next=false
    local trusted_host_next=false

    # 解析参数
    for arg in "$@"; do
        case "$arg" in
            --index-url)
                index_url_next=true
                ;;
            --extra-index-url)
                extra_index_url_next=true
                ;;
            --trusted-host)
                trusted_host_next=true
                ;;
            --*)
                if $index_url_next; then
                    index_url="$arg"
                    index_url_next=false
                elif $extra_index_url_next; then
                    extra_index_url="$arg"
                    extra_index_url_next=false
                elif $trusted_host_next; then
                    trusted_hosts+=("$arg")
                    trusted_host_next=false
                else
                    extra_args+=("$arg")
                fi
                ;;
            *)
                if $index_url_next; then
                    index_url="$arg"
                    index_url_next=false
                elif $extra_index_url_next; then
                    extra_index_url="$arg"
                    extra_index_url_next=false
                elif $trusted_host_next; then
                    trusted_hosts+=("$arg")
                    trusted_host_next=false
                else
                    packages+=("$arg")
                fi
                ;;
        esac
    done

    # 如果没传包,直接返回
    if [ ${#packages[@]} -eq 0 ]; then
        warn "⚠️  robust_pip_install: 未指定包"
        return 1
    fi

    # 🚀 智能过滤:检查已安装的包,避免重复下载
    local filtered_packages=()
    
    # 使用子shell确保输出分离,并安静地获取过滤结果
    {
        info "🔍 正在检查包安装状态以避免重复下载..."
        readarray -t filtered_packages < <(filter_installed_packages "${packages[@]}")
    }
    
    # 如果所有包都已安装,直接返回成功
    if [ ${#filtered_packages[@]} -eq 0 ]; then
        ok "🎉 所有包都已安装,跳过下载!"
        return 0
    fi
    
    # 更新包列表为需要安装的包
    packages=("${filtered_packages[@]}")
    info "📦 将安装 ${#packages[@]} 个包: ${packages[*]}"

    local max_retries=3
    local total_attempts=0
    local max_total_attempts=6

    local mirrors=(
        "https://pypi.tuna.tsinghua.edu.cn/simple/|pypi.tuna.tsinghua.edu.cn"
        "https://mirrors.aliyun.com/pypi/simple/|mirrors.aliyun.com"
        "https://pypi.douban.com/simple/|pypi.douban.com"
        "https://download.pytorch.org/whl/cu118|download.pytorch.org"
        "https://pypi.org/simple|pypi.org"
    )

    info "🚀 开始安装包: ${packages[*]}"
    
    # 快速检测网络连通性
    info "🌐 检测网络连接..."
    local network_ok=false
    for test_host in "pypi.tuna.tsinghua.edu.cn" "mirrors.aliyun.com" "pypi.org"; do
        if ping -c 1 -W 3 "$test_host" >/dev/null 2>&1; then
            network_ok=true
            info "✅ 网络连接正常 (测试主机: $test_host)"
            break
        fi
    done
    
    if [ "$network_ok" = false ]; then
        warn "⚠️  网络连接检测失败,但仍尝试安装"
    fi

    local failed_packages=()
    local current_packages=("${packages[@]}")
    local mirror_index=0

    while [ ${#current_packages[@]} -gt 0 ] && [ $total_attempts -lt $max_total_attempts ]; do
        ((total_attempts++))

        # 在每次尝试前再次过滤已安装的包(防止长时间下载已存在的 wheel)
        # 允许 package 规格(如 pkg==1.2.3 或 pkg[extra])被规整为基础包名再检查
        local to_install=()
        local skipped=()
        for pkg in "${current_packages[@]}"; do
            # 规范化包名:去掉版本约束和 extras
            local pkg_base="$pkg"
            pkg_base=$(echo "$pkg_base" | smart_sed -E 's/([<>=!].*)$//')
            pkg_base=$(echo "$pkg_base" | smart_sed -E 's/\[.*\]//')

            if check_package_installed "$pkg_base"; then
                skipped+=("$pkg")
            else
                to_install+=("$pkg")
            fi
        done

        if [ ${#skipped[@]} -gt 0 ]; then
            info "ℹ️  跳过已安装的包: ${skipped[*]}"
        fi

        # 如果没有需要安装的包,直接退出成功
        if [ ${#to_install[@]} -eq 0 ]; then
            ok "🎉 剩余包均已安装,跳过下载和安装。"
            return 0
        fi

        # 将当前安装列表替换为需要安装的包
        current_packages=("${to_install[@]}")

        if [ $mirror_index -ge ${#mirrors[@]} ]; then
            local final_failure_details="
所有镜像源都已尝试完毕,仍有以下包无法安装:
失败包列表: ${current_packages[*]}
总尝试次数: $total_attempts
已尝试的镜像源:"
            for mirror in "${mirrors[@]}"; do
                IFS='|' read -r mirror_url mirror_host <<< "$mirror"
                final_failure_details="$final_failure_details
  - $mirror_host ($mirror_url)"
            done
            
            trace_error "包安装完全失败" "$final_failure_details"
            error "❌ 所有源尝试失败,仍无法安装: ${current_packages[*]}"
            return 1
        fi

        IFS='|' read -r mirror_url mirror_host <<< "${mirrors[$mirror_index]}"
        info "📦 使用镜像: $mirror_host (第 $total_attempts 次)"
        
        # 根据包的大小调整时间预估
        local estimated_time="1-3 分钟"
        for pkg in "${current_packages[@]}"; do
            case "$pkg" in
                torch|torchvision|torchaudio)
                    estimated_time="10-15 分钟"
                    break
                    ;;
                tensorflow*|numpy|scipy|pandas)
                    estimated_time="3-8 分钟"
                    break
                    ;;
            esac
        done
        
        # 显示即将执行的包安装
        info "⏳ 正在安装: ${current_packages[*]} (预计需要 ${estimated_time})"

        # 根据包大小设置超时时间
        local timeout_seconds=120
        # 检查是否包含大型包(PyTorch相关)
        for pkg in "${current_packages[@]}"; do
            case "$pkg" in
                torch|torchvision|torchaudio|tensorflow|tensorflow-gpu)
                    timeout_seconds=1800  # 30分钟,足够下载大型包
                    info "🔄 检测到大型包 $pkg,延长超时时间至 30 分钟"
                    break
                    ;;
            esac
        done

        # 构造完整的 pip install 命令(使用数组避免引号问题)
        local pip_cmd=("pip" "install" "--no-cache-dir" "--timeout" "$timeout_seconds")
        
        # 添加进度显示参数
        pip_cmd+=( "--progress-bar" "on" )     # 启用进度条 (on/off/raw,pretty无效)
        pip_cmd+=( "--verbose" )               # 显示详细信息包括下载速度
        
        # 添加其他参数
        pip_cmd+=( "${extra_args[@]}" )
        
        # 添加 index-url
        pip_cmd+=( "--index-url" "$mirror_url" )
        pip_cmd+=( "--trusted-host" "$mirror_host" )
        
        # 添加额外的 index-url(如果存在)
        if [ -n "$extra_index_url" ]; then
            pip_cmd+=( "--extra-index-url" "$extra_index_url" )
        fi
        
        # 添加所有 trusted-host(来自参数)
        for host in "${trusted_hosts[@]}"; do
            pip_cmd+=( "--trusted-host" "$host" )
        done
        
        # 构建安装包列表时,避免把 torchvision/torchaudio 在 torch 已存在时与其它包一起安装
        # 因为 pip 在依赖解析时可能会重新下载 torch。我们将把需要 --no-deps 的包单独安装。
        local bulk_pkgs=()
        local nodeps_pkgs=()
        for pkg in "${current_packages[@]}"; do
            case "$pkg" in
                torchvision|torchaudio)
                    # 如果 torch 已安装且可 import,则单独安装这些包并使用 --no-deps
                    if check_package_installed "torch"; then
                        nodeps_pkgs+=("$pkg")
                    else
                        bulk_pkgs+=("$pkg")
                    fi
                    ;;
                *)
                    bulk_pkgs+=("$pkg")
                    ;;
            esac
        done

        # 默认将 bulk_pkgs 加入主 pip_cmd
        if [ ${#bulk_pkgs[@]} -gt 0 ]; then
            pip_cmd+=( "${bulk_pkgs[@]}" )
        fi

        # 显示完整命令(调试用)
        if [[ "${DEBUG:-0}" -eq 1 ]]; then
            info "🔧 执行命令: ${pip_cmd[*]}"
        fi

        # 执行命令并显示实时进度
        local pip_install_output=""
        local pip_install_exit_code
        
        info "⚡ 开始下载和安装..."
        info "💡 提示: 按 Ctrl+C 可跳过当前镜像安装 ${current_packages[*]} 并尝试下一个 (不会退出脚本)"
        
        # 如果包含大型包,提供更详细的信息
        if [ "$is_large_package" = true ]; then
            info "📥 检测到大型包,可能需要下载 100MB+ 文件"
            info "🚀 将显示详细的下载进度和速度信息"
            info "⏰ 预计下载时间: 1-10分钟 (取决于网络速度)"
        fi
        
        # 启动后台进度提示任务(仅对大型包)
        local progress_pid=""
        local is_large_package=false
        for pkg in "${current_packages[@]}"; do
            case "$pkg" in
                torch|torchvision|torchaudio|tensorflow|tensorflow-gpu)
                    is_large_package=true
                    break
                    ;;
            esac
        done
        
        if [ "$is_large_package" = true ]; then
            # 启动后台进度提示
            (
                local count=0
                while true; do
                    sleep 60  # 每分钟提示一次
                    count=$((count + 1))
                    echo "⏳ 大型包下载中... (已等待 ${count} 分钟,请继续等待或按 Ctrl+C 跳过此镜像)"
                done
            ) &
            progress_pid=$!
        fi
        
        # 设置局部的 SIGINT 处理,只影响这个安装过程
        local pip_interrupted=false
        local original_trap=$(trap -p INT)
        
        # 定义中断处理函数
        handle_pip_interrupt() {
            pip_interrupted=true
            # 停止后台进度提示
            if [ -n "$progress_pid" ]; then
                kill "$progress_pid" 2>/dev/null || true
                wait "$progress_pid" 2>/dev/null || true
            fi
            echo ""
            warn "⚠️  用户中断安装 ${current_packages[*]},将尝试下一个镜像..."
            return 0
        }
        
        # 设置新的中断处理
        trap 'handle_pip_interrupt' INT
        
        # 执行 pip 安装,显示实时进度
        local start_time=$(date +%s)
        "${pip_cmd[@]}" 2>&1 | while read -r line; do
            # 检查是否被中断
            if [ "$pip_interrupted" = true ]; then
                break
            fi
            
            # 显示进度信息和时间戳
            local current_time=$(date +%s)
            local elapsed_time=$((current_time - start_time))
            local time_str="[${elapsed_time}s]"
            
            case "$line" in
                *"Downloading"*|*"downloading"*)
                    # 提取文件大小信息
                    if [[ "$line" =~ ([0-9]+(\.[0-9]+)?[[:space:]]*[MGK]B) ]]; then
                        local file_size="${BASH_REMATCH[1]}"
                        echo "📥 $time_str $line"
                        # 大文件特别提示
                        if [[ "$line" =~ [0-9]+(\.[0-9]+)?[[:space:]]*MB && "$line" =~ torch ]]; then
                            echo "⏳ 正在下载大型 PyTorch 文件 ($file_size),请耐心等待..."
                        fi
                    else
                        echo "📥 $time_str $line"
                    fi
                    ;;
                *"Installing"*|*"installing"*)
                    echo "📦 $time_str $line"
                    ;;
                *"Successfully installed"*)
                    echo "✅ $time_str $line"
                    ;;
                *"Collecting"*)
                    echo "🔍 $line"
                    ;;
                *"Building"*|*"building"*)
                    echo "🔨 $time_str $line"
                    ;;
                # 新增:识别pip进度条
                *"%"*|*"━"*|*"█"*)
                    # 检查是否是进度条(包含百分比或进度字符)
                    if [[ "$line" =~ [0-9]+% ]] || [[ "$line" =~ [━█▌▎] ]]; then
                        echo "⏬ $time_str $line"
                    else
                        echo "$line"
                    fi
                    ;;
                # 新增:识别下载速度信息
                *"MB/s"*|*"KB/s"*|*"kB/s"*|*"mB/s"*)
                    echo "🚀 $time_str $line"
                    ;;
                # 新增:识别文件大小信息
                *" MB"*|*" KB"*|*" GB"*)
                    if [[ "$line" =~ (Downloading|downloading) ]]; then
                        echo "📥 $time_str $line"
                    else
                        echo "📊 $time_str $line"
                    fi
                    ;;
                *"ERROR"*|*"Error"*|*"error"*)
                    echo "❌ $time_str $line" >&2
                    ;;
                *"WARNING"*|*"Warning"*|*"warning"*)
                    echo "⚠️  $time_str $line"
                    ;;
                *)
                    # 检查是否包含重要信息
                    if [[ "$line" =~ (Processing|Preparing|Cached|Found|Using) ]]; then
                        echo "ℹ️  $line"
                    else
                        # 其他信息正常显示
                        echo "$line"
                    fi
                    ;;
            esac
        done
        
        # 获取退出码
        pip_install_exit_code=${PIPESTATUS[0]}

        # 如果 bulk 安装成功且存在需要单独安装的 nodeps_pkgs,则单独安装它们,使用 --no-deps
        if [ $pip_install_exit_code -eq 0 ] && [ ${#nodeps_pkgs[@]} -gt 0 ]; then
            info "📦 开始单独安装不带依赖的包: ${nodeps_pkgs[*]} (使用 --no-deps,避免触发 torch 重下载)"
            local nodeps_cmd=("pip" "install" "--no-deps" "--no-cache-dir" "--timeout" "$timeout_seconds" "--progress-bar" "on" "--verbose" "--index-url" "$mirror_url" "--trusted-host" "$mirror_host")
            if [ -n "$extra_index_url" ]; then
                nodeps_cmd+=("--extra-index-url" "$extra_index_url")
            fi
            for host in "${trusted_hosts[@]}"; do
                nodeps_cmd+=("--trusted-host" "$host")
            done
            nodeps_cmd+=("${nodeps_pkgs[@]}")

            # 执行 nodeps 安装并显示输出
            "${nodeps_cmd[@]}" 2>&1 | while read -r nline; do
                echo "$nline"
            done
            local nodeps_exit=${PIPESTATUS[0]}
            if [ $nodeps_exit -ne 0 ]; then
                warn "⚠️  单独安装 ${nodeps_pkgs[*]} 失败 (exit $nodeps_exit),将视为当前镜像失败并尝试下一个镜像"
                pip_install_exit_code=1
            else
                ok "✅ 单独安装 ${nodeps_pkgs[*]} 成功"
            fi
        fi
        
        # 停止后台进度提示
        if [ -n "$progress_pid" ]; then
            kill "$progress_pid" 2>/dev/null || true
            wait "$progress_pid" 2>/dev/null || true
        fi
        
        # 检查是否被用户中断
        if [ "$pip_interrupted" = true ]; then
            pip_install_exit_code=130  # 用户中断退出码
            pip_install_output="用户中断安装"
        fi
        
        # 恢复原来的中断处理
        if [ -n "$original_trap" ]; then
            eval "$original_trap"
        else
            trap - INT
        fi
        
        if [ $pip_install_exit_code -eq 0 ]; then
            local end_time=$(date +%s)
            local elapsed_time=$((end_time - start_time))
            local elapsed_min=$((elapsed_time / 60))
            local elapsed_sec=$((elapsed_time % 60))
            
            if [ $elapsed_time -gt 60 ]; then
                ok "✅ 所有包安装成功 (耗时: ${elapsed_min}分${elapsed_sec}秒)"
            else
                ok "✅ 所有包安装成功 (耗时: ${elapsed_time}秒)"
            fi
            
            # 如果是大型包,显示额外的性能信息
            if [ "$is_large_package" = true ]; then
                info "📊 大型包安装完成统计:"
                info "   ⏱️  总耗时: ${elapsed_min}分${elapsed_sec}秒"
                info "   📡 使用镜像: $mirror_host"
                info "   📦 包数量: ${#current_packages[@]}"
            fi
            
            return 0
        elif [ $pip_install_exit_code -eq 124 ]; then
            local timeout_msg="⏰ 镜像 $mirror_host 安装 ${current_packages[*]} 超时 (${timeout_seconds}秒),尝试下一个镜像"
            warn "$timeout_msg"
            # 记录详细的超时信息到日志
            local timeout_details="
超时详情:
- 镜像: $mirror_host
- 超时时间: ${timeout_seconds}秒 ($(echo "scale=1; ${timeout_seconds}/60" | bc 2>/dev/null || echo "$((timeout_seconds/60))")分钟)
- 包列表: ${current_packages[*]}
- 时间: $(sh_date)
- 建议: 尝试使用更快的网络或减少包数量"
            echo "$timeout_details" | tee -a "${LOG_FILE:-/dev/null}" >/dev/null
            trace_error "pip 安装超时 (镜像: $mirror_host, 包: ${current_packages[*]})" "$timeout_details" "124"
        elif [ $pip_install_exit_code -eq 130 ]; then
            warn "🔄 用户跳过镜像 $mirror_host (安装 ${current_packages[*]}),尝试下一个镜像"
        else
            warn "⚠️  镜像 $mirror_host 安装 ${current_packages[*]} 失败,尝试下一个镜像"
            if [[ "${DEBUG:-0}" -eq 1 ]]; then
                local mirror_failure_details="
镜像: $mirror_host
包列表: ${current_packages[*]}
命令: ${pip_cmd[*]}
退出码: $pip_install_exit_code
输出:
$pip_install_output"
                trace_error "pip 安装失败 (镜像: $mirror_host, 包: ${current_packages[*]})" "$mirror_failure_details" "$pip_install_exit_code"
            fi
        fi
        
        failed_packages=()
        for pkg in "${current_packages[@]}"; do
            if ! pip show "$pkg" &> /dev/null; then
                failed_packages+=("$pkg")
            fi
        done
        current_packages=("${failed_packages[@]}")
        ((mirror_index++))
        
        # 如果不是超时或中断,等待一下再尝试下一个镜像
        if [ $pip_install_exit_code -ne 124 ] && [ $pip_install_exit_code -ne 130 ]; then
            sleep 2
        fi
    done

    if [ ${#current_packages[@]} -gt 0 ]; then
        error "❌ 安装失败: ${current_packages[*]}"
        return 1
    fi

    ok "✅ 安装完成"
    return 0
}

# 🔧 封装:安装 GPU 版 PyTorch 的函数
# 在调用 install_torch_gpu() 前可用:
#   export TORCH_INDEX="https://download.pytorch.org/whl/cu118"
# 支持源:
#   # 使用官方源(推荐)
#   export TORCH_INDEX="https://download.pytorch.org/whl/cu118"
#   # 使用阿里云镜像(可选)
#   export TORCH_INDEX="https://mirrors.aliyun.com/pytorch-wheels/cu118/"
install_torch_gpu() {
    local index_url="${1:-$TORCH_INDEX}"

    # 提示用户使用了默认值
    if [ -z "$TORCH_INDEX" ] && [ -z "${1:-}" ]; then
        warn "⚠️  TORCH_INDEX 未设置,使用默认源: https://download.pytorch.org/whl/cu118"
    fi

    # 设置默认值
    : "${index_url:=https://download.pytorch.org/whl/cu118}"

    info "🚀 安装 GPU 版 PyTorch: torch torchaudio torchvision"
    info "🔗 主源: $index_url"
    info "📦 备用源: https://pypi.org/simple"

    if robust_pip_install \
        "torch" "torchaudio" "torchvision" \
        --index-url "$index_url" \
        --extra-index-url "https://pypi.org/simple" \
        --trusted-host "pypi.org" \
        --trusted-host "$(echo "$index_url" | awk -F[/:] '{print $4}')" \
    ; then
        ok "✅ GPU 版 PyTorch 安装成功"
        return 0
    else
        local torch_failure_details="
PyTorch GPU 版本安装失败详情:
主源: $index_url  
备用源: https://pypi.org/simple
包列表: torch torchaudio torchvision

可能的原因:
1. 网络连接问题 (访问 PyTorch 官方源失败)
2. CUDA 版本不匹配 (请检查本机 CUDA 版本)
3. Python 版本不兼容
4. 磁盘空间不足

建议的解决方案:
1. 检查 CUDA 版本: nvidia-smi 或 nvcc --version
2. 手动指定 CUDA 版本,如: 
   export TORCH_INDEX='https://download.pytorch.org/whl/cu117'
3. 降级到 CPU 版本: pip install torch torchaudio torchvision
4. 检查网络代理设置"
        
        trace_error "GPU 版 PyTorch 安装失败" "$torch_failure_details"
        error "❌ GPU 版 PyTorch 安装失败"
        return 1
    fi
}

# 🔧 通用 PyTorch 冲突保护安装器
# 功能: 使用 --no-deps 安装包,然后智能安装非冲突依赖
# 用法: install_with_torch_protection "package_name" [excluded_packages...]
install_with_torch_protection() {
    local target_package="$1"
    shift
    local excluded_packages=("$@")
    
    # 默认的 PyTorch 相关排除列表
    local default_torch_exclusions=(
        "torch" "torchvision" "torchaudio" "torchtext" 
        "pytorch-lightning" "torch-audio" "torchdiffeq"
        "torchmetrics" "torchsde" "torch-optimizer"
        "torch-stoi" "pytorch-ranger" "ema-pytorch"
        "vector-quantize-pytorch" "clip-anytorch"
        "dctorch" "kornia"
    )
    
    # 合并排除列表
    local all_exclusions=("${default_torch_exclusions[@]}" "${excluded_packages[@]}")
    
    info "🛡️  开始保护性安装: $target_package"
    info "🚫 排除包列表: ${all_exclusions[*]}"
    
    # Step 1: 检查包是否已安装
    if pip show "$target_package" &> /dev/null; then
        info "✅ $target_package 已安装,跳过"
        return 0
    fi
    
    # Step 2: 使用 --no-deps 安装目标包
    info "📦 使用 --no-deps 安装 $target_package(避免依赖冲突)"
    if ! robust_pip_install "--no-deps" "$target_package"; then
        trace_error "$target_package 安装失败" "robust_pip_install --no-deps $target_package 返回失败"
        error "❌ $target_package 安装失败"
        return 1
    fi
    
    ok "✅ $target_package 安装成功(已跳过依赖以保护 PyTorch)"
    
    # Step 3: 智能安装依赖
    info "🔍 智能安装 $target_package 依赖(排除冲突包)..."
    install_package_deps "$target_package" "${all_exclusions[@]}"
    
    return 0
}

# 🛡️ 保护性pip安装函数:防止已安装核心包被依赖重装
# 用法: protected_pip_install "package1" "package2" [pip_args...]
protected_pip_install() {
    local packages=("$@")
    local pip_args=()
    local install_packages=()
    
    # 分离包名和pip参数
    for arg in "${packages[@]}"; do
        if [[ "$arg" =~ ^-- ]]; then
            pip_args+=("$arg")
        else
            install_packages+=("$arg")
        fi
    done
    
    info "🛡️ 保护性安装: ${install_packages[*]}"
    
    # 检查是否有已保护的核心包
    local has_protected=false
    if [ -n "${PROTECTED_CORE_PACKAGES:-}" ] && [ ${#PROTECTED_CORE_PACKAGES[@]} -gt 0 ]; then
        for pkg in "${install_packages[@]}"; do
            for protected in "${PROTECTED_CORE_PACKAGES[@]}"; do
                if [ "$pkg" = "$protected" ]; then
                    warn "🛡️ 检测到保护包 $pkg,使用 --no-deps 防止依赖重装"
                    has_protected=true
                    break 2
                fi
            done
        done
    fi
    
    # 如果包含保护包,使用 --no-deps 安装
    if [ "$has_protected" = true ]; then
        info "🚫 使用 --no-deps 模式保护已安装核心包"
        robust_pip_install "${install_packages[@]}" "${pip_args[@]}" --no-deps
    else
        # 正常安装
        robust_pip_install "${install_packages[@]}" "${pip_args[@]}"
    fi
}

# 🔧 智能依赖安装器(通用版本)
# 功能: 获取包的依赖列表,排除指定包,安装其余依赖
# 用法: install_package_deps "package_name" excluded_package1 excluded_package2 ...
install_package_deps() {
    local target_package="$1"
    shift
    local excluded_packages=("$@")
    
    info "🔍 获取 $target_package 的实际依赖列表..."
    
    # 方法1: 尝试从 pip show 获取依赖信息
    local actual_deps=""
    actual_deps=$(pip show "$target_package" 2>/dev/null | grep "Requires:" | sed 's/Requires: //' | tr ',' '\n' | sed 's/^ *//;s/ *$//' | grep -v '^$')
    
    # 方法2: 如果方法1失败,尝试使用 pipdeptree (如果可用)
    if [ -z "$actual_deps" ] && command -v pipdeptree >/dev/null 2>&1; then
        info "📋 使用 pipdeptree 获取依赖..."
        actual_deps=$(pipdeptree --packages "$target_package" --json 2>/dev/null | python -c "
import sys, json
try:
    data = json.load(sys.stdin)
    for pkg in data:
        if pkg['package']['key'] == '$target_package':
            deps = [dep['key'] for dep in pkg['dependencies']]
            print('\n'.join(deps))
            break
except:
    pass
" 2>/dev/null)
    fi
    
    # 方法3: 使用包特定的已知依赖列表
    if [ -z "$actual_deps" ]; then
        info "📋 使用预定义的 $target_package 依赖列表..."
        case "$target_package" in
            "prefigure")
                actual_deps="tqdm
einops
matplotlib
numpy
Pillow
scipy
accelerate
diffusers
transformers"
                ;;
            "pytorch-lightning")
                actual_deps="torch
torchmetrics
lightning-utilities
typing-extensions
fsspec
packaging
pyyaml
tqdm"
                ;;
            "diffusers")
                actual_deps="torch
transformers
numpy
Pillow
requests
regex
importlib-metadata
huggingface-hub
accelerate
safetensors"
                ;;
            "speechbrain")
                actual_deps="torch
torchaudio
numpy
scipy
tqdm
joblib
ruamel.yaml
hyperpyyaml
sentencepiece
huggingface-hub"
                ;;
            "asteroid")
                actual_deps="torch
torchaudio
numpy
scipy
pandas
soundfile
torch-stoi
torch-optimizer
pytorch-lightning
huggingface-hub"
                ;;
            *)
                # 通用的机器学习包常见依赖
                actual_deps="numpy
scipy
matplotlib
pandas
tqdm
Pillow
requests
packaging
typing-extensions"
                ;;
        esac
    else
        info "📋 从包信息获取到依赖列表"
    fi
    
    if [ -z "$actual_deps" ]; then
        warn "⚠️  无法获取 $target_package 的依赖信息,跳过依赖安装"
        return 0
    fi
    
    # 处理每个依赖
    local installed_count=0
    local skipped_count=0
    local failed_count=0
    
    while IFS= read -r dep; do
        [ -z "$dep" ] && continue
        
        # 清理依赖名称(去掉版本要求)
        local clean_dep=$(echo "$dep" | sed 's/[<>=!].*//' | sed 's/^ *//;s/ *$//')
        [ -z "$clean_dep" ] && continue
        
        # 检查是否在排除列表中
        local is_excluded=false
        for excluded_pkg in "${excluded_packages[@]}"; do
            if [[ "$clean_dep" == "$excluded_pkg"* ]] || [[ "$clean_dep" == *"$excluded_pkg"* ]]; then
                is_excluded=true
                break
            fi
        done
        
        if [ "$is_excluded" = true ]; then
            info "⏭️  跳过排除的依赖: $clean_dep"
            ((skipped_count++))
            continue
        fi
        
        # 检查是否已安装
        if pip show "$clean_dep" &> /dev/null; then
            info "✅ $clean_dep 已安装,跳过"
        else
            info "📦 安装 $target_package 依赖: $clean_dep"
            if robust_pip_install "$clean_dep"; then
                ok "✅ $clean_dep 安装成功"
                ((installed_count++))
            else
                warn "⚠️  $clean_dep 安装失败,可能影响 $target_package 功能"
                ((failed_count++))
            fi
        fi
    done <<< "$actual_deps"
    
    # 显示安装统计
    info "📊 依赖安装统计: 新安装 $installed_count 个,跳过 $skipped_count 个,失败 $failed_count 个"
    
    # 验证目标包是否能正常导入
    info "🔍 验证 $target_package 安装完整性..."
    local import_test=""
    import_test=$(python -c "
try:
    import $target_package
    print('IMPORT_OK')
    version = getattr($target_package, '__version__', 'unknown')
    print(f'$target_package 版本: {version}')
except ImportError as e:
    print(f'IMPORT_ERROR: {e}')
except Exception as e:
    print(f'OTHER_ERROR: {e}')
" 2>&1)
    
    if echo "$import_test" | grep -q "IMPORT_OK"; then
        echo "$import_test"
        ok "✅ $target_package 及其依赖安装完成,可正常使用"
        return 0
    else
        echo "$import_test"
        warn "⚠️  $target_package 导入测试失败,可能缺少某些依赖"
        return 1
    fi
}

# 🔧 智能安装 prefigure 依赖(使用通用函数)
install_prefigure_deps() {
    install_package_deps "prefigure" \
        "torch" "torchvision" "torchaudio" "torchtext" \
        "pytorch-lightning" "torch-audio" "torchdiffeq" \
        "torchmetrics" "torchsde" "torch-optimizer" \
        "torch-stoi" "pytorch-ranger" "ema-pytorch" \
        "vector-quantize-pytorch" "clip-anytorch" \
        "dctorch" "kornia"
}

# 🛡️ 通用核心包保护安装:确保核心包版本,并保护性安装冲突包
# 用法:ensure_core_package_installed "core_package" "conflict_package1" ["conflict_package2" ...]
# 示例:ensure_core_package_installed "torch" "prefigure" "diffusers"
# 示例:ensure_core_package_installed "tensorflow" "some_tf_conflict_package"
# 示例:ensure_core_package_installed "numpy" "some_numpy_conflict_package"
ensure_core_package_installed() {
    local core_package="$1"
    shift
    local conflict_packages=("$@")
    
    if [ -z "$core_package" ]; then
        error "❌ ensure_core_package_installed: 需要指定核心包名"
        return 1
    fi
    
    if [ ${#conflict_packages[@]} -eq 0 ]; then
        error "❌ ensure_core_package_installed: 需要指定至少一个冲突包"
        return 1
    fi
    
    info "🛡️ 开始核心包保护性安装流程"
    info "🎯 核心包: $core_package"
    info "⚠️  冲突包列表: ${conflict_packages[*]}"
    
    # Step 1: 使用统一的包检查函数确保核心包已安装
    info "🔍 检查核心包 $core_package 安装状态..."
    
    if check_package_installed "$core_package"; then
        ok "✅ 检测到核心包 $core_package 已正确安装"
        
        # 显示当前版本信息(通用版)
        local version_info=""
        version_info=$(python -c "
try:
    import $core_package
    if hasattr($core_package, '__version__'):
        print(f'$core_package 版本: {$core_package.__version__}')
    else:
        print(f'$core_package: 已安装(无版本信息)')
    
    # 特殊处理 torch 的 CUDA 信息
    if '$core_package' == 'torch':
        print(f'CUDA可用: {\"是\" if $core_package.cuda.is_available() else \"否\"}')
        if $core_package.cuda.is_available():
            print(f'GPU数量: {$core_package.cuda.device_count()}')
except Exception as e:
    print(f'版本检查失败: {e}')
" 2>/dev/null)
        echo "$version_info"
    else
        info "📦 需要安装核心包 $core_package..."
        
        # 根据核心包类型选择安装策略
        case "$core_package" in
            "torch")
                if ! install_torch_gpu; then
                    error "❌ PyTorch GPU 版本安装失败"
                    return 1
                fi
                ;;
            *)
                # 通用包安装
                if ! robust_pip_install "$core_package"; then
                    error "❌ 核心包 $core_package 安装失败"
                    return 1
                fi
                ;;
        esac
        ok "✅ 核心包 $core_package 安装完成"
    fi

    # Step 2: 循环保护性安装所有冲突包
    for conflict_pkg in "${conflict_packages[@]}"; do
        info "🛡️ 开始保护性安装 $conflict_pkg (避免覆盖核心包 $core_package)"
        
        # 根据核心包类型选择保护策略
        case "$core_package" in
            "torch")
                if ! install_with_torch_protection "$conflict_pkg"; then
                    warn "⚠️ $conflict_pkg 安装失败,继续处理下一个包"
                    continue
                fi
                ;;
            *)
                # 通用保护策略:使用 --no-deps
                if ! robust_pip_install "$conflict_pkg" --no-deps; then
                    warn "⚠️ $conflict_pkg 保护性安装失败,继续处理下一个包"
                    continue
                fi
                ;;
        esac
        
        ok "✅ $conflict_pkg 保护性安装完成"
    done

    # Step 3: 最终验证核心包完整性
    info "🔍 验证核心包 $core_package 是否保持完整"
    local final_check=""
    final_check=$(python -c "
try:
    import $core_package
    if hasattr($core_package, '__version__'):
        print(f'最终 $core_package 版本: {$core_package.__version__}')
    else:
        print(f'最终 $core_package: 导入成功')
    
    # 特殊验证逻辑
    if '$core_package' == 'torch':
        if $core_package.cuda.is_available():
            print('✅ GPU支持正常')
            print(f'GPU设备: {$core_package.cuda.get_device_name(0)}')
        else:
            print('❌ GPU支持异常')
    else:
        print('✅ 包导入正常')
        
except Exception as e:
    print(f'❌ 验证失败: {e}')
" 2>/dev/null)
    
    echo "$final_check"
    
    if echo "$final_check" | grep -q "✅"; then
        ok "🎉 核心包 $core_package 保护性安装流程完成"
        return 0
    else
        error "❌ 核心包 $core_package 验证失败"
        return 1
    fi
}

# 🛡️ PyTorch 专用保护函数(向后兼容)
ensure_torch_gpu_be_installed() {
    local conflict_packages=("$@")
    info "🔄 调用通用核心包保护函数处理 PyTorch"
    ensure_core_package_installed "torch" "${conflict_packages[@]}"
}

# 🛡️ 预防性安装:确保 PyTorch GPU 版本,并保护性安装 prefigure(向后兼容函数)
install_pytorch_and_prefigure_safely() {
    info "🔄 调用通用核心包保护函数处理 prefigure"
    ensure_core_package_installed "torch" "prefigure"
}
    info "🛡️ 开始 PyTorch GPU 保护性安装流程"
    
    # Step 1: 使用统一的包检查函数检查 PyTorch GPU 版本
    info "🔍 检查当前 PyTorch 安装状态..."
    
    if check_package_installed "torch"; then
        ok "✅ 检测到 GPU 版本的 PyTorch 已正确安装"
        
        # 显示当前版本信息
        local version_info=""
        version_info=$(python -c "
try:
    import torch
    print(f'PyTorch版本: {torch.__version__}')
    if torch.cuda.is_available():
        print(f'CUDA可用: 是')
        print(f'GPU数量: {torch.cuda.device_count()}')
    else:
        print(f'CUDA可用: 否')
except Exception as e:
    print(f'版本检查失败: {e}')
" 2>/dev/null)
        echo "$version_info"
    else
        info "� 需要安装 GPU 版本的 PyTorch..."
        if ! install_torch_gpu; then
            error "❌ PyTorch GPU 版本安装失败"
            return 1
        fi
        ok "✅ PyTorch GPU 版本安装完成"
    fi

    # Step 2: 安装 prefigure(使用通用保护函数)
    info "🛡️  开始保护性安装 prefigure (避免覆盖 PyTorch GPU 版本)"
    if ! install_with_torch_protection "prefigure"; then
        warn "⚠️  prefigure 安装失败,但继续执行后续步骤"
        # 可选:exit 1 如果必须成功
    fi

    # Step 4: 验证安装后 PyTorch GPU 版本是否保持完整
    info "🔍 验证 PyTorch GPU 版本是否保持完整"
    local current_torch_check=""
    current_torch_check=$(python -c "
import torch
print(f'当前PyTorch版本: {torch.__version__}')
if torch.cuda.is_available():
    print('CURRENT_GPU_OK')
    print(f'CUDA版本: {torch.version.cuda if hasattr(torch.version, \"cuda\") else \"unknown\"}')
    print(f'GPU设备: {torch.cuda.get_device_name(0)}')
else:
    print('CURRENT_CPU_ON***')
" 2>&1)
    
    local torch_check_exit_code=$?
    
    if [ $torch_check_exit_code -eq 0 ] && echo "$current_torch_check" | grep -q "CURRENT_GPU_OK"; then
        echo "$current_torch_check"
        ok "✅ PyTorch GPU 版本保持完整,prefigure 安装成功"
        return 0
    else
        warn "⚠️  检测到 PyTorch 问题,可能需要重新安装"
        echo "$current_torch_check"
        
        # 如果确实有问题,再重新安装 GPU 版本
        info "🔧 重新安装 GPU 版 PyTorch 以确保完整性"
        if ! install_torch_gpu; then
            trace_error "GPU 版 PyTorch 恢复安装失败" "install_torch_gpu 函数在 prefigure 后调用失败"
            error "❌ GPU 版 PyTorch 安装失败,请检查 CUDA 环境"
            return 1
        fi
    fi

    # Step 5: 最终验证 CUDA 是否可用
    info "🔍 最终验证 PyTorch 是否支持 CUDA"
    local cuda_verification_output=""
    cuda_verification_output=$(python -c "
import torch
print(f'PyTorch: {torch.__version__}')
assert torch.cuda.is_available(), 'CUDA not available'
print(f'✅ CUDA 可用: {torch.cuda.get_device_name(0)}')
" 2>&1)
    local cuda_verification_exit_code=$?
    
    if [ $cuda_verification_exit_code -eq 0 ]; then
        echo "$cuda_verification_output"
        ok "✅ 成功确保 PyTorch 为 GPU 版"
    else
        local cuda_diagnostic_output=""
        cuda_diagnostic_output=$(python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')" 2>&1)
        
        local full_diagnostic="
CUDA 验证失败详情:
PyTorch 验证输出:
$cuda_verification_output

CUDA 可用性诊断:
$cuda_diagnostic_output

可能的原因:
1. CUDA 驱动版本不匹配
2. PyTorch 安装的是 CPU 版本
3. CUDA 库未正确安装
4. 系统没有兼容的 GPU

建议的解决方案:
1. 检查 NVIDIA 驱动: nvidia-smi
2. 检查 CUDA 版本: nvcc --version
3. 重新安装对应 CUDA 版本的 PyTorch
4. 如无 GPU,改用 CPU 版本: pip install torch torchvision torchaudio"
        
        trace_error "PyTorch CUDA 验证失败" "$full_diagnostic" "$cuda_verification_exit_code"
        error "❌ PyTorch 不支持 CUDA,请检查驱动、CUDA、安装版本是否匹配"
        exit 1
    fi
}


# # 🔧 智能升级 pip:仅当版本过低时才升级
# # 调用函数(使用默认最低版本 23.0)
# upgrade_pip_if_needed
# # 或指定最低版本
# upgrade_pip_if_needed "24.0"
upgrade_pip_if_needed() {
    local required_version="${1:-23.0}"  # 建议最低版本(可传参)
    local current_version

    info "🔍 检查 pip 版本..."

    # 获取当前 pip 版本
    local pip_version_output=""
    pip_version_output=$(python -m pip --version 2>&1)
    local pip_version_exit_code=$?
    
    if [ $pip_version_exit_code -eq 0 ]; then
        current_version=$(echo "$pip_version_output" | awk '{print $2}')
    else
        trace_error "pip 版本检查失败" "$pip_version_output" "$pip_version_exit_code"
        warn "⚠️  pip 未安装或无法获取版本,准备安装"
        
        # 先尝试 ensurepip(某些系统不包含)
        local ensurepip_output=""
        ensurepip_output=$(python -m ensurepip --default-pip 2>&1)
        local ensurepip_exit_code=$?
        if [ $ensurepip_exit_code -ne 0 ]; then
            trace_error "ensurepip 安装失败" "$ensurepip_output" "$ensurepip_exit_code"
        fi
        
        current_version=$(python -m pip --version 2>/dev/null | awk '{print $2}')

        # 如果仍然没有 pip,则尝试使用 get-pip.py(使用清华镜像以提高可用性)
        if [ -z "$current_version" ]; then
            warn "⚠️ pip 仍未安装,尝试通过 get-pip.py 安装"
            GET_PIP_URL="https://pypi.tuna.tsinghua.edu.cn/bootstrap/pip/get-pip.py"
            GET_PIP_PY="/tmp/get-pip-$$.py"

            local download_output=""
            if command -v curl >/dev/null 2>&1; then
                download_output=$(curl -fsSL --connect-timeout 10 --max-time 60 "$GET_PIP_URL" -o "$GET_PIP_PY" 2>&1)
                local download_exit_code=$?
                if [ $download_exit_code -ne 0 ]; then
                    trace_error "curl 下载 get-pip.py 失败" "$download_output" "$download_exit_code"
                fi
            elif command -v wget >/dev/null 2>&1; then
                download_output=$(wget -q -O "$GET_PIP_PY" "$GET_PIP_URL" 2>&1)
                local download_exit_code=$?
                if [ $download_exit_code -ne 0 ]; then
                    trace_error "wget 下载 get-pip.py 失败" "$download_output" "$download_exit_code"
                fi
            else
                trace_error "缺少下载工具" "系统未安装 curl 或 wget,无法下载 get-pip.py"
                warn "⚠️ 无法下载 get-pip.py:系统未安装 curl 或 wget"
            fi

            if [ -f "$GET_PIP_PY" ]; then
                local get_pip_output=""
                get_pip_output=$(python "$GET_PIP_PY" --quiet --no-warn-script-location 2>&1)
                local get_pip_exit_code=$?
                if [ $get_pip_exit_code -eq 0 ]; then
                    ok "✅ pip 安装成功 (get-pip.py)"
                else
                    trace_error "get-pip.py 安装失败" "$get_pip_output" "$get_pip_exit_code"
                    warn "⚠️ 使用 get-pip.py 安装 pip 失败"
                fi
                rm -f "$GET_PIP_PY"
            fi

            current_version=$(python -m pip --version 2>/dev/null | awk '{print $2}')
        fi
    fi

    info "📦 当前 pip 版本: $current_version,目标最低版本: $required_version"

    # 比较版本(使用 sort -V 进行版本排序比较)
    if printf '%s\n%s' "$required_version" "$current_version" | sort -V | head -n1 | grep -q "$required_version"; then
        ok "✅ pip 版本已满足要求,跳过升级"
        return 0
    else
        info "⏫ pip 版本过低,正在升级..."
        local pip_upgrade_output=""
        local pip_upgrade_exit_code
        
        if [ -n "$PIP_INDEX" ] && [ -n "$PIP_TRUSTED_HOST" ]; then
            pip_upgrade_output=$(python -m pip install --upgrade pip \
                -i "$PIP_INDEX" \
                --trusted-host "$PIP_TRUSTED_HOST" 2>&1)
            pip_upgrade_exit_code=$?
        else
            pip_upgrade_output=$(python -m pip install --upgrade pip 2>&1)
            pip_upgrade_exit_code=$?
        fi

        if [ $pip_upgrade_exit_code -eq 0 ]; then
            ok "✅ pip 升级成功"
        else
            trace_error "pip 升级失败" "$pip_upgrade_output" "$pip_upgrade_exit_code"
            warn "⚠️  pip 升级失败,但继续执行后续步骤"
        fi
    fi
}

# -----------------------------
# 3. 检查或创建环境(Conda 优先,venv fallback)
# -----------------------------
ENV_NAME="train_ss"

# 创建或使用已有环境(Conda 或 venv)
if ! create_or_use_env "$ENV_NAME" "${PYTHON_VERSIONS[@]}"; then
    trace_error "虚拟环境创建/激活完全失败" "create_or_use_env 函数返回非零退出码"
    error "虚拟环境创建或激活失败,脚本终止"
fi

# 此时环境已激活,无需额外 activate
info "✅ 环境已激活: $ENV_NAME"
echo "最新进度请查看日志文件: $LOG_FILE"



# -----------------------------
# 5. 升级 pip
# -----------------------------
upgrade_pip_if_needed 
echo "最新进度请查看日志文件: $LOG_FILE"

# -----------------------------
# 6. 智能安装 PyTorch(根据 GPU)
# -----------------------------
info "🔍 检测 GPU..."
TORCH_INDEX="https://download.pytorch.org/whl/cu128"

if command -v nvidia-smi &> /dev/null; then
    GPU_NAME=$(nvidia-smi --query-gpu=name --format=csv,noheader,nounits -i 0 || echo "unknown")
    info "GPU: $GPU_NAME"
    case "$GPU_NAME" in
        *"P100"*) TORCH_INDEX="https://download.pytorch.org/whl/cu118" ;;
        *"T4"*|*"V100"*) info "使用 CUDA 11.8/12.x" ;;
        *"A10"*|*"A100"*|*"3090"*|*"4090"*) info "使用 CUDA 12.8" ;;
        *) info "未知 GPU,尝试 CUDA 12.8" ;;
    esac
else
    warn "⚠️  无 nvidia-smi,使用 CPU 版"
    TORCH_INDEX="https://download.pytorch.org/whl/cpu"
fi

# 🎯 处理核心包参数
DEFAULT_CORE_PACKAGES="torch,torchvision,torchaudio"
CORE_PACKAGES="${CORE_PACKAGES_ARG:-$DEFAULT_CORE_PACKAGES}"

# 解析核心包列表
IFS=',' read -ra CORE_PACKAGE_ARRAY <<< "$CORE_PACKAGES"
PRIMARY_CORE_PACKAGE="${CORE_PACKAGE_ARRAY[0]}"

info "🛡️ 核心包配置:"
info "   主核心包: $PRIMARY_CORE_PACKAGE"
if [ ${#CORE_PACKAGE_ARRAY[@]} -gt 1 ]; then
    info "   相关核心包: ${CORE_PACKAGE_ARRAY[*]:1}"
fi
info "   冲突包: prefigure"

# 🚀 改进:对所有核心包进行保护,不仅仅是主核心包
info "🔍 检查所有指定的核心包安装状态..."

# 检查每个核心包是否已安装
ALL_CORE_PACKAGES_INSTALLED=true

# 🚀 改进:完全使用Python检查,兼容受限环境(无需grep/sed/cut等外部命令)
torch_check_result=$(python -c "
try:
    import subprocess
    import sys
    
    # 检查torch包
    result = subprocess.run([sys.executable, '-m', 'pip', 'show', 'torch'], 
                          capture_output=True, text=True, timeout=10)
    if result.returncode == 0:
        version = None
        for line in result.stdout.split('\n'):
            if line.startswith('Version:'):
                version = line.split(':', 1)[1].strip()
                break
        
        if version:
            print(f'TORCH_VERSION:{version}')
            if '2.8.0' in version and ('cu' in version or '+cu' in version):
                print('STATUS:2.8.0_GPU_FOUND')
            elif 'cu' in version or '+cu' in version:
                print('STATUS:OTHER_GPU_FOUND')
            else:
                print('STATUS:CPU_VERSION')
        else:
            print('STATUS:NO_VERSION')
    else:
        print('STATUS:NOT_FOUND')
        
    # 同时检查其他核心包
    other_packages = ['torchvision', 'torchaudio']
    missing_packages = []
    for pkg in other_packages:
        pkg_result = subprocess.run([sys.executable, '-m', 'pip', 'show', pkg], 
                                  capture_output=True, text=True, timeout=10)
        if pkg_result.returncode != 0:
            missing_packages.append(pkg)
    
    if missing_packages:
        print(f'MISSING_PACKAGES:{\"|\".join(missing_packages)}')
    else:
        print('ALL_PYTORCH_PACKAGES_FOUND')
        
except Exception as e:
    print(f'PYTHON_CHECK_FAILED:{e}')
" 2>/dev/null)

# 使用纯bash字符串处理解析结果
case "$torch_check_result" in
    *"STATUS:2.8.0_GPU_FOUND"*)
        # 提取版本号
        torch_version=$(echo "$torch_check_result" | while read line; do
            case "$line" in
                TORCH_VERSION:*) echo "${line#TORCH_VERSION:}" ;;
            esac
        done)
        ok "🎯 检测到 PyTorch 2.8.0 GPU版本: $torch_version,启用强制保护模式"
        ALL_CORE_PACKAGES_INSTALLED=true
        for core_pkg in "${CORE_PACKAGE_ARRAY[@]}"; do
            ok "✅ $core_pkg - 强制保护模式,跳过重复安装"
        done
        ;;
    *"STATUS:OTHER_GPU_FOUND"*)
        torch_version=$(echo "$torch_check_result" | while read line; do
            case "$line" in
                TORCH_VERSION:*) echo "${line#TORCH_VERSION:}" ;;
            esac
        done)
        ok "🎯 检测到 PyTorch GPU版本: $torch_version,启用强制保护模式"
        ALL_CORE_PACKAGES_INSTALLED=true
        for core_pkg in "${CORE_PACKAGE_ARRAY[@]}"; do
            ok "✅ $core_pkg - 强制保护模式,跳过重复安装"
        done
        ;;
    *"PYTHON_CHECK_FAILED"*|*"STATUS:NOT_FOUND"*)
        # 环境检查失败或torch未安装,提供手动安装指导
        warn "⚠️ 环境检查失败或PyTorch未安装"
        echo ""
        error "💥 建议手动安装以下包:"
        echo ""
        echo "🔧 复制以下命令进行手动安装:"
        echo ""
        echo "# PyTorch GPU版本(推荐)"
        echo "pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128"
        echo ""
        echo "# 或者CPU版本"  
        echo "pip install torch torchvision torchaudio"
        echo ""
        echo "# 其他常用包"
        echo "pip install transformers diffusers opencv-python pillow numpy pandas matplotlib"
        echo ""
        echo "🔄 安装完成后,请重新运行脚本"
        echo ""
        read -p "⚠️  是否继续尝试自动安装?(y/N): " continue_auto
        if [[ ! "$continue_auto" =~ ^[Yy]$ ]]; then
            exit 1
        fi
        ALL_CORE_PACKAGES_INSTALLED=false
        ;;
    *"STATUS:CPU_VERSION"*)
        warn "⚠️ 检测到PyTorch CPU版本,建议升级到GPU版本"
        ALL_CORE_PACKAGES_INSTALLED=false
        ;;
    *)
        # 未知状态,进入常规检查
        ALL_CORE_PACKAGES_INSTALLED=false
        ;;
esac

# 如果强制保护模式未激活,执行常规检查
if [ "$ALL_CORE_PACKAGES_INSTALLED" != true ]; then
    # 常规检查流程
    for core_pkg in "${CORE_PACKAGE_ARRAY[@]}"; do
        echo "🔍 正在检查核心包: $core_pkg" >&2
        if check_package_installed "$core_pkg"; then
            ok "✅ $core_pkg - 已正确安装"
            echo "✅ 核心包 $core_pkg 检查通过" >&2
        else
            warn "📦 $core_pkg - 需要安装"
            echo "❌ 核心包 $core_pkg 检查失败" >&2
            ALL_CORE_PACKAGES_INSTALLED=false
        fi
    done
fi

echo "🎯 最终状态: ALL_CORE_PACKAGES_INSTALLED=$ALL_CORE_PACKAGES_INSTALLED" >&2

if [ "$ALL_CORE_PACKAGES_INSTALLED" = true ]; then
    ok "🎉 所有指定的核心包都已安装,跳过核心包保护流程"
else
    # 只有在需要时才进行保护性安装
    info "🛡️ 开始核心包保护性安装流程..."
    
    # 确保再安装了prefigure之后安装的是指定的核心包版本
    if ! ensure_core_package_installed "$PRIMARY_CORE_PACKAGE" "prefigure"; then
        trace_error "核心包保护性安装流程失败" "ensure_core_package_installed 函数返回非零退出码"
        error "核心包 $PRIMARY_CORE_PACKAGE 安装失败,无法继续"
    fi
fi

# -----------------------------
# 6.5. 🎯 核心大型包专项安装阶段
# -----------------------------

# 🎯 核心大型包安装函数:专门处理需要大量下载的包
install_essential_large_packages() {
    info "🎯 开始核心大型包专项安装阶段..."
    
    echo "🔍 调试: ALL_CORE_PACKAGES_INSTALLED=${ALL_CORE_PACKAGES_INSTALLED:-未设置}" >&2
    
    # 🚀 如果前面已经确认所有核心包都安装了,直接跳过
    if [ "${ALL_CORE_PACKAGES_INSTALLED:-false}" = true ]; then
        ok "🎉 前面已确认所有核心包都已安装,跳过大型包安装阶段"
        echo "✅ 大型包安装阶段成功跳过" >&2
        return 0
    fi
    
    echo "⚠️ 继续执行大型包安装流程" >&2
    
    # �️ 创建已安装核心包保护列表 - 防止依赖重装
    local PROTECTED_CORE_PACKAGES=()
    if [ -n "${CORE_PACKAGE_ARRAY:-}" ] && [ ${#CORE_PACKAGE_ARRAY[@]} -gt 0 ]; then
        for core_pkg in "${CORE_PACKAGE_ARRAY[@]}"; do
            if check_package_installed "$core_pkg"; then
                PROTECTED_CORE_PACKAGES+=("$core_pkg")
                info "🛡️ 保护已安装核心包: $core_pkg"
            fi
        done
    fi
    
    # �🚀 智能使用 CLI 指定的核心包,而不是硬编码列表
    local ESSENTIAL_LARGE_PACKAGES=()
    
    # 如果有 CLI 指定的核心包,优先使用
    if [ -n "${CORE_PACKAGE_ARRAY:-}" ] && [ ${#CORE_PACKAGE_ARRAY[@]} -gt 0 ]; then
        ESSENTIAL_LARGE_PACKAGES=("${CORE_PACKAGE_ARRAY[@]}")
        info "📋 使用 CLI 指定的核心包: ${ESSENTIAL_LARGE_PACKAGES[*]}"
    else
        # 回退到默认的大型包列表
        ESSENTIAL_LARGE_PACKAGES=(
            "torch" "torchvision" "torchaudio"
            "tensorflow" "transformers" "diffusers"
            "opencv-python" "pillow"
        )
        info "📋 使用默认大型包列表"
    fi
    
    # 检查是否有任何核心包需要安装
    local large_packages_needed=()
    
    # 🛡️ 应用保护过滤:从安装列表中移除已保护的核心包
    local filtered_packages=()
    readarray -t filtered_packages < <(filter_installed_packages "${ESSENTIAL_LARGE_PACKAGES[@]}")
    
    # 进一步过滤:移除已保护的核心包,防止依赖冲突重装
    for pkg in "${filtered_packages[@]}"; do
        local is_protected=false
        for protected_pkg in "${PROTECTED_CORE_PACKAGES[@]}"; do
            if [ "$pkg" = "$protected_pkg" ]; then
                info "🛡️ 跳过已保护核心包: $pkg (防止依赖重装)"
                is_protected=true
                break
            fi
        done
        if [ "$is_protected" = false ]; then
            large_packages_needed+=("$pkg")
        fi
    done
    
    if [ ${#large_packages_needed[@]} -eq 0 ]; then
        ok "🎉 所有核心大型包都已安装,跳过专项安装阶段"
        return 0
    fi
    
    # 给用户明确的提示
    info "📋 检测到需要安装的核心大型包 (${#large_packages_needed[@]}个):"
    for pkg in "${large_packages_needed[@]}"; do
        case "$pkg" in
            torch|torchvision|torchaudio)
                info "   🔥 $pkg - PyTorch生态系统 (~200-500MB)"
                ;;
            tensorflow)
                info "   🧠 $pkg - TensorFlow框架 (~400MB)"
                ;;
            transformers)
                info "   🤗 $pkg - Hugging Face模型库 (~100MB)"
                ;;
            diffusers)
                info "   🎨 $pkg - 扩散模型库 (~50MB)"
                ;;
            opencv-python)
                info "   👁️  $pkg - 计算机视觉库 (~90MB)"
                ;;
            *)
                info "   📦 $pkg - 核心依赖包"
                ;;
        esac
    done
    
    info "⚠️  注意: 这些包下载量较大,预计总下载量: 500MB-2GB"
    info "🌐 将使用最快的镜像源进行下载"
    info "⏰ 预计耗时: 2-15分钟 (取决于网络速度)"
    info "💡 下载过程中会显示详细的进度和速度信息"
    echo ""
    
    # 让用户有心理准备
    read -t 10 -p "⏳ 10秒后开始下载,按回车立即开始,或按Ctrl+C取消: " || true
    echo ""
    
    # 分批安装大型包 (避免内存压力)
    local batch_size=2
    local total_packages=${#large_packages_needed[@]}
    local current_batch=1
    local total_batches=$(( (total_packages + batch_size - 1) / batch_size ))
    
    for ((i=0; i /dev/null; then
        has_gpu=true
        info "✅ 检测到 GPU 环境"
    else
        info "ℹ️  未检测到 GPU 环境,跳过 GPU 版本验证"
        return 0
    fi
    
    # 检查 PyTorch 是否支持 CUDA
    local cuda_check_output=""
    cuda_check_output=$(python -c "
import torch
print(f'PyTorch版本: {torch.__version__}')
print(f'CUDA可用: {torch.cuda.is_available()}')
if torch.cuda.is_available():
    print(f'CUDA版本: {torch.version.cuda}')
    print(f'GPU设备: {torch.cuda.get_device_name(0)}')
    print('GPU_SUPPORTED')
elif '+cu' in torch.__version__ or 'cuda' in torch.__version__.lower():
    print('GPU版本已安装但CUDA不可用(可能是驱动问题)')
    print('GPU_VERSION_INSTALLED')
else:
    print('CPU_ON***')
" 2>&1)
    
    local cuda_check_exit_code=$?
    
    if [ $cuda_check_exit_code -ne 0 ]; then
        trace_error "PyTorch 导入失败" "$cuda_check_output" "$cuda_check_exit_code"
        error "❌ PyTorch 导入失败,请检查安装"
        return 1
    fi
    
    echo "$cuda_check_output"
    
    # 检查是否支持 GPU 或已安装 GPU 版本
    if echo "$cuda_check_output" | grep -q "GPU_SUPPORTED"; then
        ok "✅ PyTorch GPU 版本验证成功"
        return 0
    elif echo "$cuda_check_output" | grep -q "GPU_VERSION_INSTALLED"; then
        warn "⚠️  PyTorch GPU版本已安装但CUDA不可用,可能是驱动问题"
        ok "✅ PyTorch GPU 版本已正确安装,跳过重装"
        return 0
    elif echo "$cuda_check_output" | grep -q "CPU_ON***"; then
        warn "⚠️  检测到 CPU 版本的 PyTorch,需要重新安装 GPU 版本"
        
        # 强制重新安装 GPU 版本
        info "🔄 正在重新安装 GPU 版本的 PyTorch..."
        
        # 先卸载 CPU 版本
        info "📥 卸载当前版本..."
        pip uninstall torch torchvision torchaudio -y >/dev/null 2>&1 || true
        
        # 重新安装 GPU 版本
        if install_torch_gpu; then
            # 再次验证
            local recheck_output=""
            recheck_output=$(python -c "
import torch
print(f'重新安装后 - PyTorch版本: {torch.__version__}')
print(f'CUDA可用: {torch.cuda.is_available()}')
if torch.cuda.is_available():
    print(f'GPU设备: {torch.cuda.get_device_name(0)}')
    print('RECHECK_GPU_OK')
else:
    print('RECHECK_STILL_CPU')
" 2>&1)
            
            if echo "$recheck_output" | grep -q "RECHECK_GPU_OK"; then
                ok "✅ GPU 版本 PyTorch 重新安装成功"
                echo "$recheck_output"
                return 0
            else
                trace_error "PyTorch GPU 重新安装验证失败" "$recheck_output"
                error "❌ 重新安装后仍然不支持 GPU,请检查 CUDA 环境"
                return 1
            fi
        else
            error "❌ GPU 版本 PyTorch 重新安装失败"
            return 1
        fi
    else
        trace_error "PyTorch GPU 验证异常" "$cuda_check_output"
        error "❌ PyTorch GPU 验证结果异常"
        return 1
    fi
}

# 执行最终验证
if ! final_gpu_verification; then
    error "❌ PyTorch GPU 最终验证失败"
fi

info "🎉 环境配置完成!"

# -----------------------------
# 9. ✅ 最终成功提示(终端彩色 + 日志纯文本)
# -----------------------------

# 调用时先获取
get_activate_cmd "$ENV_NAME" "$ENV_PATH"

log_success "$PLATFORM" "$ENV_NAME" "$LOG_FILE" "$WORKSPACE" "$ACTIVATE_CMD" "$DETECTED_ENV_TYPE"


;>

20250905 0445 ...

立即注册
更新于:2025-09-05 04:45:23
    您需要登录后才可以评论。 立即注册
    相关内容

    Python 学习整理2

    fastapi-speaker-extractor whisperx 项目报错 ValueError: The chosen ...

    python报错 UnicodeEncodeError: 'gbk' codec can't encode character '\u...

    python whisperx 报错 in load_align_model raise ValueError(f'The ch...

    pyannote/embedding 模型是真难引入模型

    Trae 或者是我自己 莫名奇妙创建了个文件,影响了项目代码的运行。

    WhisperX 无法加载模型

    HUGGINGFACE_HUB_CACHE 设置错误导致的问题

    Trae的bug太多了,怪不得免费

    通义之旅

    通义之旅2

    目标说话人声音提取模型训练的思路

    python报错 can't convert cuda:0 device type tensor to numpy. Use Tenso...

    Expected all tensors to be on the same device, but found at least two ...

    腾讯元宝推荐的项目结构(音频处理项目)

    音频处理项目fse

    各种python 相关命令

    python 报错 SyntaxError: 'return' outside function

    python常用命令

    腾讯编程助手

    python一些扩展兼容安装的处理方案

    AI和Python 学习整理

    AudioSeparationGUI 对输入的音频,自动根据说话人进行分类 20250817

    SoloSpeech 项目安装和运行测试 20250817

    python 多项目部署 优先考虑用Anaconda

    espnet 声音分离

    ClearerVoice-Studio 安装测试遇到的问题,安装pysptk一直失败

    uvr5 bs roformer 爆显存以及关于huggingface的国内镜像hf-mirror.com

    用Kimi编程

    Studio One 调试插件Techivation AI-Rack 一键智能混音

    在hf-mirror.com模型镜像站用代码下载模型遇到报错 speaker-diarization模型不...

    用腾讯元宝编程

    Conda国内镜像源

    数字对象标识符 (DOI)

    在创建conda环境时,如果不指定Python版本,conda将不会默认安装Python。

    whisperx 的使用 音频处理

    Win10系统 Trae的使用 关于powershell报错: 因为在此系统上禁止运行脚本

    warp的使用

    AI编程工具比较

    FastApi

    python 学习中遇到的问题整理

    没有使用asynccontextmanager ,但是报cannot import name 'asynccontextman...

    python3.10.0+pyinstaller4.7打包,IndexError: tuple index out of range...

    error: Microsoft Visual C++ 14.0 or greater is required.

    安装conda搭建python环境(保姆级教程)

    学习飞浆过程中遇到“缺少paddle.fluid”

    [NLP实践01]simpletransformers安装和文本分类简单实现

    primeqa 安装requirements时报错

    sublime text下 Python 问题:TabError: inconsistent use of tabs and s...

    uiautomation报错 No module named 'comtypes.stream' Can not load UIA...

    解决无法加载UIAutomationCore.dll的报错

    汉字目标点选识别-ddddocr(返回识别的内容和位置)

    python 常用命令

    opencv报错及解决:AttributeError: module ‘cv2‘ has no attribute ‘...

    AttributeError: module 'cv2.cv2' has no attribute 'cv'

    sublime text常用快捷键及多行列模式批量操作教程

    python配置opencv环境后,读取图片,报错:can‘t open/read file: check f...

    各种服务器通用搭建python训练模型用的环境,以训练SoloSpeech为列子

    Python与模型相关知识以及问题的整理

    学习模型蒸馏之蒸馏SoloSpeech 2025年8月

    Google colab 测试运行SoloSpeech蒸馏项目中教师模型的训练

    学习模型蒸馏之蒸馏SoloSpeech 2025年8月 与通义对话

    腾讯云代码助手(Tencent Cloud CodeBuddy)插件在VS Code上

    线上训练数据的一些技巧

    云主机选择 试试 DigitalOcean 毕竟有新加坡服务器。

    云盘选择

    Linux/Ubuntu服务器命令行使用百度网盘

    SoloSpeech 模型训练终于有了眉目 20250829 2325

    各种和模型训练相关的工具

    相关问题报错

    python 调式代码的几种方法

    python报错 ModuleNotFoundError: No module named 'solospeech'​

    如何用有效的用conda安装python扩展

    SoloSpeech 训练的扩展安装

    python的一些包或扩展依赖于torch,会在安装的时候安装上torch的CPU版

    模型训练过程中的报错 unexpected pos 88457920 vs 88457808

    模型训练平台汇总

    Copilot的能力不低,不可小觑 20250902

    关于魔塔的静默提示,解决静默提醒提示。

    python -m py_compile "d:\python\SoloSpeech\solospeech\stable_audio_v...

    线上平台和CPU服务器压力测试

    Python的扩展和模块安装时遇到的问题整理

    windows环境下python3安装Crypto扩展

    pip install​ 报错 ERROR: Can not execute setup.py since setuptools i...

    运行python -V 报错 -bash: python: command not found

    protobuf requires Python ‘>=3.7‘ but the running Python is 3.6.5的解...

    推荐内容

    怎样使用V2Ray代理和SSTap玩如魔兽世界/绝地求生/LOL台服/战地3/黑色沙漠/彩...

    sstap游戏代理教程 从此玩如魔兽世界/绝地求生/LOL台服/战地3/黑色沙漠/彩虹六...

    BT磁力搜索网站汇总和找不到的资源

    什么是磁力链接,您如何使用?

    Z-Library:全球最大的数字图书馆/含打不开的解决方案/镜像

    使用V2Ray的mKCP协议加速游戏

    v2rayN已停止工作

    【车险课堂】什么是无赔款优待系数ncd,你“造”吗?