#!/usr/bin/env bash # 财务大模型智能问答客服系统 — 后端一键落地脚本 # # 前置: # - Ubuntu 24.04,Python 3.12、postgresql、redis-server、nginx 已通过 apt 安装 # - 代码已放在 /home/ubuntu/finai/{backend,frontend,miniapp} # - 用 ubuntu 账号执行本脚本;脚本内需要 root 权限的步骤会自己 sudo # # 用法: # bash /home/ubuntu/finai/deploy/setup-backend.sh # 可选环境变量: # DOMAIN=finai.ctc-zc.com 站点域名(写进 ALLOWED_ORIGINS) # DB_NAME=finai PG 库名 = 用户名 # DB_PASS=<留空自动生成> PG 用户密码 # FORCE_ENV=1 即使 .env 已存在也覆盖重写 # # 幂等性: # venv、依赖、PG 用户/库、.env、systemd unit 均检查后再动作,重复执行安全。 set -Eeuo pipefail # ─── 可调参数 ────────────────────────────────────────────── FINAI_HOME="/home/ubuntu/finai" BACKEND_DIR="${FINAI_HOME}/backend" STORAGE_DIR="${BACKEND_DIR}/storage" VENV_DIR="${BACKEND_DIR}/.venv" ENV_FILE="${BACKEND_DIR}/.env" DOMAIN="${DOMAIN:-finai.ctc-zc.com}" DB_NAME="${DB_NAME:-finai}" DB_USER="${DB_NAME}" DB_PASS="${DB_PASS:-}" FORCE_ENV="${FORCE_ENV:-0}" SERVICE_NAME="finai-backend" SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" # ─── 工具函数 ────────────────────────────────────────────── c_green() { printf '\033[32m%s\033[0m\n' "$*"; } c_yellow() { printf '\033[33m%s\033[0m\n' "$*"; } c_red() { printf '\033[31m%s\033[0m\n' "$*" >&2; } step() { printf '\n\033[36m▶ %s\033[0m\n' "$*"; } require_cmd() { command -v "$1" >/dev/null 2>&1 || { c_red "缺少命令:$1,请先 apt 安装对应包"; exit 1; } } # ─── 0. 前置检查 ─────────────────────────────────────────── step "0. 前置检查" if [[ "${EUID}" -eq 0 ]]; then c_red "请用 ubuntu 账号(非 root)运行,脚本内部会按需 sudo。" exit 1 fi if [[ "$(whoami)" != "ubuntu" ]]; then c_yellow "当前用户是 $(whoami)(非 ubuntu),若你确认要用当前用户可继续,5 秒内 Ctrl+C 中止…" sleep 5 fi require_cmd python3.12 require_cmd psql require_cmd systemctl require_cmd openssl require_cmd curl if [[ ! -d "${BACKEND_DIR}" ]]; then c_red "找不到 ${BACKEND_DIR},请先把代码上传到 ${FINAI_HOME}/backend" exit 1 fi if [[ ! -f "${BACKEND_DIR}/pyproject.toml" ]]; then c_red "${BACKEND_DIR}/pyproject.toml 不存在,代码目录不完整" exit 1 fi sudo chown -R ubuntu:ubuntu "${FINAI_HOME}" # ─── 1. Python 虚拟环境 + 依赖 ───────────────────────────── step "1. 虚拟环境 & 依赖" if [[ ! -x "${VENV_DIR}/bin/python" ]]; then python3.12 -m venv "${VENV_DIR}" c_green "venv 已创建:${VENV_DIR}" else c_yellow "venv 已存在,跳过创建" fi # shellcheck disable=SC1091 source "${VENV_DIR}/bin/activate" pip install --upgrade pip >/dev/null pip install . >/dev/null c_green "依赖安装完成" python - <<'PY' import fastapi, sqlalchemy, pydantic_settings, httpx from tencentcloud.lke.v20231130 import lke_client # noqa: F401 print(f" fastapi={fastapi.__version__} sqlalchemy={sqlalchemy.__version__}") PY mkdir -p "${STORAGE_DIR}" # ─── 2. PostgreSQL 库 & 用户 ─────────────────────────────── step "2. PostgreSQL 建库建用户" sudo systemctl is-active --quiet postgresql || { c_red "postgresql 服务未运行,先 sudo systemctl start postgresql" exit 1 } user_exists=$(sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" || true) db_exists=$(sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'" || true) if [[ "${user_exists}" != "1" ]]; then if [[ -z "${DB_PASS}" ]]; then DB_PASS="$(openssl rand -hex 16)" c_yellow "自动生成 DB_PASS = ${DB_PASS} ← 保存好" fi sudo -u postgres psql -v ON_ERROR_STOP=1 < "${ENV_FILE}" </dev/null </dev/null sudo systemctl restart "${SERVICE_NAME}" sleep 2 sudo systemctl --no-pager status "${SERVICE_NAME}" | head -n 12 || true # ─── 5. 健康检查 ────────────────────────────────────────── step "5. 健康检查" for i in 1 2 3 4 5; do if curl -fsS http://127.0.0.1:8000/health >/dev/null; then c_green "GET /health OK" break fi if [[ "$i" == "5" ]]; then c_red "5 次探测均失败,跑 journalctl -u ${SERVICE_NAME} -n 100 --no-pager 排查" exit 1 fi sleep 2 done # ─── 6. 总结 ────────────────────────────────────────────── step "6. 完成 ✔" cat <