install.sh 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #!/usr/bin/env bash
  2. set -e
  3. # ══════════════════════════════════════════════════════════════
  4. # 题库PLUS 服务端安装脚本
  5. # 支持 Arch Linux (pacman) / Debian-Ubuntu (apt)
  6. # ══════════════════════════════════════════════════════════════
  7. RED='\033[0;31m'
  8. GREEN='\033[0;32m'
  9. YELLOW='\033[1;33m'
  10. NC='\033[0m'
  11. echo "========================================"
  12. echo " 题库PLUS 服务端安装"
  13. echo "========================================"
  14. echo ""
  15. # ── 检测 ──────────────────────────────────────────────────
  16. command_exists() { command -v "$1" &> /dev/null; }
  17. # Python >= 3.10
  18. if command_exists python3; then
  19. PY_VER=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
  20. echo -e "${GREEN}✓${NC} Python $PY_VER"
  21. else
  22. echo -e "${RED}✗${NC} Python 3.10+ 未安装"
  23. echo " 请先安装 Python: https://www.python.org/downloads/"
  24. exit 1
  25. fi
  26. # pandoc
  27. if command_exists pandoc; then
  28. echo -e "${GREEN}✓${NC} pandoc $(pandoc --version | head -1 | cut -d' ' -f2)"
  29. else
  30. echo -e "${YELLOW}⚠${NC} pandoc 未安装"
  31. if command_exists pacman; then
  32. echo " 安装: sudo pacman -S pandoc"
  33. elif command_exists apt; then
  34. echo " 安装: sudo apt install pandoc"
  35. else
  36. echo " 请手动安装 pandoc: https://pandoc.org/installing.html"
  37. fi
  38. echo " pandoc 用于 docx→HTML 渲染,如不安装则题目渲染功能不可用"
  39. fi
  40. # 中文字体
  41. FONT_OK=0
  42. for font in "宋体" "SimSun" "Noto Serif CJK SC" "WenQuanYi Micro Hei"; do
  43. if fc-list | grep -qi "$font"; then
  44. FONT_OK=1
  45. break
  46. fi
  47. done
  48. if [ "$FONT_OK" -eq 1 ]; then
  49. echo -e "${GREEN}✓${NC} 中文字体"
  50. else
  51. echo -e "${YELLOW}⚠${NC} 未检测到中文字体"
  52. if command_exists pacman; then
  53. echo " 安装: sudo pacman -S noto-fonts-cjk"
  54. elif command_exists apt; then
  55. echo " 安装: sudo apt install fonts-noto-cjk"
  56. fi
  57. fi
  58. echo ""
  59. # ── 虚拟环境 ──────────────────────────────────────────────
  60. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  61. cd "$SCRIPT_DIR"
  62. if [ ! -d ".venv" ]; then
  63. echo "创建 Python 虚拟环境..."
  64. python3 -m venv .venv
  65. echo -e "${GREEN}✓${NC} 虚拟环境已创建"
  66. fi
  67. source .venv/bin/activate
  68. echo "安装 Python 依赖..."
  69. pip install -r requirements.txt -q
  70. echo -e "${GREEN}✓${NC} Python 依赖已安装"
  71. echo ""
  72. # ── 配置文件 ──────────────────────────────────────────────
  73. if [ ! -f "config.yaml" ]; then
  74. cp config.yaml.example config.yaml 2>/dev/null || true
  75. echo -e "${GREEN}✓${NC} config.yaml 已就绪"
  76. else
  77. echo -e "${GREEN}✓${NC} config.yaml 已存在"
  78. fi
  79. # ── 数据目录 ──────────────────────────────────────────────
  80. mkdir -p data/problems data/papers data/backups data/uploads
  81. echo -e "${GREEN}✓${NC} 数据目录已创建"
  82. # ── 知识点编码 ────────────────────────────────────────────
  83. if [ ! -f "src/knowledge_map.json" ]; then
  84. if [ -f "src/知识点树.md" ]; then
  85. echo ""
  86. echo "构建知识点编码..."
  87. .venv/bin/python tiku-server knowledge build
  88. echo -e "${GREEN}✓${NC} 知识点编码已构建"
  89. else
  90. echo -e "${YELLOW}⚠${NC} src/知识点树.md 不存在,跳过知识点构建"
  91. echo " 如需知识点编码,请从现有题库复制该文件后运行:"
  92. echo " ./tiku-server knowledge build"
  93. fi
  94. fi
  95. # ── Token ─────────────────────────────────────────────────
  96. TOKEN=$(grep -oP 'token:\s*"\K[^"]+' config.yaml 2>/dev/null || true)
  97. if [ -z "$TOKEN" ]; then
  98. echo ""
  99. echo "生成 API Token..."
  100. .venv/bin/python tiku-server token regerate 2>/dev/null || {
  101. # 如果 CLI token 命令不存在,手动生成
  102. TOKEN=$(python3 -c "import secrets; print(secrets.token_hex(16))")
  103. sed -i "s/token: \"\"/token: \"$TOKEN\"/" config.yaml 2>/dev/null || true
  104. echo -e "${GREEN}✓${NC} Token: $TOKEN"
  105. }
  106. fi
  107. echo ""
  108. echo "========================================"
  109. echo -e "${GREEN} 安装完成!${NC}"
  110. echo "========================================"
  111. echo ""
  112. echo "API Token: $(grep -oP 'token:\s*"\K[^"]+' config.yaml 2>/dev/null || echo '(查看 config.yaml)')"
  113. echo ""
  114. echo "启动命令:"
  115. echo " cd $SCRIPT_DIR && source .venv/bin/activate"
  116. echo " nohup ./tiku-server serve --restart > tiku.log 2>&1 &"
  117. echo ""
  118. echo " 或使用 systemd (下方创建)"
  119. echo ""
  120. echo "访问: http://localhost:8765"
  121. echo ""
  122. # ── systemd 服务(可选)───────────────────────────────────
  123. read -p "是否创建 systemd 服务实现开机自启?[y/N] " -r
  124. if [[ $REPLY =~ ^[Yy]$ ]]; then
  125. SERVICE_FILE="/etc/systemd/system/tiku-server.service"
  126. echo "[Unit]
  127. Description=题库PLUS 服务端
  128. After=network.target
  129. [Service]
  130. Type=simple
  131. User=$USER
  132. WorkingDirectory=$SCRIPT_DIR
  133. ExecStart=$SCRIPT_DIR/.venv/bin/python $SCRIPT_DIR/tiku-server serve
  134. Restart=on-failure
  135. RestartSec=5
  136. [Install]
  137. WantedBy=multi-user.target" | sudo tee "$SERVICE_FILE" > /dev/null
  138. sudo systemctl daemon-reload
  139. sudo systemctl enable tiku-server
  140. echo -e "${GREEN}✓${NC} systemd 服务已创建"
  141. echo " 启动: sudo systemctl start tiku-server"
  142. echo " 状态: sudo systemctl status tiku-server"
  143. fi
  144. echo ""
  145. # ── Flutter Web(可选)────────────────────────────────────
  146. if command_exists flutter; then
  147. echo ""
  148. read -p "检测到 Flutter SDK,是否构建 Web 客户端?[y/N] " -r
  149. if [[ $REPLY =~ ^[Yy]$ ]]; then
  150. FLUTTER_DIR="$SCRIPT_DIR/../tiku-client"
  151. if [ -d "$FLUTTER_DIR" ]; then
  152. cd "$FLUTTER_DIR"
  153. echo "构建 Flutter Web..."
  154. flutter build web --release
  155. cp -r build/web/* "$SCRIPT_DIR/web/"
  156. echo -e "${GREEN}✓${NC} Flutter Web 已部署"
  157. cd "$SCRIPT_DIR"
  158. else
  159. echo -e "${YELLOW}⚠${NC} Flutter 客户端目录不存在: $FLUTTER_DIR"
  160. fi
  161. fi
  162. fi