| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- #!/usr/bin/env bash
- set -e
- # ══════════════════════════════════════════════════════════════
- # 题库PLUS 服务端安装脚本
- # 支持 Arch Linux (pacman) / Debian-Ubuntu (apt)
- # ══════════════════════════════════════════════════════════════
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- NC='\033[0m'
- echo "========================================"
- echo " 题库PLUS 服务端安装"
- echo "========================================"
- echo ""
- # ── 检测 ──────────────────────────────────────────────────
- command_exists() { command -v "$1" &> /dev/null; }
- # Python >= 3.10
- if command_exists python3; then
- PY_VER=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
- echo -e "${GREEN}✓${NC} Python $PY_VER"
- else
- echo -e "${RED}✗${NC} Python 3.10+ 未安装"
- echo " 请先安装 Python: https://www.python.org/downloads/"
- exit 1
- fi
- # pandoc
- if command_exists pandoc; then
- echo -e "${GREEN}✓${NC} pandoc $(pandoc --version | head -1 | cut -d' ' -f2)"
- else
- echo -e "${YELLOW}⚠${NC} pandoc 未安装"
- if command_exists pacman; then
- echo " 安装: sudo pacman -S pandoc"
- elif command_exists apt; then
- echo " 安装: sudo apt install pandoc"
- else
- echo " 请手动安装 pandoc: https://pandoc.org/installing.html"
- fi
- echo " pandoc 用于 docx→HTML 渲染,如不安装则题目渲染功能不可用"
- fi
- # 中文字体
- FONT_OK=0
- for font in "宋体" "SimSun" "Noto Serif CJK SC" "WenQuanYi Micro Hei"; do
- if fc-list | grep -qi "$font"; then
- FONT_OK=1
- break
- fi
- done
- if [ "$FONT_OK" -eq 1 ]; then
- echo -e "${GREEN}✓${NC} 中文字体"
- else
- echo -e "${YELLOW}⚠${NC} 未检测到中文字体"
- if command_exists pacman; then
- echo " 安装: sudo pacman -S noto-fonts-cjk"
- elif command_exists apt; then
- echo " 安装: sudo apt install fonts-noto-cjk"
- fi
- fi
- echo ""
- # ── 虚拟环境 ──────────────────────────────────────────────
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- cd "$SCRIPT_DIR"
- if [ ! -d ".venv" ]; then
- echo "创建 Python 虚拟环境..."
- python3 -m venv .venv
- echo -e "${GREEN}✓${NC} 虚拟环境已创建"
- fi
- source .venv/bin/activate
- echo "安装 Python 依赖..."
- pip install -r requirements.txt -q
- echo -e "${GREEN}✓${NC} Python 依赖已安装"
- echo ""
- # ── 配置文件 ──────────────────────────────────────────────
- if [ ! -f "config.yaml" ]; then
- cp config.yaml.example config.yaml 2>/dev/null || true
- echo -e "${GREEN}✓${NC} config.yaml 已就绪"
- else
- echo -e "${GREEN}✓${NC} config.yaml 已存在"
- fi
- # ── 数据目录 ──────────────────────────────────────────────
- mkdir -p data/problems data/papers data/backups data/uploads
- echo -e "${GREEN}✓${NC} 数据目录已创建"
- # ── 知识点编码 ────────────────────────────────────────────
- if [ ! -f "src/knowledge_map.json" ]; then
- if [ -f "src/知识点树.md" ]; then
- echo ""
- echo "构建知识点编码..."
- .venv/bin/python tiku-server knowledge build
- echo -e "${GREEN}✓${NC} 知识点编码已构建"
- else
- echo -e "${YELLOW}⚠${NC} src/知识点树.md 不存在,跳过知识点构建"
- echo " 如需知识点编码,请从现有题库复制该文件后运行:"
- echo " ./tiku-server knowledge build"
- fi
- fi
- # ── Token ─────────────────────────────────────────────────
- TOKEN=$(grep -oP 'token:\s*"\K[^"]+' config.yaml 2>/dev/null || true)
- if [ -z "$TOKEN" ]; then
- echo ""
- echo "生成 API Token..."
- .venv/bin/python tiku-server token regerate 2>/dev/null || {
- # 如果 CLI token 命令不存在,手动生成
- TOKEN=$(python3 -c "import secrets; print(secrets.token_hex(16))")
- sed -i "s/token: \"\"/token: \"$TOKEN\"/" config.yaml 2>/dev/null || true
- echo -e "${GREEN}✓${NC} Token: $TOKEN"
- }
- fi
- echo ""
- echo "========================================"
- echo -e "${GREEN} 安装完成!${NC}"
- echo "========================================"
- echo ""
- echo "API Token: $(grep -oP 'token:\s*"\K[^"]+' config.yaml 2>/dev/null || echo '(查看 config.yaml)')"
- echo ""
- echo "启动命令:"
- echo " cd $SCRIPT_DIR && source .venv/bin/activate"
- echo " nohup ./tiku-server serve --restart > tiku.log 2>&1 &"
- echo ""
- echo " 或使用 systemd (下方创建)"
- echo ""
- echo "访问: http://localhost:8765"
- echo ""
- # ── systemd 服务(可选)───────────────────────────────────
- read -p "是否创建 systemd 服务实现开机自启?[y/N] " -r
- if [[ $REPLY =~ ^[Yy]$ ]]; then
- SERVICE_FILE="/etc/systemd/system/tiku-server.service"
- echo "[Unit]
- Description=题库PLUS 服务端
- After=network.target
- [Service]
- Type=simple
- User=$USER
- WorkingDirectory=$SCRIPT_DIR
- ExecStart=$SCRIPT_DIR/.venv/bin/python $SCRIPT_DIR/tiku-server serve
- Restart=on-failure
- RestartSec=5
- [Install]
- WantedBy=multi-user.target" | sudo tee "$SERVICE_FILE" > /dev/null
- sudo systemctl daemon-reload
- sudo systemctl enable tiku-server
- echo -e "${GREEN}✓${NC} systemd 服务已创建"
- echo " 启动: sudo systemctl start tiku-server"
- echo " 状态: sudo systemctl status tiku-server"
- fi
- echo ""
- # ── Flutter Web(可选)────────────────────────────────────
- if command_exists flutter; then
- echo ""
- read -p "检测到 Flutter SDK,是否构建 Web 客户端?[y/N] " -r
- if [[ $REPLY =~ ^[Yy]$ ]]; then
- FLUTTER_DIR="$SCRIPT_DIR/../tiku-client"
- if [ -d "$FLUTTER_DIR" ]; then
- cd "$FLUTTER_DIR"
- echo "构建 Flutter Web..."
- flutter build web --release
- cp -r build/web/* "$SCRIPT_DIR/web/"
- echo -e "${GREEN}✓${NC} Flutter Web 已部署"
- cd "$SCRIPT_DIR"
- else
- echo -e "${YELLOW}⚠${NC} Flutter 客户端目录不存在: $FLUTTER_DIR"
- fi
- fi
- fi
|