From e8769642a166f2ab3fca781864cb8615854f86a9 Mon Sep 17 00:00:00 2001 From: Fly143 <80356009+Fly143@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:26:19 +0800 Subject: [PATCH] Android_Termux_install_MuMuAINovel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 改动内容 **源码更新方式** - 原:每次删除整个目录重新克隆(venv/.env/data 全部丢失) - 改:已有项目时 `git pull` 增量更新,保留 venv、.env、data 等本地文件 **网络加速** - GitHub 克隆:使用 `ghfast.top` 镜像加速 - Python 依赖:使用阿里云 PyPI 镜像 (`mirrors.aliyun.com`) **安装体验优化** - 所有耗时操作改为后台运行 + 转圈动画(⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏) - 成功显示 ✅,失败显示 ❌ + 最后 20 行错误日志 - npm/pip/vite 输出到日志文件,界面保持整洁 **依赖跳过逻辑** - 前端依赖:`node_modules` 已存在则跳过 `npm install` - Python 依赖:`venv` 已存在则跳过创建,pip 自动跳过已安装的包 - 数据库:迁移自动跳过已执行的版本 **兼容性补丁** - `memory_service.py`:import 改为 try/except,缺失 chromadb 时优雅降级 - API 文件(chapters/memories/outlines/projects/foreshadow):memory_service 导入改为 try/except - 自动修复 `.env` 中 `DEFAULT_MAX_TOKENS=***` 导致的数据库迁移失败 **移除不兼容依赖** - 移除 `psutil`(Android 不支持编译) - 移除 `chromadb` + `sentence-transformers`(依赖 PyTorch,无 Android 版本) - 向量记忆功能在 Termux 上不可用,其余功能正常 ### 运行效果 ``` [1/9] 检查环境 [✓] Termux 环境检测通过 [2/9] 安装系统依赖 ✅ 安装中 完成 [3/9] 拉取/更新项目源码 ✅ 拉取中 完成 [4/9] 应用 Termux 补丁 ✅ 修补中 完成 [5/9] 安装 Python 依赖 ✅ 安装中 完成 [6/9] 数据库迁移 ✅ 迁移中 完成 [7/9] 安装前端依赖 ✅ 安装中 完成 [8/9] 构建前端 ✅ 构建中 完成 [9/9] 创建启动脚本 [✓] 启动脚本已创建: ~/mumuainovel-start.sh ``` ### 使用方式 ```bash # 首次安装 curl -fsSL | bash # 启动 bash ~/mumuainovel-start.sh # 前台 bash ~/mumuainovel-start.sh --bg # 后台 ``` --- install-termux.sh | 263 ++++++++++++++++++++++++++++------------------ 1 file changed, 158 insertions(+), 105 deletions(-) diff --git a/install-termux.sh b/install-termux.sh index 3b7e521..2385352 100644 --- a/install-termux.sh +++ b/install-termux.sh @@ -1,26 +1,56 @@ #!/bin/bash +# ============================================================================= # MuMuAINovel Termux 一键安装脚本 -# 用法: curl -fsSL | bash -# 或者: bash install-termux.sh +# ============================================================================= +# + set -e -INSTALL_DIR="$HOME/MuMuAINovel" -DATA_DIR="$HOME/mumuainovel/data" -LOG_DIR="$HOME/mumuainovel/logs" -REPO="https://github.com/xiamuceer-j/MuMuAINovel.git" - -# 颜色 -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -CYAN='\033[0;36m' -NC='\033[0m' +# ── 路径配置 ────────────────────────────────────────────────────────────────── +INSTALL_DIR="$HOME/MuMuAINovel" # 项目安装目录 +DATA_DIR="$HOME/mumuainovel/data" # 数据库目录 +LOG_DIR="$HOME/mumuainovel/logs" # 日志目录 +REPO="https://ghfast.top/https://github.com/xiamuceer-j/MuMuAINovel.git" # GitHub 镜像 +# ── 输出函数 ────────────────────────────────────────────────────────────────── +GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${GREEN}[✓]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } err() { echo -e "${RED}[✗]${NC} $1"; } step() { echo -e "\n${CYAN}[$1/$2]${NC} $3"; } +# ── 转圈动画函数 ────────────────────────────────────────────────────────────── +# 用法: SPIN <后台进程PID> <提示文字> <日志文件路径> +# 原理: 检测进程是否存活,存活就显示旋转动画,结束后显示 ✅ 或 ❌ +SPIN() { + local PID=$1 MSG=$2 LOGF=$3 + echo -n " $MSG" + while kill -0 $PID 2>/dev/null; do + for s in ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏; do + echo -ne "\r $s $MSG" + sleep 0.3 + kill -0 $PID 2>/dev/null || break 2 + done + done + wait $PID + local RET=$? + if [ $RET -eq 0 ]; then + echo -e "\r ✅ $MSG 完成 " + else + echo -e "\r ❌ $MSG 失败 " + if [ -n "$LOGF" ] && [ -f "$LOGF" ]; then + echo -e "${RED}--- 错误日志 (最后20行) ---${NC}" + tail -20 "$LOGF" + echo -e "${RED}--- 日志结束 ---${NC}" + fi + exit 1 + fi +} + +# ── pip 镜像源(国内加速)────────────────────────────────────────────────────── +MIRROR="-i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com" + +# ============================================================================= echo "" echo -e "${CYAN}╔══════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ 📚 MuMuAINovel Termux 一键安装 ║${NC}" @@ -29,50 +59,72 @@ echo "" TOTAL=9 -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 1: 检查 Termux 环境 +# ============================================================================= step 1 $TOTAL "检查环境" -# ────────────────────────────────────────── if [ ! -d "/data/data/com.termux" ]; then err "未检测到 Termux 环境,请在 Termux 中运行" exit 1 fi info "Termux 环境检测通过" -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 2: 安装系统依赖 (python/nodejs/git) +# 说明: pkg install 自动跳过已安装的包,重复运行不会重新下载 +# ============================================================================= step 2 $TOTAL "安装系统依赖" -# ────────────────────────────────────────── -pkg install -y python nodejs git > /dev/null 2>&1 -info "python/nodejs/git 已安装" +LOG="$TMPDIR/pkg-install.log" +pkg install -y python nodejs git > "$LOG" 2>&1 & +SPIN $! "安装中" "$LOG" -# ────────────────────────────────────────── -step 3 $TOTAL "克隆项目" -# ────────────────────────────────────────── -if [ -d "$INSTALL_DIR" ]; then - warn "检测到旧安装,清理中..." - rm -rf "$INSTALL_DIR" +# ============================================================================= +# 步骤 3: 拉取/更新项目源码 +# 说明: 已有 .git 目录 → git pull 增量更新 (保留 venv/.env/data) +# 没有 → git clone 全量下载 +# ============================================================================= +step 3 $TOTAL "拉取/更新项目源码" +if [ -d "$INSTALL_DIR/.git" ]; then + LOG="$TMPDIR/git-pull.log" + ( + cd "$INSTALL_DIR" + git fetch origin + git reset --hard origin/main 2>/dev/null || git reset --hard origin/master + ) > "$LOG" 2>&1 & + SPIN $! "拉取中" "$LOG" +else + # 目录存在但不是 git 仓库,清理后重新克隆 + if [ -d "$INSTALL_DIR" ]; then + rm -rf "$INSTALL_DIR" + fi + LOG="$TMPDIR/git-clone.log" + git clone "$REPO" "$INSTALL_DIR" > "$LOG" 2>&1 & + SPIN $! "克隆中" "$LOG" fi -git clone "$REPO" "$INSTALL_DIR" -info "项目已就位: $INSTALL_DIR" BACKEND="$INSTALL_DIR/backend" FRONTEND="$INSTALL_DIR/frontend" -PYTHON="$BACKEND/venv/bin/python" -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 4: 应用 Termux 兼容补丁 +# 说明: Termux 不支持 chromadb/sentence-transformers,需要修补代码避免崩溃 +# 4a. memory_service.py — import 改为 try/except,缺失时优雅降级 +# 4b. API 文件 — memory_service 导入改为 try/except +# 4c. .env — 已有则跳过,新建则写入默认配置 +# ============================================================================= step 4 $TOTAL "应用 Termux 补丁" -# ────────────────────────────────────────── - -# 4a. Patch memory_service.py - 让 chromadb/sentence_transformers 缺失不崩溃 -MEM_FILE="$BACKEND/app/services/memory_service.py" -python3 << PYEOF +LOG="$TMPDIR/patch.log" +( +# ── 4a. 修补 memory_service.py ────────────────────────────────────────────── +python3 << 'PYEOF' import os f = os.path.expanduser("~/MuMuAINovel/backend/app/services/memory_service.py") with open(f) as fh: c = fh.read() -# 替换顶层 import +# 顶层 import 改为 try/except c = c.replace( - "import chromadb\nfrom sentence_transformers import SentenceTransformer", + "import chromadb\\nfrom sentence_transformers import SentenceTransformer", """try: import chromadb from sentence_transformers import SentenceTransformer @@ -83,36 +135,17 @@ except ImportError: SentenceTransformer = None""" ) -# 在 __init__ 的 _initialized 检查后加 MEMORY_AVAILABLE 保护 -old_init = """ def __init__(self): - \"\"\"初始化ChromaDB和Embedding模型\"\"\" - if self._initialized: - return - - try:""" -new_init = """ def __init__(self): - \"\"\"初始化ChromaDB和Embedding模型\"\"\" - if self._initialized: - return - - if not MEMORY_AVAILABLE: - self.client = None - self.model = None - self.collection = None - self._initialized = True - logger.warning("⚠️ 向量记忆功能不可用(缺少 chromadb/sentence-transformers)") - return - - try:""" +# __init__ 中加 MEMORY_AVAILABLE 检查,缺失时直接 return 不初始化 +old_init = ' def __init__(self):\n \\\"\\\"\\\"初始化ChromaDB和Embedding模型\\\"\\\"\\\"\n if self._initialized:\n return\n \n try:' +new_init = ' def __init__(self):\n \\\"\\\"\\\"初始化ChromaDB和Embedding模型\\\"\\\"\\\"\n if self._initialized:\n return\n\n if not MEMORY_AVAILABLE:\n self.client = None\n self.model = None\n self.collection = None\n self._initialized = True\n logger.warning("⚠️ 向量记忆功能不可用(缺少 chromadb/sentence-transformers)")\n return\n\n try:' c = c.replace(old_init, new_init, 1) with open(f, "w") as fh: fh.write(c) print(" ✅ memory_service.py 已修补") PYEOF -info "memory_service.py 已修补" -# 4b. Patch API files - memory_service 导入改为 try/except +# ── 4b. 修补 API 文件的 memory_service 导入 ────────────────────────────────── python3 << 'PYEOF' import os home = os.path.expanduser("~") @@ -135,10 +168,10 @@ for f in files: count += 1 print(f" ✅ API 文件已修补({count} 个)") PYEOF -info "API 文件已修补" -# 4c. 创建 .env +# ── 4c. 创建 .env 配置文件 (已有则跳过) ───────────────────────────────────── mkdir -p "$DATA_DIR" "$LOG_DIR" +if [ ! -f "$BACKEND/.env" ]; then cat > "$BACKEND/.env" << 'ENVEOF' # MuMuAINovel Termux 配置 APP_NAME=MuMuAINovel @@ -161,36 +194,43 @@ LOG_BACKUP_COUNT=5 CORS_ORIGINS=["http://localhost:8000","http://127.0.0.1:8000"] # ⚠️ 请填入你的 API Key -OPENAI_API_KEY=sk-your-key-here +OPENAI_API_KEY=*** OPENAI_BASE_URL=https://api.openai.com/v1 DEFAULT_AI_PROVIDER=openai DEFAULT_MODEL=gpt-4o-mini DEFAULT_TEMPERATURE=0.7 -DEFAULT_MAX_TOKENS=4096 +DEFAULT_MAX_TOKENS=*** # 本地登录账号 -LOCAL_AUTH_USERNAME=admin -LOCAL_AUTH_PASSWORD=admin123 -LOCAL_AUTH_DISPLAY_NAME=管理员 +LOCAL_AUTH_USERNAME=*** +LOCAL_AUTH_PASSWORD=*** +LOCAL_AUTH_DISPLAY_NAME=*** ENVEOF - -# 修正 DATABASE_URL 路径(替换占位符为实际路径) +# 替换占位符路径为实际 $HOME 路径 sed -i "s|/data/data/com.termux/files/home|$HOME|g" "$BACKEND/.env" sed -i "s|LOG_FILE_PATH=.*|LOG_FILE_PATH=$LOG_DIR/app.log|" "$BACKEND/.env" -info ".env 已创建(SQLite + admin/admin123)" +echo " ✅ .env 已创建" +else +echo " ✅ .env 已存在,跳过" +fi -# ────────────────────────────────────────── +# 修复 DEFAULT_MAX_TOKENS 占位符 (*** 不是有效整数,会导致数据库迁移失败) +sed -i "s|DEFAULT_MAX_TOKENS=\*\*\*|DEFAULT_MAX_TOKENS=4096|" "$BACKEND/.env" +) > "$LOG" 2>&1 & +SPIN $! "修补中" "$LOG" + +# ============================================================================= +# 步骤 5: 安装 Python 依赖 +# 说明: venv 不存在则创建;pip 自动跳过已安装的包,只安装新增的 +# ============================================================================= step 5 $TOTAL "安装 Python 依赖" -# ────────────────────────────────────────── if [ ! -d "$BACKEND/venv" ]; then python -m venv "$BACKEND/venv" fi PIP="$BACKEND/venv/bin/pip" -$PIP install --upgrade pip setuptools wheel -q - -# 精简依赖(跳过 Termux 不兼容的包) +# 写入精简依赖列表 (不含 Termux 不兼容的 psutil/chromadb/sentence-transformers) cat > "$BACKEND/requirements-lite.txt" << 'REQEOF' fastapi==0.121.0 uvicorn==0.38.0 @@ -209,45 +249,56 @@ mcp==1.22.0 greenlet>=3.0 REQEOF -$PIP install -r "$BACKEND/requirements-lite.txt" -q -info "Python 依赖已安装" +LOG="$TMPDIR/pip-install.log" +( + $PIP install --upgrade pip setuptools wheel -q $MIRROR + $PIP install -r "$BACKEND/requirements-lite.txt" $MIRROR +) > "$LOG" 2>&1 & +SPIN $! "安装中" "$LOG" -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 6: 数据库迁移 +# 说明: 首次安装创建所有表;重复运行自动跳过已执行的迁移 +# ============================================================================= step 6 $TOTAL "数据库迁移" -# ────────────────────────────────────────── export DATABASE_URL="sqlite+aiosqlite:///$DATA_DIR/ai_story.db" -cd "$BACKEND" -"$BACKEND/venv/bin/python" -m alembic -c alembic-sqlite.ini upgrade head || { - warn "alembic 迁移失败,尝试修复后重试..." - "$BACKEND/venv/bin/pip" install --force-reinstall alembic==1.14.0 -q - "$BACKEND/venv/bin/python" -m alembic -c alembic-sqlite.ini upgrade head || { - err "数据库迁移失败,请手动运行: cd $BACKEND && python -m alembic -c alembic-sqlite.ini upgrade head" - exit 1 - } -} -info "SQLite 数据库已初始化" +LOG="$TMPDIR/alembic.log" +( + cd "$BACKEND" + "$BACKEND/venv/bin/python" -m alembic -c alembic-sqlite.ini upgrade head +) > "$LOG" 2>&1 & +SPIN $! "迁移中" "$LOG" -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 7: 安装前端依赖 +# 说明: node_modules 已存在则跳过;首次运行 npm install +# ============================================================================= step 7 $TOTAL "安装前端依赖" -# ────────────────────────────────────────── cd "$FRONTEND" -npm install --include=dev -info "前端依赖已安装" +if [ -d "node_modules" ] && [ -f "node_modules/.package-lock.json" ]; then + info "前端依赖已安装,跳过" +else + LOG="$TMPDIR/npm-install.log" + npm install --include=dev --loglevel=silent > "$LOG" 2>&1 & + SPIN $! "安装中" "$LOG" +fi -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 8: 构建前端 +# 说明: 每次都重新构建,确保最新代码生效 +# ============================================================================= step 8 $TOTAL "构建前端" -# ────────────────────────────────────────── -# Termux 下 npm 的符号链接可能失效,用 node 直接调用 -node "$FRONTEND/node_modules/typescript/bin/tsc" -b 2>/dev/null || warn "TypeScript 有类型警告(已跳过)" -node "$FRONTEND/node_modules/vite/bin/vite.js" build || { - err "前端构建失败" - exit 1 -} -info "前端已构建 → $BACKEND/static/" +node "$FRONTEND/node_modules/typescript/bin/tsc" -b 2>/dev/null || true +LOG="$TMPDIR/vite-build.log" +node "$FRONTEND/node_modules/vite/bin/vite.js" build > "$LOG" 2>&1 & +SPIN $! "构建中" "$LOG" +grep -E "built in" "$LOG" | sed 's/^/ /' -# ────────────────────────────────────────── +# ============================================================================= +# 步骤 9: 创建启动脚本 +# 说明: 生成 ~/mumuainovel-start.sh,支持前台/后台运行 +# ============================================================================= step 9 $TOTAL "创建启动脚本" -# ────────────────────────────────────────── cat > "$HOME/mumuainovel-start.sh" << STARTEOF #!/bin/bash # MuMuAINovel Termux 启动脚本 @@ -282,7 +333,9 @@ STARTEOF chmod +x "$HOME/mumuainovel-start.sh" info "启动脚本已创建: ~/mumuainovel-start.sh" -# ────────────────────────────────────────── +# ============================================================================= +# 安装完成 +# ============================================================================= echo "" echo -e "${GREEN}╔══════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ 🎉 MuMuAINovel 安装完成! ║${NC}" @@ -295,7 +348,7 @@ echo -e "${GREEN}║ 后台运行: ║${NC}" echo -e "${GREEN}║ bash ~/mumuainovel-start.sh --bg ║${NC}" echo -e "${GREEN}║ ║${NC}" echo -e "${GREEN}║ 停止后台: ║${NC}" -echo -e "${GREEN}║ kill \\\$(cat ~/mumuainovel.pid) ║${NC}" +echo -e "${GREEN}║ kill \$(cat ~/mumuainovel.pid) ║${NC}" echo -e "${GREEN}║ ║${NC}" echo -e "${GREEN}║ 查看日志: ║${NC}" echo -e "${GREEN}║ tail -f ~/mumuainovel/logs/app.log ║${NC}"