#!/usr/bin/env bash # 在 105 服务器上执行(/root/wordloop) set -euo pipefail ROOT="${WORDLOOP_ROOT:-/root/wordloop}" cd "$ROOT" MYSQL_HOST="${MYSQL_HOST:?MYSQL_HOST required}" MYSQL_PORT="${MYSQL_PORT:-3306}" MYSQL_USER="${MYSQL_USER:?MYSQL_USER required}" MYSQL_PASSWORD="${MYSQL_PASSWORD:?MYSQL_PASSWORD required}" MYSQL_DATABASE="${MYSQL_DATABASE:-wordloop}" if [ -z "${WORDLOOP_SECRET_KEY:-}" ] && [ -f "$ROOT/backend/.env" ]; then WORDLOOP_SECRET_KEY="$(grep -E '^WORDLOOP_SECRET_KEY=' "$ROOT/backend/.env" | cut -d= -f2- || true)" fi WORDLOOP_SECRET_KEY="${WORDLOOP_SECRET_KEY:-$(openssl rand -hex 32)}" DEEPSEEK_API_KEY="${DEEPSEEK_API_KEY:-}" DEEPSEEK_BASE_URL="${DEEPSEEK_BASE_URL:-https://api.deepseek.com}" DEEPSEEK_MODEL="${DEEPSEEK_MODEL:-deepseek-chat}" AI_WIKI_DAILY_LLM_LIMIT="${AI_WIKI_DAILY_LLM_LIMIT:-20}" TKMIND_TTS_BASE_URL="${TKMIND_TTS_BASE_URL:-http://127.0.0.1:19200}" TKMIND_TTS_ENABLED="${TKMIND_TTS_ENABLED:-true}" TKMIND_TTS_SPK_ID="${TKMIND_TTS_SPK_ID:-aitong}" echo ">>> 写入 backend/.env" cat > "$ROOT/backend/.env" <>> Python 虚拟环境与依赖" cd "$ROOT/backend" if [ ! -d venv ]; then python3 -m venv venv fi source venv/bin/activate pip install -q -r requirements.txt echo ">>> OCR 依赖(iOS 拍照录入走服务端识别)" if command -v tesseract >/dev/null 2>&1; then echo "tesseract 已安装: $(tesseract --version 2>&1 | head -1)" else if command -v apt-get >/dev/null 2>&1; then apt-get update -qq apt-get install -y -qq tesseract-ocr tesseract-ocr-chi-sim tesseract-ocr-eng elif command -v yum >/dev/null 2>&1; then yum install -y tesseract tesseract-langpack-chi-sim 2>/dev/null || true elif command -v dnf >/dev/null 2>&1; then dnf install -y tesseract tesseract-langpack-chi-sim 2>/dev/null || true fi fi if ! command -v tesseract >/dev/null 2>&1; then echo "警告: 未安装 tesseract,iOS 拍照录入将无法识别照片" >&2 fi echo ">>> 创建数据库(若不存在)并建表" python - <<'PY' import pymysql from config import get_settings s = get_settings() conn = pymysql.connect( host=s.mysql_host, port=s.mysql_port, user=s.mysql_user, password=s.mysql_password, charset="utf8mb4", ) try: with conn.cursor() as cur: cur.execute( f"CREATE DATABASE IF NOT EXISTS `{s.mysql_database}` " "CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" ) conn.commit() print(f"database `{s.mysql_database}` ready") finally: conn.close() from database import engine, Base from sqlalchemy import text import models # noqa: F401 with engine.connect() as conn: conn.execute(text("SELECT 1")) Base.metadata.create_all(bind=engine) print("tables ready") PY echo ">>> 导入词书目录(沪版 + 商务)" cd "$ROOT/backend" source venv/bin/activate if [ -d "$ROOT/backend/data/books" ] && ls "$ROOT/backend/data/books"/*.json >/dev/null 2>&1; then python -m scripts.import_word_books else echo "未找到 data/books/*.json,跳过词书导入" fi echo ">>> 构建前端" cd "$ROOT/frontend" if ! command -v npm >/dev/null 2>&1; then echo "请先安装 Node.js/npm" exit 1 fi npm ci --silent npm run build echo ">>> Nginx 可读静态目录" chmod 755 /root /root/wordloop /root/wordloop/frontend /root/wordloop/frontend/dist 2>/dev/null || true echo ">>> 配置 Nginx + HTTPS (w.tkmind.cn)" if command -v nginx >/dev/null 2>&1; then cp "$ROOT/deploy/wordloop-locations.inc" /etc/nginx/conf.d/wordloop-locations.inc chmod +x "$ROOT/deploy/ssl-w.tkmind.cn.sh" bash "$ROOT/deploy/ssl-w.tkmind.cn.sh" systemctl enable nginx 2>/dev/null || true else echo "警告: 未安装 nginx,请手动安装后执行 deploy/ssl-w.tkmind.cn.sh" fi echo ">>> 配置 systemd 后端服务" cp "$ROOT/deploy/systemd/wordloop-backend-root.service" /etc/systemd/system/wordloop-backend.service systemctl daemon-reload systemctl enable wordloop-backend systemctl restart wordloop-backend echo ">>> 完成" systemctl --no-pager status wordloop-backend || true curl -sf http://127.0.0.1:18004/ >/dev/null && echo "API: ok" || echo "API: 请检查 journalctl -u wordloop-backend"