Files
dy/install.sh
2026-07-23 17:56:25 +08:00

362 lines
11 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 抖音客服系统 - Linux 一键安装(兼容宝塔 Python 项目 + 原生 CentOS/Ubuntu
# 用法:
# ./install.sh # 自动探测可用 Python 并安装
# ./install.sh --diagnose # 仅列出本机 Python 探测结果
# AUTO_BUILD_PYTHON=1 ./install.sh # 无可用 Python 时自动编译 3.11
# KEFU_PYTHON=/path/to/python3 ./install.sh # 手动指定
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
MIN_PY_MAJOR=3
MIN_PY_MINOR=10
DIAGNOSE=0
AUTO_BUILD="${AUTO_BUILD_PYTHON:-0}"
for arg in "$@"; do
case "$arg" in
--diagnose) DIAGNOSE=1 ;;
--build-python) AUTO_BUILD=1 ;;
esac
done
echo "========================================"
echo " 抖音客服系统 - 依赖安装"
echo "========================================"
echo
# ---------- Python 检测工具 ----------
check_python_ssl() {
"$1" -c "import ssl" 2>/dev/null
}
check_python_version() {
"$1" -c "import sys; sys.exit(0 if sys.version_info >= ($MIN_PY_MAJOR, $MIN_PY_MINOR) else 1)" 2>/dev/null
}
python_brief() {
local py="$1"
if [ ! -x "$py" ]; then
echo "不存在"
return
fi
local ver ssl
ver="$("$py" -V 2>&1 | awk '{print $2}')" || ver="?"
if check_python_ssl "$py"; then
ssl="$("$py" -c "import ssl; print(ssl.OPENSSL_VERSION)" 2>/dev/null)"
else
ssl="无SSL"
fi
echo "${ver} | ${ssl}"
}
try_python() {
local py="$1"
[ -n "$py" ] && [ -x "$py" ] || return 1
check_python_ssl "$py" || return 1
check_python_version "$py" || return 1
return 0
}
# 收集候选 Python(去重,高版本优先)
declare -a CANDIDATES=()
declare -A SEEN=()
add_candidate() {
local py="$1"
[ -n "$py" ] || return 0
if [ -x "$py" ] && [ -z "${SEEN[$py]:-}" ]; then
SEEN[$py]=1
CANDIDATES+=("$py")
fi
}
collect_python_candidates() {
CANDIDATES=()
SEEN=()
# 1) 用户指定
[ -n "${KEFU_PYTHON:-}" ] && add_candidate "$KEFU_PYTHON"
# 2) 当前 shell(宝塔 source 项目环境后 which python 会指向项目 Python
add_candidate "$(command -v python 2>/dev/null || true)"
add_candidate "$(command -v python3 2>/dev/null || true)"
add_candidate "$(command -v python3.11 2>/dev/null || true)"
add_candidate "$(command -v python3.10 2>/dev/null || true)"
# 3) 虚拟环境
[ -n "${VIRTUAL_ENV:-}" ] && add_candidate "${VIRTUAL_ENV}/bin/python"
# 4) 宝塔 Python 项目环境(多版本目录名,动态扫描,不写死单一版本)
local base py ver_dir
for base in \
/www/server/pyporject_evn/versions \
/home/www/server/pyporject_evn/versions \
/www/server/panel/pyenv/versions \
/www/server/python_project/versions; do
[ -d "$base" ] || continue
for ver_dir in "$base"/*; do
[ -d "$ver_dir" ] || continue
for py in "$ver_dir"/bin/python3.* "$ver_dir"/bin/python3 "$ver_dir"/bin/python; do
add_candidate "$py"
done
done
done
# 5) 源码/包管理器安装路径
for py in \
/usr/local/python3.11/bin/python3.11 \
/usr/local/python3.10/bin/python3.10 \
/usr/local/bin/python3.11 /usr/local/bin/python3.10 \
/usr/bin/python3.11 /usr/bin/python3.10; do
add_candidate "$py"
done
# 6) conda
add_candidate "${CONDA_PREFIX:-}/bin/python"
for py in /opt/miniconda3/envs/*/bin/python /root/miniconda3/envs/*/bin/python; do
[ -e "$py" ] && add_candidate "$py"
done
}
sort_candidates_by_version() {
local -a sorted=()
local py ver
while IFS= read -r line; do
sorted+=("$line")
done < <(
for py in "${CANDIDATES[@]}"; do
ver="$("$py" -V 2>&1 | awk '{print $2}' || echo 0.0.0)"
echo "$ver $py"
done | sort -t. -k1,1nr -k2,2nr -k3,3nr | awk '{print $2}'
)
CANDIDATES=("${sorted[@]}")
}
select_python() {
local py
collect_python_candidates
if [ "${#CANDIDATES[@]}" -eq 0 ]; then
return 1
fi
sort_candidates_by_version
for py in "${CANDIDATES[@]}"; do
if try_python "$py"; then
echo "$py"
return 0
fi
done
return 1
}
print_diagnose() {
local py tag
echo "[诊断] 本机 Python 探测结果(需要 3.10+ 且带 SSL:"
echo
collect_python_candidates
if [ "${#CANDIDATES[@]}" -eq 0 ]; then
echo " (未找到任何 Python 可执行文件)"
return
fi
sort_candidates_by_version
for py in "${CANDIDATES[@]}"; do
if try_python "$py"; then tag="可用"; else tag="不可用"; fi
printf " [%s] %s\n %s\n" "$tag" "$py" "$(python_brief "$py")"
done
echo
if [ -d /www/server/panel ] || [ -d /www/server/pyporject_evn ] || [ -d /home/www/server/pyporject_evn ]; then
echo " 环境: 检测到宝塔面板"
echo " 提示: 宝塔 Python 项目需先 source 项目环境,或确保 pyporject_evn 下 Python 带 _ssl"
else
echo " 环境: 原生 Linux"
fi
}
build_python311() {
local PYVER="3.11.9" PY_SHORT="3.11"
local PREFIX="/usr/local/python${PY_SHORT}"
local PY_BIN="${PREFIX}/bin/python${PY_SHORT}"
local SRC="/usr/src/Python-${PYVER}"
if [ "$(id -u)" -ne 0 ]; then
echo "[错误] 自动编译 Python 需要 root 权限"
return 1
fi
if [ -x "$PY_BIN" ] && try_python "$PY_BIN"; then
echo "[OK] 已存在可用 Python: $PY_BIN"
echo "$PY_BIN"
return 0
fi
echo "[编译] 未找到可用 Python,开始编译 ${PYVER} -> ${PREFIX}(约 10 分钟)"
if command -v yum &>/dev/null; then
yum groupinstall -y "Development Tools" 2>/dev/null || yum install -y gcc make
yum install -y openssl openssl-devel libffi-devel zlib-devel bzip2-devel \
readline-devel sqlite-devel xz-devel wget tar
elif command -v apt-get &>/dev/null; then
apt-get update
apt-get install -y build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev libffi-dev wget tar
else
echo "[错误] 不支持的包管理器"
return 1
fi
mkdir -p /usr/src && cd /usr/src
if [ ! -f "Python-${PYVER}.tgz" ]; then
wget -q "https://www.python.org/ftp/python/${PYVER}/Python-${PYVER}.tgz" \
|| wget -q "https://registry.npmmirror.com/-/binary/python/${PYVER}/Python-${PYVER}.tgz"
fi
rm -rf "$SRC" && tar xzf "Python-${PYVER}.tgz" && cd "$SRC"
./configure --prefix="$PREFIX" --enable-optimizations --with-openssl=/usr
make -j"$(nproc 2>/dev/null || echo 2)"
make altinstall
try_python "$PY_BIN" || return 1
echo "[OK] 编译完成: $PY_BIN"
echo "$PY_BIN"
}
# ---------- 选择 Python ----------
if [ "$DIAGNOSE" -eq 1 ]; then
print_diagnose
exit 0
fi
PYTHON=""
if [ -n "${KEFU_PYTHON:-}" ]; then
if [ ! -x "$KEFU_PYTHON" ]; then
echo "[错误] KEFU_PYTHON 不存在: $KEFU_PYTHON"
echo " 运行 ./install.sh --diagnose 查看本机可用 Python"
exit 1
fi
if ! try_python "$KEFU_PYTHON"; then
echo "[错误] KEFU_PYTHON 不可用(需 3.10+ 且带 SSL: $KEFU_PYTHON"
echo " 详情: $(python_brief "$KEFU_PYTHON")"
echo " 运行 ./install.sh --diagnose 查看全部候选"
exit 1
fi
PYTHON="$KEFU_PYTHON"
else
if ! PYTHON="$(select_python)"; then
print_diagnose
echo "[错误] 未找到可用的 Python 3.10+(需带 SSL 模块)。"
echo
if [ "$AUTO_BUILD" = "1" ] || [ "$AUTO_BUILD" = "yes" ]; then
PYTHON="$(build_python311)" || exit 1
else
echo " 宝塔用户常见原因: pyporject_evn 里的 Python 编译时缺少 openssl-devel。"
echo
echo " 解决方式(任选):"
echo " 1) 自动编译 Python 3.11:"
echo " AUTO_BUILD_PYTHON=1 ./install.sh"
echo " 2) 宝塔面板卸载 Python 3.11 后执行:"
echo " yum install -y openssl openssl-devel && 在面板重装 Python 3.11"
echo " 3) 手动指定已验证可用的 Python:"
echo " KEFU_PYTHON=/path/to/python3.11 ./install.sh"
echo " 4) 查看探测详情:"
echo " ./install.sh --diagnose"
exit 1
fi
fi
fi
echo "[OK] $("$PYTHON" --version) @ $PYTHON"
"$PYTHON" -c "import ssl; print('[OK] OpenSSL:', ssl.OPENSSL_VERSION)"
# ---------- Node.js ----------
if ! command -v node &>/dev/null; then
echo "[警告] 未找到 Node.js,私信签名将无法工作"
echo " 宝塔: 软件商店 -> Node 版本管理器 -> 安装 Node 18+"
else
echo "[OK] Node $(node --version)"
fi
echo
# ---------- 1. Python venv ----------
echo "[1/6] Python 虚拟环境与 pip 包..."
cd "$ROOT/backend"
VENV_PY=".venv/bin/python"
need_new_venv=0
if [ ! -x "$VENV_PY" ]; then
need_new_venv=1
elif ! try_python "$VENV_PY"; then
echo " 现有 .venv 不符合要求,删除并重建..."
rm -rf .venv
need_new_venv=1
fi
if [ "$need_new_venv" -eq 1 ]; then
echo " 创建 .venv <- $PYTHON"
"$PYTHON" -m venv .venv
fi
try_python "$VENV_PY" || { echo "[错误] .venv 创建失败"; exit 1; }
chmod +x .venv/bin/python .venv/bin/pip 2>/dev/null || true
.venv/bin/python -m pip install -U pip -q
.venv/bin/pip install -r requirements.txt
echo " Python 依赖完成"
echo
# ---------- 2. Playwright ----------
echo "[2/6] Playwright Chromium..."
export PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSERS_PATH:-$ROOT/playwright-browsers}"
.venv/bin/python -m playwright install chromium
if [ "$(uname -s)" = "Linux" ]; then
.venv/bin/python -m playwright install-deps chromium 2>/dev/null \
|| echo "[警告] install-deps 失败,可手动以 root 执行"
fi
echo " 路径: $PLAYWRIGHT_BROWSERS_PATH"
echo
# ---------- 3. IM Node 依赖 ----------
echo "[3/6] IM 签名依赖..."
cd "$ROOT/backend/rpa_engine/douyin_im/static"
if [ -f package.json ]; then
npm install --no-fund --no-audit
echo " jsrsasign 完成"
fi
echo
# ---------- 4. 前端依赖 ----------
echo "[4/6] 前端依赖..."
cd "$ROOT/frontend"
if [ -f package.json ]; then
npm install --no-fund --no-audit
echo " 前端 npm 完成"
fi
echo
# ---------- 5. 构建前端 ----------
echo "[5/6] 构建前端..."
if [ -f "$ROOT/frontend/package.json" ]; then
cd "$ROOT/frontend" && npm run build
echo " -> frontend/dist"
fi
echo
# ---------- 6. 校验 ----------
echo "[6/6] 校验..."
cd "$ROOT/backend"
.venv/bin/python -c "import fastapi, uvicorn, playwright, execjs; print(' 核心包 OK')"
[ -f "$ROOT/frontend/dist/index.html" ] && echo " 前端静态 OK" \
|| echo "[警告] 未找到 frontend/dist/index.html"
echo
echo "========================================"
echo " 安装完成"
echo
echo " 启动: ./start_web.sh"
echo " API: ./start_backend.sh"
echo " 地址: http://服务器IP:8000"
echo
echo " 宝塔 Python 项目:"
echo " 项目路径: $ROOT/backend"
echo " 启动命令: bash $ROOT/backend/baota_start.sh"
echo " 初始化: bash $ROOT/backend/baota_init.sh"
echo " 详见: deploy/baota.md"
echo "========================================"