From b38b821c355675062917036f0ee288abe5ca9f2e Mon Sep 17 00:00:00 2001 From: dekun Date: Fri, 12 Jun 2026 13:32:06 +0800 Subject: [PATCH] Add one-click deploy script for /opt production setup with PM2. Co-authored-by: Cursor --- DEPLOY.md | 137 ++++++++++++++++-- README.md | 54 ++++--- config.py | 5 +- deploy.sh | 340 ++++++++++++++++++++++++++++++++++++++++++++ ecosystem.config.js | 15 +- 5 files changed, 519 insertions(+), 32 deletions(-) create mode 100644 deploy.sh diff --git a/DEPLOY.md b/DEPLOY.md index fbc07a8..b9b5abe 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -2,12 +2,14 @@ 本文档面向 **Ubuntu 物理服务器**(搭载 RTX 3060 Ti,已锁定 120W 功耗墙)的完整环境配置与 PM2 常驻部署流程。适用于首次安装或迁移重装场景。 +**标准安装路径:** `/opt/Trading_Studio`(root 用户) **Git 仓库:** https://git.bz121.com/dekun/Trading_Studio.git --- ## 目录 +0. [**一键部署(推荐)**](#0-一键部署推荐) 1. [硬件与系统前提](#1-硬件与系统前提) 2. [3060 Ti 120W 功耗墙配置](#2-3060-ti-120w-功耗墙配置) 3. [NVIDIA 驱动与 CUDA](#3-nvidia-驱动与-cuda) @@ -21,6 +23,112 @@ --- +## 0. 一键部署(推荐) + +项目内置 `deploy.sh`,以 **root** 用户将 Trading Studio 部署到 `/opt/Trading_Studio`,并自动完成依赖安装、虚拟环境、PyTorch CUDA、PM2 常驻与开机自启。 + +### 0.1 前提条件 + +在运行脚本前,请确保服务器已满足: + +| 项目 | 说明 | +|------|------| +| 系统 | Ubuntu 22.04 / 24.04 LTS | +| 用户 | **root**(`sudo -i` 切换) | +| GPU 驱动 | `nvidia-smi` 可正常输出 | +| 网络 | 可访问 `git.bz121.com` 拉取代码 | +| Ollama | 局域网 `192.168.8.64:11434` 可达(润色功能) | + +> **Git 认证:** 若 `git clone` 需要登录,请先在 root 下配置 HTTPS 凭据或 SSH 密钥,再执行部署脚本。 + +### 0.2 首次一键部署 + +```bash +# 切换 root +sudo -i + +# 方式 A:从 Git 克隆后执行(推荐) +git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio +cd /opt/Trading_Studio +chmod +x deploy.sh +bash deploy.sh + +# 方式 B:若已有本地代码目录,直接在该目录执行 +cd /opt/Trading_Studio +chmod +x deploy.sh +bash deploy.sh +``` + +脚本自动执行以下步骤: + +1. 安装系统依赖(python3、ffmpeg、libsndfile 等) +2. 安装 Node.js 20 + PM2 +3. 克隆/更新代码到 `/opt/Trading_Studio` +4. 创建 `venv/` 并安装 PyTorch cu121 + requirements.txt +5. 创建 `logs/`、`uploads/`、`outputs/` 目录 +6. 设置 GPU 120W 功耗墙(若 nvidia-smi 可用) +7. 放行防火墙端口 5683(若 ufw 已启用) +8. `pm2 start ecosystem.config.js` 并配置开机自启 + +部署成功后访问: + +``` +http://<服务器局域网IP>:5683 +``` + +### 0.3 脚本命令速查 + +```bash +cd /opt/Trading_Studio + +bash deploy.sh # 首次完整部署 + PM2 启动 +bash deploy.sh update # git pull + 更新依赖 + PM2 重启 +bash deploy.sh restart # 仅重启 PM2 +bash deploy.sh stop # 停止 PM2 +bash deploy.sh status # 查看 PM2 / GPU / 端口状态 +bash deploy.sh logs # 查看 PM2 最近 80 行日志 +bash deploy.sh help # 显示帮助 +``` + +### 0.4 日常更新流程 + +代码推送到 Git 后,在服务器上执行: + +```bash +sudo -i +cd /opt/Trading_Studio +bash deploy.sh update +``` + +### 0.5 PM2 运维(root 环境) + +```bash +pm2 status # 进程状态 +pm2 logs trading_studio # 实时日志 +pm2 restart trading_studio # 手动重启 +pm2 monit # 资源监控 + +# 应用日志 +tail -f /opt/Trading_Studio/trading_studio.log +tail -f /opt/Trading_Studio/logs/pm2-out.log +``` + +### 0.6 目录布局(/opt 标准路径) + +``` +/opt/Trading_Studio/ +├── deploy.sh # 一键部署脚本 +├── app.py # Gradio 主入口 +├── venv/ # Python 虚拟环境 +├── logs/ # PM2 日志 +├── uploads/ # 上传临时文件 +├── outputs/ # 合成 wav 输出 +├── speaker_emb.pt # 音色文件(Web UI 生成,需手动备份) +└── trading_studio.log # 应用日志 +``` + +--- + ## 1. 硬件与系统前提 | 项目 | 要求 | @@ -130,7 +238,7 @@ PyTorch cu121 wheel 通常自带运行时库。若 Whisper 报 cuDNN 错误: ```bash # 克隆项目 -cd ~ +cd /opt git clone https://git.bz121.com/dekun/Trading_Studio.git cd Trading_Studio @@ -184,7 +292,7 @@ GPU: NVIDIA GeForce RTX 3060 Ti ```bash source venv/bin/activate -cd ~/Trading_Studio +cd /opt/Trading_Studio # 安装其余依赖 pip install -r requirements.txt @@ -270,7 +378,7 @@ curl http://192.168.8.64:11434/api/chat -d '{ ```bash source venv/bin/activate -cd ~/Trading_Studio +cd /opt/Trading_Studio # 前台启动(调试) python app.py @@ -341,7 +449,7 @@ module.exports = { 启动: ```bash -cd ~/Trading_Studio +cd /opt/Trading_Studio mkdir -p logs pm2 start ecosystem.config.js @@ -349,10 +457,12 @@ pm2 status pm2 logs trading_studio --lines 50 ``` +> **推荐:** 直接使用 `bash deploy.sh` 一键完成上述步骤,见 [第 0 节](#0-一键部署推荐)。 + ### 9.3 方式 B:直接命令行 ```bash -cd ~/Trading_Studio +cd /opt/Trading_Studio pm2 start app.py \ --name "trading_studio" \ @@ -382,7 +492,14 @@ pm2 monit # 实时监控 CPU/内存 ### 9.6 更新代码后重新部署 ```bash -cd ~/Trading_Studio +cd /opt/Trading_Studio +bash deploy.sh update +``` + +或手动: + +```bash +cd /opt/Trading_Studio git pull source venv/bin/activate pip install -r requirements.txt # 若有新依赖 @@ -395,10 +512,10 @@ pm2 restart trading_studio ### 10.1 迁移到新机器 -1. 复制 `speaker_emb.pt`(音色文件,在 `.gitignore` 中,需手动备份) -2. 新机器按本文档完整部署 -3. 将 `speaker_emb.pt` 放回项目根目录 -4. `pm2 restart trading_studio` +1. 备份 `/opt/Trading_Studio/speaker_emb.pt`(音色文件,不入 Git) +2. 新机器执行 `bash deploy.sh` 一键部署 +3. 将 `speaker_emb.pt` 复制回 `/opt/Trading_Studio/` +4. `bash deploy.sh restart` ### 10.2 CUDA / 显存问题 diff --git a/README.md b/README.md index e067280..f9b5980 100644 --- a/README.md +++ b/README.md @@ -52,20 +52,36 @@ Trading Studio 是一套运行在 Ubuntu 物理服务器(RTX 3060 Ti)上的 > 完整环境配置请参阅 [DEPLOY.md](./DEPLOY.md) -```bash -# 1. 克隆仓库 -git clone https://git.bz121.com/dekun/Trading_Studio.git -cd Trading_Studio +### 一键部署(生产环境推荐) -# 2. 创建虚拟环境并安装依赖(详见 DEPLOY.md) +以 **root** 用户部署到 `/opt/Trading_Studio` 并由 PM2 常驻: + +```bash +sudo -i +git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio +cd /opt/Trading_Studio +chmod +x deploy.sh +bash deploy.sh +``` + +浏览器访问:`http://<服务器IP>:5683` + +日常更新: + +```bash +cd /opt/Trading_Studio && bash deploy.sh update +``` + +### 手动部署(开发调试) + +```bash +git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio +cd /opt/Trading_Studio python3 -m venv venv source venv/bin/activate pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install -r requirements.txt - -# 3. 启动中控 python app.py -# 浏览器访问: http://<服务器IP>:5683 ``` --- @@ -108,18 +124,21 @@ python app.py ## PM2 守护运行 -```bash -# 方式 1:ecosystem 配置 -pm2 start ecosystem.config.js +标准路径 `/opt/Trading_Studio`,root 用户: -# 方式 2:直接命令 -pm2 start app.py --name "trading_studio" --interpreter ./venv/bin/python +```bash +# 一键部署 + PM2 启动(推荐) +cd /opt/Trading_Studio && bash deploy.sh + +# 或手动 PM2 +pm2 start ecosystem.config.js # 常用管理 pm2 status pm2 logs trading_studio -pm2 restart trading_studio -pm2 save && pm2 startup # 开机自启 +bash deploy.sh restart # 重启 +bash deploy.sh update # 拉代码 + 更新依赖 + 重启 +pm2 save && pm2 startup # 开机自启(deploy.sh 已自动配置) ``` --- @@ -150,6 +169,7 @@ outputs/ ``` Trading_Studio/ +├── deploy.sh # 一键部署脚本(/opt + PM2) ├── app.py # Gradio 主入口 ├── config.py # 全局配置 ├── whisper_service.py # Whisper CUDA 识别 @@ -158,13 +178,15 @@ Trading_Studio/ ├── ecosystem.config.js # PM2 守护配置 ├── requirements.txt # Python 依赖 ├── README.md # 本文件 -├── DEPLOY.md # 部署指南 +├── DEPLOY.md # 部署指南(含一键部署教程) ├── .gitignore ├── speaker_emb.pt # 音色文件(运行时生成,不入库) ├── uploads/ # 上传临时目录 └── outputs/ # 合成 wav 输出 ``` +**生产标准路径:** `/opt/Trading_Studio` + --- ## 硬件要求 diff --git a/config.py b/config.py index 37b13af..f6b53d7 100644 --- a/config.py +++ b/config.py @@ -47,7 +47,10 @@ WHISPER_LANGUAGE = "zh" # --------------------------------------------------------------------------- # ChatTTS 配置 # --------------------------------------------------------------------------- -# 项目根目录 +# 标准生产安装路径(/opt,root 部署) +INSTALL_DIR = Path("/opt/Trading_Studio") + +# 项目根目录(开发/生产均自适应,以实际 app.py 所在目录为准) BASE_DIR = Path(__file__).resolve().parent # 固定音色 Embedding 存储路径 diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..df175f7 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env bash +# ============================================================================= +# Trading Studio 一键部署脚本 +# 安装路径: /opt/Trading_Studio +# 运行用户: root +# 功能: 系统依赖 → 代码拉取 → Python 虚拟环境 → PyTorch CUDA → PM2 常驻 +# +# 用法: +# sudo bash deploy.sh # 首次完整部署并 PM2 启动 +# sudo bash deploy.sh update # 拉取最新代码、更新依赖、重启 PM2 +# sudo bash deploy.sh restart # 仅重启 PM2 进程 +# sudo bash deploy.sh stop # 停止 PM2 进程 +# sudo bash deploy.sh status # 查看 PM2 与 GPU 状态 +# sudo bash deploy.sh logs # 查看 PM2 最近日志 +# ============================================================================= + +set -euo pipefail + +# --------------------------------------------------------------------------- +# 可配置常量 +# --------------------------------------------------------------------------- +INSTALL_DIR="/opt/Trading_Studio" +GIT_REPO="https://git.bz121.com/dekun/Trading_Studio.git" +PM2_APP_NAME="trading_studio" +GRADIO_PORT=5683 +GPU_POWER_LIMIT=120 +PYTORCH_INDEX="https://download.pytorch.org/whl/cu121" + +# --------------------------------------------------------------------------- +# 颜色输出 +# --------------------------------------------------------------------------- +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +log_info() { echo -e "${CYAN}[INFO]${NC} $*"; } +log_ok() { echo -e "${GREEN}[OK]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } + +# --------------------------------------------------------------------------- +# 前置检查 +# --------------------------------------------------------------------------- +require_root() { + if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then + log_error "请使用 root 用户运行: sudo bash deploy.sh" + exit 1 + fi +} + +check_gpu() { + if command -v nvidia-smi &>/dev/null; then + log_ok "检测到 NVIDIA GPU:" + nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader + else + log_warn "未检测到 nvidia-smi,Whisper/ChatTTS CUDA 加速可能不可用。" + fi +} + +set_gpu_power_limit() { + if command -v nvidia-smi &>/dev/null; then + log_info "设置 GPU 功耗上限为 ${GPU_POWER_LIMIT}W ..." + if nvidia-smi -pl "${GPU_POWER_LIMIT}" &>/dev/null; then + log_ok "GPU 功耗墙已设为 ${GPU_POWER_LIMIT}W" + else + log_warn "无法设置功耗墙,请手动执行: nvidia-smi -pl ${GPU_POWER_LIMIT}" + fi + fi +} + +# --------------------------------------------------------------------------- +# 系统依赖 +# --------------------------------------------------------------------------- +install_system_deps() { + log_info "安装系统依赖 ..." + apt-get update -qq + apt-get install -y \ + git curl wget build-essential \ + python3 python3-venv python3-dev python3-pip \ + ffmpeg libsndfile1 portaudio19-dev \ + ca-certificates gnupg + + log_ok "系统依赖安装完成" +} + +install_node_pm2() { + if command -v pm2 &>/dev/null; then + log_ok "PM2 已安装: $(pm2 -v)" + return + fi + + log_info "安装 Node.js 20 LTS 与 PM2 ..." + if ! command -v node &>/dev/null; then + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y nodejs + fi + npm install -g pm2 + log_ok "PM2 安装完成: $(pm2 -v)" +} + +# --------------------------------------------------------------------------- +# 代码部署 +# --------------------------------------------------------------------------- +deploy_code() { + if [[ -d "${INSTALL_DIR}/.git" ]]; then + log_info "更新已有代码: ${INSTALL_DIR}" + git -C "${INSTALL_DIR}" pull --ff-only || { + log_warn "git pull 失败,尝试保留本地更改继续部署 ..." + } + elif [[ -d "${INSTALL_DIR}" ]]; then + log_error "${INSTALL_DIR} 已存在但不是 git 仓库,请手动处理后重试。" + exit 1 + else + log_info "克隆仓库到 ${INSTALL_DIR} ..." + git clone "${GIT_REPO}" "${INSTALL_DIR}" + fi + log_ok "代码就绪: ${INSTALL_DIR}" +} + +# --------------------------------------------------------------------------- +# Python 环境 +# ------------------------------------------------------------------- +setup_python_venv() { + local venv_path="${INSTALL_DIR}/venv" + + if [[ ! -d "${venv_path}" ]]; then + log_info "创建 Python 虚拟环境 ..." + python3 -m venv "${venv_path}" + fi + + # shellcheck disable=SC1091 + source "${venv_path}/bin/activate" + + log_info "升级 pip ..." + pip install --upgrade pip setuptools wheel -q + + log_info "安装 PyTorch (CUDA 12.1) ..." + pip install torch torchvision torchaudio --index-url "${PYTORCH_INDEX}" -q + + log_info "安装项目依赖 ..." + pip install -r "${INSTALL_DIR}/requirements.txt" -q + + # 验证 CUDA + if python -c "import torch; assert torch.cuda.is_available()" 2>/dev/null; then + log_ok "PyTorch CUDA 可用: $(python -c 'import torch; print(torch.cuda.get_device_name(0))')" + else + log_warn "PyTorch CUDA 不可用,请检查 NVIDIA 驱动与 CUDA 运行时。" + fi + + deactivate + log_ok "Python 虚拟环境配置完成" +} + +create_runtime_dirs() { + mkdir -p "${INSTALL_DIR}/logs" + mkdir -p "${INSTALL_DIR}/uploads" + mkdir -p "${INSTALL_DIR}/outputs" + log_ok "运行时目录已创建 (logs, uploads, outputs)" +} + +# --------------------------------------------------------------------------- +# 防火墙 +# --------------------------------------------------------------------------- +configure_firewall() { + if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then + log_info "放行 Gradio 端口 ${GRADIO_PORT} ..." + ufw allow "${GRADIO_PORT}/tcp" || true + log_ok "防火墙规则已更新" + else + log_info "ufw 未启用,跳过防火墙配置" + fi +} + +# --------------------------------------------------------------------------- +# PM2 管理 +# --------------------------------------------------------------------------- +pm2_start() { + log_info "通过 PM2 启动 Trading Studio ..." + cd "${INSTALL_DIR}" + + # 若已有同名进程则先删除再启动,避免重复 + if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then + pm2 delete "${PM2_APP_NAME}" || true + fi + + pm2 start ecosystem.config.js + pm2 save + + # 配置 root 用户开机自启 + local startup_cmd + startup_cmd=$(pm2 startup systemd -u root --hp /root 2>&1 | grep "sudo env" || true) + if [[ -n "${startup_cmd}" ]]; then + eval "${startup_cmd}" || log_warn "PM2 startup 可能已配置过" + fi + pm2 save + + log_ok "PM2 启动完成" + pm2 status +} + +pm2_restart() { + cd "${INSTALL_DIR}" + if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then + pm2 restart "${PM2_APP_NAME}" + log_ok "PM2 已重启: ${PM2_APP_NAME}" + else + log_warn "进程不存在,执行完整启动 ..." + pm2_start + fi + pm2 status +} + +pm2_stop() { + if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then + pm2 stop "${PM2_APP_NAME}" + log_ok "PM2 已停止: ${PM2_APP_NAME}" + else + log_warn "PM2 进程 ${PM2_APP_NAME} 不存在" + fi + pm2 status +} + +pm2_status() { + echo "" + log_info "=== PM2 状态 ===" + pm2 status || true + echo "" + log_info "=== GPU 状态 ===" + nvidia-smi 2>/dev/null || log_warn "nvidia-smi 不可用" + echo "" + log_info "=== 端口 ${GRADIO_PORT} 监听 ===" + ss -tlnp | grep ":${GRADIO_PORT}" || log_warn "端口 ${GRADIO_PORT} 未监听,服务可能未启动" + echo "" + log_info "访问地址: http://$(hostname -I | awk '{print $1}'):${GRADIO_PORT}" +} + +pm2_logs() { + pm2 logs "${PM2_APP_NAME}" --lines 80 --nostream || true +} + +# --------------------------------------------------------------------------- +# 主流程 +# --------------------------------------------------------------------------- +cmd_install() { + log_info "========== Trading Studio 一键部署开始 ==========" + log_info "安装目录: ${INSTALL_DIR}" + log_info "运行用户: root" + + install_system_deps + install_node_pm2 + deploy_code + setup_python_venv + create_runtime_dirs + set_gpu_power_limit + configure_firewall + pm2_start + + echo "" + log_ok "========== 部署完成 ==========" + echo "" + echo -e " Web 中控: ${GREEN}http://$(hostname -I | awk '{print $1}'):${GRADIO_PORT}${NC}" + echo -e " 项目目录: ${INSTALL_DIR}" + echo -e " 查看日志: ${CYAN}pm2 logs ${PM2_APP_NAME}${NC}" + echo -e " 重启服务: ${CYAN}bash ${INSTALL_DIR}/deploy.sh restart${NC}" + echo "" + log_warn "首次使用请打开 Web UI「音色锁定」上传参考人声,生成 speaker_emb.pt" +} + +cmd_update() { + log_info "========== 更新部署 ==========" + deploy_code + setup_python_venv + create_runtime_dirs + pm2_restart + log_ok "更新完成" +} + +print_usage() { + cat <