diff --git a/CLAUDE.md b/CLAUDE.md
deleted file mode 100644
index 1b61f8ed..00000000
--- a/CLAUDE.md
+++ /dev/null
@@ -1,244 +0,0 @@
-# MaiMBot 开发文档
-
-## 📊 系统架构图
-
-```mermaid
-graph TD
- A[入口点] --> B[核心模块]
- A --> C[插件系统]
- B --> D[通用功能]
- C --> E[聊天系统]
- C --> F[记忆系统]
- C --> G[情绪系统]
- C --> H[意愿系统]
- C --> I[其他插件]
-
- %% 入口点
- A1[bot.py] --> A
- A2[run.py] --> A
- A3[webui.py] --> A
-
- %% 核心模块
- B1[src/common/logger.py] --> B
- B2[src/common/database.py] --> B
-
- %% 通用功能
- D1[日志系统] --> D
- D2[数据库连接] --> D
- D3[配置管理] --> D
-
- %% 聊天系统
- E1[消息处理] --> E
- E2[提示构建] --> E
- E3[LLM生成] --> E
- E4[关系管理] --> E
-
- %% 记忆系统
- F1[记忆图] --> F
- F2[记忆构建] --> F
- F3[记忆检索] --> F
- F4[记忆遗忘] --> F
-
- %% 情绪系统
- G1[情绪状态] --> G
- G2[情绪更新] --> G
- G3[情绪衰减] --> G
-
- %% 意愿系统
- H1[回复意愿] --> H
- H2[意愿模式] --> H
- H3[概率控制] --> H
-
- %% 其他插件
- I1[远程统计] --> I
- I2[配置重载] --> I
- I3[日程生成] --> I
-```
-
-## 📁 核心文件索引
-
-| 功能 | 文件路径 | 描述 |
-|------|----------|------|
-| **入口点** | `/bot.py` | 主入口,初始化环境和启动服务 |
-| | `/run.py` | 安装管理脚本,主要用于Windows |
-| | `/webui.py` | Gradio基础的配置UI |
-| **配置** | `/template.env` | 环境变量模板 |
-| | `/template/bot_config_template.toml` | 机器人配置模板 |
-| **核心基础** | `/src/common/database.py` | MongoDB连接管理 |
-| | `/src/common/logger.py` | 基于loguru的日志系统 |
-| **聊天系统** | `/src/plugins/chat/bot.py` | 消息处理核心逻辑 |
-| | `/src/plugins/chat/config.py` | 配置管理与验证 |
-| | `/src/plugins/chat/llm_generator.py` | LLM响应生成 |
-| | `/src/plugins/chat/prompt_builder.py` | LLM提示构建 |
-| **记忆系统** | `/src/plugins/memory_system/memory.py` | 图结构记忆实现 |
-| | `/src/plugins/memory_system/draw_memory.py` | 记忆可视化 |
-| **情绪系统** | `/src/plugins/moods/moods.py` | 情绪状态管理 |
-| **意愿系统** | `/src/plugins/willing/willing_manager.py` | 回复意愿管理 |
-| | `/src/plugins/willing/mode_classical.py` | 经典意愿模式 |
-| | `/src/plugins/willing/mode_dynamic.py` | 动态意愿模式 |
-| | `/src/plugins/willing/mode_custom.py` | 自定义意愿模式 |
-
-## 🔄 模块依赖关系
-
-```mermaid
-flowchart TD
- A[bot.py] --> B[src/common/logger.py]
- A --> C[src/plugins/chat/bot.py]
-
- C --> D[src/plugins/chat/config.py]
- C --> E[src/plugins/chat/llm_generator.py]
- C --> F[src/plugins/memory_system/memory.py]
- C --> G[src/plugins/moods/moods.py]
- C --> H[src/plugins/willing/willing_manager.py]
-
- E --> D
- E --> I[src/plugins/chat/prompt_builder.py]
- E --> J[src/plugins/models/utils_model.py]
-
- F --> B
- F --> D
- F --> J
-
- G --> D
-
- H --> B
- H --> D
- H --> K[src/plugins/willing/mode_classical.py]
- H --> L[src/plugins/willing/mode_dynamic.py]
- H --> M[src/plugins/willing/mode_custom.py]
-
- I --> B
- I --> F
- I --> G
-
- J --> B
-```
-
-## 🔄 消息处理流程
-
-```mermaid
-sequenceDiagram
- participant User
- participant ChatBot
- participant WillingManager
- participant Memory
- participant PromptBuilder
- participant LLMGenerator
- participant MoodManager
-
- User->>ChatBot: 发送消息
- ChatBot->>ChatBot: 消息预处理
- ChatBot->>Memory: 记忆激活
- Memory-->>ChatBot: 激活度
- ChatBot->>WillingManager: 更新回复意愿
- WillingManager-->>ChatBot: 回复决策
-
- alt 决定回复
- ChatBot->>PromptBuilder: 构建提示
- PromptBuilder->>Memory: 获取相关记忆
- Memory-->>PromptBuilder: 相关记忆
- PromptBuilder->>MoodManager: 获取情绪状态
- MoodManager-->>PromptBuilder: 情绪状态
- PromptBuilder-->>ChatBot: 完整提示
- ChatBot->>LLMGenerator: 生成回复
- LLMGenerator-->>ChatBot: AI回复
- ChatBot->>MoodManager: 更新情绪
- ChatBot->>User: 发送回复
- else 不回复
- ChatBot->>WillingManager: 更新未回复状态
- end
-```
-
-## 📋 类和功能清单
-
-### 🤖 聊天系统 (`src/plugins/chat/`)
-
-| 类/功能 | 文件 | 描述 |
-|--------|------|------|
-| `ChatBot` | `bot.py` | 消息处理主类 |
-| `ResponseGenerator` | `llm_generator.py` | 响应生成器 |
-| `PromptBuilder` | `prompt_builder.py` | 提示构建器 |
-| `Message`系列 | `message.py` | 消息表示类 |
-| `RelationshipManager` | `relationship_manager.py` | 用户关系管理 |
-| `EmojiManager` | `emoji_manager.py` | 表情符号管理 |
-
-### 🧠 记忆系统 (`src/plugins/memory_system/`)
-
-| 类/功能 | 文件 | 描述 |
-|--------|------|------|
-| `Memory_graph` | `memory.py` | 图结构记忆存储 |
-| `Hippocampus` | `memory.py` | 记忆管理主类 |
-| `memory_compress()` | `memory.py` | 记忆压缩函数 |
-| `get_relevant_memories()` | `memory.py` | 记忆检索函数 |
-| `operation_forget_topic()` | `memory.py` | 记忆遗忘函数 |
-
-### 😊 情绪系统 (`src/plugins/moods/`)
-
-| 类/功能 | 文件 | 描述 |
-|--------|------|------|
-| `MoodManager` | `moods.py` | 情绪管理器单例 |
-| `MoodState` | `moods.py` | 情绪状态数据类 |
-| `update_mood_from_emotion()` | `moods.py` | 情绪更新函数 |
-| `_apply_decay()` | `moods.py` | 情绪衰减函数 |
-
-### 🤔 意愿系统 (`src/plugins/willing/`)
-
-| 类/功能 | 文件 | 描述 |
-|--------|------|------|
-| `WillingManager` | `willing_manager.py` | 意愿管理工厂类 |
-| `ClassicalWillingManager` | `mode_classical.py` | 经典意愿模式 |
-| `DynamicWillingManager` | `mode_dynamic.py` | 动态意愿模式 |
-| `CustomWillingManager` | `mode_custom.py` | 自定义意愿模式 |
-
-## 🔧 常用命令
-
-- **运行机器人**: `python run.py` 或 `python bot.py`
-- **安装依赖**: `pip install --upgrade -r requirements.txt`
-- **Docker 部署**: `docker-compose up`
-- **代码检查**: `ruff check .`
-- **代码格式化**: `ruff format .`
-- **内存可视化**: `run_memory_vis.bat` 或 `python -m src.plugins.memory_system.draw_memory`
-- **推理过程可视化**: `script/run_thingking.bat`
-
-## 🔧 脚本工具
-
-- **运行MongoDB**: `script/run_db.bat` - 在端口27017启动MongoDB
-- **Windows完整启动**: `script/run_windows.bat` - 检查Python版本、设置虚拟环境、安装依赖并运行机器人
-- **快速启动**: `script/run_maimai.bat` - 设置UTF-8编码并执行"nb run"命令
-
-## 📝 代码风格
-
-- **Python版本**: 3.9+
-- **行长度限制**: 88字符
-- **命名规范**:
- - `snake_case` 用于函数和变量
- - `PascalCase` 用于类
- - `_prefix` 用于私有成员
-- **导入顺序**: 标准库 → 第三方库 → 本地模块
-- **异步编程**: 对I/O操作使用async/await
-- **日志记录**: 使用loguru进行一致的日志记录
-- **错误处理**: 使用带有具体异常的try/except
-- **文档**: 为类和公共函数编写docstrings
-
-## 📋 常见修改点
-
-### 配置修改
-- **机器人配置**: `/template/bot_config_template.toml`
-- **环境变量**: `/template.env`
-
-### 行为定制
-- **个性调整**: `src/plugins/chat/config.py` 中的 BotConfig 类
-- **回复意愿算法**: `src/plugins/willing/mode_classical.py`
-- **情绪反应模式**: `src/plugins/moods/moods.py`
-
-### 消息处理
-- **消息管道**: `src/plugins/chat/message.py`
-- **话题识别**: `src/plugins/chat/topic_identifier.py`
-
-### 记忆与学习
-- **记忆算法**: `src/plugins/memory_system/memory.py`
-- **手动记忆构建**: `src/plugins/memory_system/memory_manual_build.py`
-
-### LLM集成
-- **LLM提供商**: `src/plugins/chat/llm_generator.py`
-- **模型参数**: `template/bot_config_template.toml` 的 [model] 部分
\ No newline at end of file
diff --git a/MaiLauncher.bat b/MaiLauncher.bat
deleted file mode 100644
index 03e59b59..00000000
--- a/MaiLauncher.bat
+++ /dev/null
@@ -1,650 +0,0 @@
-@echo off
-@setlocal enabledelayedexpansion
-@chcp 936
-
-@REM 设置版本号
-set "VERSION=1.0"
-
-title 麦麦Bot控制台 v%VERSION%
-
-@REM 设置Python和Git环境变量
-set "_root=%~dp0"
-set "_root=%_root:~0,-1%"
-cd "%_root%"
-
-
-:search_python
-cls
-if exist "%_root%\python" (
- set "PYTHON_HOME=%_root%\python"
-) else if exist "%_root%\venv" (
- call "%_root%\venv\Scripts\activate.bat"
- set "PYTHON_HOME=%_root%\venv\Scripts"
-) else (
- echo 正在自动查找Python解释器...
-
- where python >nul 2>&1
- if %errorlevel% equ 0 (
- for /f "delims=" %%i in ('where python') do (
- echo %%i | findstr /i /c:"!LocalAppData!\Microsoft\WindowsApps\python.exe" >nul
- if errorlevel 1 (
- echo 找到Python解释器:%%i
- set "py_path=%%i"
- goto :validate_python
- )
- )
- )
- set "search_paths=%ProgramFiles%\Git*;!LocalAppData!\Programs\Python\Python*"
- for /d %%d in (!search_paths!) do (
- if exist "%%d\python.exe" (
- set "py_path=%%d\python.exe"
- goto :validate_python
- )
- )
- echo 没有找到Python解释器,要安装吗?
- set /p pyinstall_confirm="继续?(Y/n): "
- if /i "!pyinstall_confirm!"=="Y" (
- cls
- echo 正在安装Python...
- winget install --id Python.Python.3.13 -e --accept-package-agreements --accept-source-agreements
- if %errorlevel% neq 0 (
- echo 安装失败,请手动安装Python
- start https://www.python.org/downloads/
- exit /b
- )
- echo 安装完成,正在验证Python...
- goto search_python
-
- ) else (
- echo 取消安装Python,按任意键退出...
- pause >nul
- exit /b
- )
-
- echo 错误:未找到可用的Python解释器!
- exit /b 1
-
- :validate_python
- "!py_path!" --version >nul 2>&1
- if %errorlevel% neq 0 (
- echo 无效的Python解释器:%py_path%
- exit /b 1
- )
-
- :: 提取安装目录
- for %%i in ("%py_path%") do set "PYTHON_HOME=%%~dpi"
- set "PYTHON_HOME=%PYTHON_HOME:~0,-1%"
-)
-if not exist "%PYTHON_HOME%\python.exe" (
- echo Python路径验证失败:%PYTHON_HOME%
- echo 请检查Python安装路径中是否有python.exe文件
- exit /b 1
-)
-echo 成功设置Python路径:%PYTHON_HOME%
-
-
-
-:search_git
-cls
-if exist "%_root%\tools\git\bin" (
- set "GIT_HOME=%_root%\tools\git\bin"
-) else (
- echo 正在自动查找Git...
-
- where git >nul 2>&1
- if %errorlevel% equ 0 (
- for /f "delims=" %%i in ('where git') do (
- set "git_path=%%i"
- goto :validate_git
- )
- )
- echo 正在扫描常见安装路径...
- set "search_paths=!ProgramFiles!\Git\cmd"
- for /f "tokens=*" %%d in ("!search_paths!") do (
- if exist "%%d\git.exe" (
- set "git_path=%%d\git.exe"
- goto :validate_git
- )
- )
- echo 没有找到Git,要安装吗?
- set /p confirm="继续?(Y/N): "
- if /i "!confirm!"=="Y" (
- cls
- echo 正在安装Git...
- set "custom_url=https://ghfast.top/https://github.com/git-for-windows/git/releases/download/v2.48.1.windows.1/Git-2.48.1-64-bit.exe"
-
- set "download_path=%TEMP%\Git-Installer.exe"
-
- echo 正在下载Git安装包...
- curl -L -o "!download_path!" "!custom_url!"
-
- if exist "!download_path!" (
- echo 下载成功,开始安装Git...
- start /wait "" "!download_path!" /SILENT /NORESTART
- ) else (
- echo 下载失败,请手动安装Git
- start https://git-scm.com/download/win
- exit /b
- )
-
- del "!download_path!"
- echo 临时文件已清理。
-
- echo 安装完成,正在验证Git...
- where git >nul 2>&1
- if %errorlevel% equ 0 (
- for /f "delims=" %%i in ('where git') do (
- set "git_path=%%i"
- goto :validate_git
- )
- goto :search_git
-
- ) else (
- echo 安装完成,但未找到Git,请手动安装Git
- start https://git-scm.com/download/win
- exit /b
- )
-
- ) else (
- echo 取消安装Git,按任意键退出...
- pause >nul
- exit /b
- )
-
- echo 错误:未找到可用的Git!
- exit /b 1
-
- :validate_git
- "%git_path%" --version >nul 2>&1
- if %errorlevel% neq 0 (
- echo 无效的Git:%git_path%
- exit /b 1
- )
-
- :: 提取安装目录
- for %%i in ("%git_path%") do set "GIT_HOME=%%~dpi"
- set "GIT_HOME=%GIT_HOME:~0,-1%"
-)
-
-:search_mongodb
-cls
-sc query | findstr /i "MongoDB" >nul
-if !errorlevel! neq 0 (
- echo MongoDB服务未运行,是否尝试运行服务?
- set /p confirm="是否启动?(Y/N): "
- if /i "!confirm!"=="Y" (
- echo 正在尝试启动MongoDB服务...
- powershell -Command "Start-Process -Verb RunAs cmd -ArgumentList '/c net start MongoDB'"
- echo 正在等待MongoDB服务启动...
- echo 按下任意键跳过等待...
- timeout /t 30 >nul
- sc query | findstr /i "MongoDB" >nul
- if !errorlevel! neq 0 (
- echo MongoDB服务启动失败,可能是没有安装,要安装吗?
- set /p install_confirm="继续安装?(Y/N): "
- if /i "!install_confirm!"=="Y" (
- echo 正在安装MongoDB...
- winget install --id MongoDB.Server -e --accept-package-agreements --accept-source-agreements
- echo 安装完成,正在启动MongoDB服务...
- net start MongoDB
- if !errorlevel! neq 0 (
- echo 启动MongoDB服务失败,请手动启动
- exit /b
- ) else (
- echo MongoDB服务已成功启动
- )
- ) else (
- echo 取消安装MongoDB,按任意键退出...
- pause >nul
- exit /b
- )
- )
- ) else (
- echo "警告:MongoDB服务未运行,将导致MaiMBot无法访问数据库!"
- )
-) else (
- echo MongoDB服务已运行
-)
-
-@REM set "GIT_HOME=%_root%\tools\git\bin"
-set "PATH=%PYTHON_HOME%;%GIT_HOME%;%PATH%"
-
-:install_maim
-if not exist "!_root!\bot.py" (
- cls
- echo 你似乎没有安装麦麦Bot,要安装在当前目录吗?
- set /p confirm="继续?(Y/N): "
- if /i "!confirm!"=="Y" (
- echo 要使用Git代理下载吗?
- set /p proxy_confirm="继续?(Y/N): "
- if /i "!proxy_confirm!"=="Y" (
- echo 正在安装麦麦Bot...
- git clone https://ghfast.top/https://github.com/SengokuCola/MaiMBot
- ) else (
- echo 正在安装麦麦Bot...
- git clone https://github.com/SengokuCola/MaiMBot
- )
- xcopy /E /H /I MaiMBot . >nul 2>&1
- rmdir /s /q MaiMBot
- git checkout main-fix
-
- echo 安装完成,正在安装依赖...
- python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
- python -m pip install virtualenv
- python -m virtualenv venv
- call venv\Scripts\activate.bat
- python -m pip install -r requirements.txt
-
- echo 安装完成,要编辑配置文件吗?
- set /p edit_confirm="继续?(Y/N): "
- if /i "!edit_confirm!"=="Y" (
- goto config_menu
- ) else (
- echo 取消编辑配置文件,按任意键返回主菜单...
- )
- )
-)
-
-
-@REM git获取当前分支名并保存在变量里
-for /f "delims=" %%b in ('git symbolic-ref --short HEAD 2^>nul') do (
- set "BRANCH=%%b"
-)
-
-@REM 根据不同分支名给分支名字符串使用不同颜色
-echo 分支名: %BRANCH%
-if "!BRANCH!"=="main" (
- set "BRANCH_COLOR=[92m"
-) else if "!BRANCH!"=="main-fix" (
- set "BRANCH_COLOR=[91m"
-@REM ) else if "%BRANCH%"=="stable-dev" (
-@REM set "BRANCH_COLOR=[96m"
-) else (
- set "BRANCH_COLOR=[93m"
-)
-
-@REM endlocal & set "BRANCH_COLOR=%BRANCH_COLOR%"
-
-:check_is_venv
-echo 正在检查虚拟环境状态...
-if exist "%_root%\config\no_venv" (
- echo 检测到no_venv,跳过虚拟环境检查
- goto menu
-)
-
-:: 环境检测
-if defined VIRTUAL_ENV (
- goto menu
-)
-
-if exist "%_root%\config\conda_env" (
- set /p CONDA_ENV=<"%_root%\config\conda_env"
- call conda activate !CONDA_ENV! || (
- echo 激活失败,可能原因:
- echo 1. 环境不存在
- echo 2. conda配置异常
- pause
- goto conda_menu
- )
- echo 成功激活conda环境:!CONDA_ENV!
- goto menu
-)
-
-echo =====================================
-echo 虚拟环境检测警告:
-echo 当前使用系统Python路径:!PYTHON_HOME!
-echo 未检测到激活的虚拟环境!
-
-:env_interaction
-echo =====================================
-echo 请选择操作:
-echo 1 - 创建并激活Venv虚拟环境
-echo 2 - 创建/激活Conda虚拟环境
-echo 3 - 临时跳过本次检查
-echo 4 - 永久跳过虚拟环境检查
-set /p choice="请输入选项(1-4): "
-
-if "!choice!"=="4" (
- echo 要永久跳过虚拟环境检查吗?
- set /p no_venv_confirm="继续?(Y/N): ....."
- if /i "!no_venv_confirm!"=="Y" (
- echo 1 > "%_root%\config\no_venv"
- echo 已创建no_venv文件
- pause >nul
- goto menu
- ) else (
- echo 取消跳过虚拟环境检查,按任意键返回...
- pause >nul
- goto env_interaction
- )
-)
-
-if "!choice!"=="3" (
- echo 警告:使用系统环境可能导致依赖冲突!
- timeout /t 2 >nul
- goto menu
-)
-
-if "!choice!"=="2" goto handle_conda
-if "!choice!"=="1" goto handle_venv
-
-echo 无效的输入,请输入1-4之间的数字
-timeout /t 2 >nul
-goto env_interaction
-
-:handle_venv
-python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
-echo 正在初始化Venv环境...
-python -m pip install virtualenv || (
- echo 安装环境失败,错误码:!errorlevel!
- pause
- goto env_interaction
-)
-echo 创建虚拟环境到:venv
- python -m virtualenv venv || (
- echo 环境创建失败,错误码:!errorlevel!
- pause
- goto env_interaction
-)
-
-call venv\Scripts\activate.bat
-echo 已激活Venv环境
-echo 要安装依赖吗?
-set /p install_confirm="继续?(Y/N): "
-if /i "!install_confirm!"=="Y" (
- goto update_dependencies
-)
-goto menu
-
-:handle_conda
-where conda >nul 2>&1 || (
- echo 未检测到conda,可能原因:
- echo 1. 未安装Miniconda
- echo 2. conda配置异常
- timeout /t 10 >nul
- goto env_interaction
-)
-
-:conda_menu
-echo 请选择Conda操作:
-echo 1 - 创建新环境
-echo 2 - 激活已有环境
-echo 3 - 返回上级菜单
-set /p choice="请输入选项(1-3): "
-
-if "!choice!"=="3" goto env_interaction
-if "!choice!"=="2" goto activate_conda
-if "!choice!"=="1" goto create_conda
-
-echo 无效的输入,请输入1-3之间的数字
-timeout /t 2 >nul
-goto conda_menu
-
-:create_conda
-set /p "CONDA_ENV=请输入新环境名称:"
-if "!CONDA_ENV!"=="" (
- echo 环境名称不能为空!
- goto create_conda
-)
-conda create -n !CONDA_ENV! python=3.13 -y || (
- echo 环境创建失败,错误码:!errorlevel!
- timeout /t 10 >nul
- goto conda_menu
-)
-goto activate_conda
-
-:activate_conda
-set /p "CONDA_ENV=请输入要激活的环境名称:"
-call conda activate !CONDA_ENV! || (
- echo 激活失败,可能原因:
- echo 1. 环境不存在
- echo 2. conda配置异常
- pause
- goto conda_menu
-)
-echo 成功激活conda环境:!CONDA_ENV!
-echo !CONDA_ENV! > "%_root%\config\conda_env"
-echo 要安装依赖吗?
-set /p install_confirm="继续?(Y/N): "
-if /i "!install_confirm!"=="Y" (
- goto update_dependencies
-)
-:menu
-@chcp 936
-cls
-echo 麦麦Bot控制台 v%VERSION% 当前分支: %BRANCH_COLOR%%BRANCH%[0m
-echo 当前Python环境: [96m!PYTHON_HOME![0m
-echo ======================
-echo 1. 更新并启动麦麦Bot (默认)
-echo 2. 直接启动麦麦Bot
-echo 3. 启动麦麦配置界面
-echo 4. 打开麦麦神奇工具箱
-echo 5. 退出
-echo ======================
-
-set /p choice="请输入选项数字 (1-5)并按下回车以选择: "
-
-if "!choice!"=="" set choice=1
-
-if "!choice!"=="1" goto update_and_start
-if "!choice!"=="2" goto start_bot
-if "!choice!"=="3" goto config_menu
-if "!choice!"=="4" goto tools_menu
-if "!choice!"=="5" exit /b
-
-echo 无效的输入,请输入1-5之间的数字
-timeout /t 2 >nul
-goto menu
-
-:config_menu
-@chcp 936
-cls
-if not exist config/bot_config.toml (
- copy /Y "template\bot_config_template.toml" "config\bot_config.toml"
-
-)
-if not exist .env.prod (
- copy /Y "template.env" ".env.prod"
-)
-
-start python webui.py
-
-goto menu
-
-
-:tools_menu
-@chcp 936
-cls
-echo 麦麦时尚工具箱 当前分支: %BRANCH_COLOR%%BRANCH%[0m
-echo ======================
-echo 1. 更新依赖
-echo 2. 切换分支
-echo 3. 重置当前分支
-echo 4. 更新配置文件
-echo 5. 学习新的知识库
-echo 6. 打开知识库文件夹
-echo 7. 返回主菜单
-echo ======================
-
-set /p choice="请输入选项数字: "
-if "!choice!"=="1" goto update_dependencies
-if "!choice!"=="2" goto switch_branch
-if "!choice!"=="3" goto reset_branch
-if "!choice!"=="4" goto update_config
-if "!choice!"=="5" goto learn_new_knowledge
-if "!choice!"=="6" goto open_knowledge_folder
-if "!choice!"=="7" goto menu
-
-echo 无效的输入,请输入1-6之间的数字
-timeout /t 2 >nul
-goto tools_menu
-
-:update_dependencies
-cls
-echo 正在更新依赖...
-python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
-python.exe -m pip install -r requirements.txt
-
-echo 依赖更新完成,按任意键返回工具箱菜单...
-pause
-goto tools_menu
-
-:switch_branch
-cls
-echo 正在切换分支...
-echo 当前分支: %BRANCH%
-@REM echo 可用分支: main, debug, stable-dev
-echo 1. 切换到[92mmain[0m
-echo 2. 切换到[91mmain-fix[0m
-echo 请输入要切换到的分支:
-set /p branch_name="分支名: "
-if "%branch_name%"=="" set branch_name=main
-if "%branch_name%"=="main" (
- set "BRANCH_COLOR=[92m"
-) else if "%branch_name%"=="main-fix" (
- set "BRANCH_COLOR=[91m"
-@REM ) else if "%branch_name%"=="stable-dev" (
-@REM set "BRANCH_COLOR=[96m"
-) else if "%branch_name%"=="1" (
- set "BRANCH_COLOR=[92m"
- set "branch_name=main"
-) else if "%branch_name%"=="2" (
- set "BRANCH_COLOR=[91m"
- set "branch_name=main-fix"
-) else (
- echo 无效的分支名, 请重新输入
- timeout /t 2 >nul
- goto switch_branch
-)
-
-echo 正在切换到分支 %branch_name%...
-git checkout %branch_name%
-echo 分支切换完成,当前分支: %BRANCH_COLOR%%branch_name%[0m
-set "BRANCH=%branch_name%"
-echo 按任意键返回工具箱菜单...
-pause >nul
-goto tools_menu
-
-
-:reset_branch
-cls
-echo 正在重置当前分支...
-echo 当前分支: !BRANCH!
-echo 确认要重置当前分支吗?
-set /p confirm="继续?(Y/N): "
-if /i "!confirm!"=="Y" (
- echo 正在重置当前分支...
- git reset --hard !BRANCH!
- echo 分支重置完成,按任意键返回工具箱菜单...
-) else (
- echo 取消重置当前分支,按任意键返回工具箱菜单...
-)
-pause >nul
-goto tools_menu
-
-
-:update_config
-cls
-echo 正在更新配置文件...
-echo 请确保已备份重要数据,继续将修改当前配置文件。
-echo 继续请按Y,取消请按任意键...
-set /p confirm="继续?(Y/N): "
-if /i "!confirm!"=="Y" (
- echo 正在更新配置文件...
- python.exe config\auto_update.py
- echo 配置文件更新完成,按任意键返回工具箱菜单...
-) else (
- echo 取消更新配置文件,按任意键返回工具箱菜单...
-)
-pause >nul
-goto tools_menu
-
-:learn_new_knowledge
-cls
-echo 正在学习新的知识库...
-echo 请确保已备份重要数据,继续将修改当前知识库。
-echo 继续请按Y,取消请按任意键...
-set /p confirm="继续?(Y/N): "
-if /i "!confirm!"=="Y" (
- echo 正在学习新的知识库...
- python.exe src\plugins\zhishi\knowledge_library.py
- echo 学习完成,按任意键返回工具箱菜单...
-) else (
- echo 取消学习新的知识库,按任意键返回工具箱菜单...
-)
-pause >nul
-goto tools_menu
-
-:open_knowledge_folder
-cls
-echo 正在打开知识库文件夹...
-if exist data\raw_info (
- start explorer data\raw_info
-) else (
- echo 知识库文件夹不存在!
- echo 正在创建文件夹...
- mkdir data\raw_info
- timeout /t 2 >nul
-)
-goto tools_menu
-
-
-:update_and_start
-cls
-:retry_git_pull
-git pull > temp.log 2>&1
-findstr /C:"detected dubious ownership" temp.log >nul
-if %errorlevel% equ 0 (
- echo 检测到仓库权限问题,正在自动修复...
- git config --global --add safe.directory "%cd%"
- echo 已添加例外,正在重试git pull...
- del temp.log
- goto retry_git_pull
-)
-del temp.log
-echo 正在更新依赖...
-python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
-python -m pip install -r requirements.txt && cls
-
-echo 当前代理设置:
-echo HTTP_PROXY=%HTTP_PROXY%
-echo HTTPS_PROXY=%HTTPS_PROXY%
-
-echo Disable Proxy...
-set HTTP_PROXY=
-set HTTPS_PROXY=
-set no_proxy=0.0.0.0/32
-
-REM chcp 65001
-python bot.py
-echo.
-echo Bot已停止运行,按任意键返回主菜单...
-pause >nul
-goto menu
-
-:start_bot
-cls
-echo 正在更新依赖...
-python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
-python -m pip install -r requirements.txt && cls
-
-echo 当前代理设置:
-echo HTTP_PROXY=%HTTP_PROXY%
-echo HTTPS_PROXY=%HTTPS_PROXY%
-
-echo Disable Proxy...
-set HTTP_PROXY=
-set HTTPS_PROXY=
-set no_proxy=0.0.0.0/32
-
-REM chcp 65001
-python bot.py
-echo.
-echo Bot已停止运行,按任意键返回主菜单...
-pause >nul
-goto menu
-
-
-:open_dir
-start explorer "%cd%"
-goto menu
diff --git a/changelog.md b/changelogs/changelog.md
similarity index 100%
rename from changelog.md
rename to changelogs/changelog.md
diff --git a/changelog_config.md b/changelogs/changelog_config.md
similarity index 100%
rename from changelog_config.md
rename to changelogs/changelog_config.md
diff --git a/config/auto_update.py b/config/auto_update.py
deleted file mode 100644
index a0d87852..00000000
--- a/config/auto_update.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import os
-import shutil
-import tomlkit
-from pathlib import Path
-
-
-def update_config():
- # 获取根目录路径
- root_dir = Path(__file__).parent.parent
- template_dir = root_dir / "template"
- config_dir = root_dir / "config"
-
- # 定义文件路径
- template_path = template_dir / "bot_config_template.toml"
- old_config_path = config_dir / "bot_config.toml"
- new_config_path = config_dir / "bot_config.toml"
-
- # 读取旧配置文件
- old_config = {}
- if old_config_path.exists():
- with open(old_config_path, "r", encoding="utf-8") as f:
- old_config = tomlkit.load(f)
-
- # 删除旧的配置文件
- if old_config_path.exists():
- os.remove(old_config_path)
-
- # 复制模板文件到配置目录
- shutil.copy2(template_path, new_config_path)
-
- # 读取新配置文件
- with open(new_config_path, "r", encoding="utf-8") as f:
- new_config = tomlkit.load(f)
-
- # 递归更新配置
- def update_dict(target, source):
- for key, value in source.items():
- # 跳过version字段的更新
- if key == "version":
- continue
- if key in target:
- if isinstance(value, dict) and isinstance(target[key], (dict, tomlkit.items.Table)):
- update_dict(target[key], value)
- else:
- try:
- # 对数组类型进行特殊处理
- if isinstance(value, list):
- # 如果是空数组,确保它保持为空数组
- if not value:
- target[key] = tomlkit.array()
- else:
- target[key] = tomlkit.array(value)
- else:
- # 其他类型使用item方法创建新值
- target[key] = tomlkit.item(value)
- except (TypeError, ValueError):
- # 如果转换失败,直接赋值
- target[key] = value
-
- # 将旧配置的值更新到新配置中
- update_dict(new_config, old_config)
-
- # 保存更新后的配置(保留注释和格式)
- with open(new_config_path, "w", encoding="utf-8") as f:
- f.write(tomlkit.dumps(new_config))
-
-
-if __name__ == "__main__":
- update_config()
diff --git a/char_frequency.json b/depends-data/char_frequency.json
similarity index 100%
rename from char_frequency.json
rename to depends-data/char_frequency.json
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 82ca4e25..00000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-services:
- napcat:
- container_name: napcat
- environment:
- - TZ=Asia/Shanghai
- - NAPCAT_UID=${NAPCAT_UID}
- - NAPCAT_GID=${NAPCAT_GID} # 让 NapCat 获取当前用户 GID,UID,防止权限问题
- ports:
- - 6099:6099
- restart: unless-stopped
- volumes:
- - napcatQQ:/app/.config/QQ # 持久化 QQ 本体
- - napcatCONFIG:/app/napcat/config # 持久化 NapCat 配置文件
- - maimbotDATA:/MaiMBot/data # NapCat 和 NoneBot 共享此卷,否则发送图片会有问题
- image: mlikiowa/napcat-docker:latest
-
- mongodb:
- container_name: mongodb
- environment:
- - TZ=Asia/Shanghai
- # - MONGO_INITDB_ROOT_USERNAME=your_username
- # - MONGO_INITDB_ROOT_PASSWORD=your_password
- expose:
- - "27017"
- restart: unless-stopped
- volumes:
- - mongodb:/data/db # 持久化 MongoDB 数据库
- - mongodbCONFIG:/data/configdb # 持久化 MongoDB 配置文件
- image: mongo:latest
-
- maimbot:
- container_name: maimbot
- environment:
- - TZ=Asia/Shanghai
- expose:
- - "8080"
- restart: unless-stopped
- depends_on:
- - mongodb
- - napcat
- volumes:
- - napcatCONFIG:/MaiMBot/napcat # 自动根据配置中的 QQ 号创建 ws 反向客户端配置
- - ./bot_config.toml:/MaiMBot/config/bot_config.toml # Toml 配置文件映射
- - maimbotDATA:/MaiMBot/data # NapCat 和 NoneBot 共享此卷,否则发送图片会有问题
- - ./.env:/MaiMBot/.env # Toml 配置文件映射
- image: sengokucola/maimbot:latest
-
-volumes:
- maimbotCONFIG:
- maimbotDATA:
- napcatQQ:
- napcatCONFIG:
- mongodb:
- mongodbCONFIG:
-
-
diff --git a/docs/Jonathan R.md b/docs/Jonathan R.md
deleted file mode 100644
index 660caaee..00000000
--- a/docs/Jonathan R.md
+++ /dev/null
@@ -1,20 +0,0 @@
-Jonathan R. Wolpaw 在 “Memory in neuroscience: rhetoric versus reality.” 一文中提到,从神经科学的感觉运动假设出发,整个神经系统的功能是将经验与适当的行为联系起来,而不是单纯的信息存储。
-Jonathan R,Wolpaw. (2019). Memory in neuroscience: rhetoric versus reality.. Behavioral and cognitive neuroscience reviews(2).
-
-1. **单一过程理论**
- - 单一过程理论认为,识别记忆主要是基于熟悉性这一单一因素的影响。熟悉性是指对刺激的一种自动的、无意识的感知,它可以使我们在没有回忆起具体细节的情况下,判断一个刺激是否曾经出现过。
- - 例如,在一些实验中,研究者发现被试可以在没有回忆起具体学习情境的情况下,对曾经出现过的刺激做出正确的判断,这被认为是熟悉性在起作用1。
-2. **双重过程理论**
- - 双重过程理论则认为,识别记忆是基于两个过程:回忆和熟悉性。回忆是指对过去经验的有意识的回忆,它可以使我们回忆起具体的细节和情境;熟悉性则是一种自动的、无意识的感知。
- - 该理论认为,在识别记忆中,回忆和熟悉性共同作用,使我们能够判断一个刺激是否曾经出现过。例如,在 “记得 / 知道” 范式中,被试被要求判断他们对一个刺激的记忆是基于回忆还是熟悉性。研究发现,被试可以区分这两种不同的记忆过程,这为双重过程理论提供了支持1。
-
-
-
-1. **神经元节点与连接**:借鉴神经网络原理,将每个记忆单元视为一个神经元节点。节点之间通过连接相互关联,连接的强度代表记忆之间的关联程度。在形态学联想记忆中,具有相似形态特征的记忆节点连接强度较高。例如,苹果和橘子的记忆节点,由于在形状、都是水果等形态语义特征上相似,它们之间的连接强度大于苹果与汽车记忆节点间的连接强度。
-2. **记忆聚类与层次结构**:依据形态特征的相似性对记忆进行聚类,形成不同的记忆簇。每个记忆簇内部的记忆具有较高的相似性,而不同记忆簇之间的记忆相似性较低。同时,构建记忆的层次结构,高层次的记忆节点代表更抽象、概括的概念,低层次的记忆节点对应具体的实例。比如,“水果” 作为高层次记忆节点,连接着 “苹果”“橘子”“香蕉” 等低层次具体水果的记忆节点。
-3. **网络的动态更新**:随着新记忆的不断加入,记忆网络动态调整。新记忆节点根据其形态特征与现有网络中的节点建立连接,同时影响相关连接的强度。若新记忆与某个记忆簇的特征高度相似,则被纳入该记忆簇;若具有独特特征,则可能引发新的记忆簇的形成。例如,当系统学习到一种新的水果 “番石榴”,它会根据番石榴的形态、语义等特征,在记忆网络中找到与之最相似的区域(如水果记忆簇),并建立相应连接,同时调整周围节点连接强度以适应这一新记忆。
-
-
-
-- **相似性联想**:该理论认为,当两个或多个事物在形态上具有相似性时,它们在记忆中会形成关联。例如,梨和苹果在形状和都是水果这一属性上有相似性,所以当我们看到梨时,很容易通过形态学联想记忆联想到苹果。这种相似性联想有助于我们对新事物进行分类和理解,当遇到一个新的类似水果时,我们可以通过与已有的水果记忆进行相似性匹配,来推测它的一些特征。
-- **时空关联性联想**:除了相似性联想,MAM 还强调时空关联性联想。如果两个事物在时间或空间上经常同时出现,它们也会在记忆中形成关联。比如,每次在公园里看到花的时候,都能听到鸟儿的叫声,那么花和鸟儿叫声的形态特征(花的视觉形态和鸟叫的听觉形态)就会在记忆中形成关联,以后听到鸟叫可能就会联想到公园里的花。
\ No newline at end of file
diff --git a/docs/avatars/SengokuCola.jpg b/docs/avatars/SengokuCola.jpg
deleted file mode 100644
index deebf5ed..00000000
Binary files a/docs/avatars/SengokuCola.jpg and /dev/null differ
diff --git a/docs/avatars/default.png b/docs/avatars/default.png
deleted file mode 100644
index 5b561dac..00000000
Binary files a/docs/avatars/default.png and /dev/null differ
diff --git a/docs/avatars/run.bat b/docs/avatars/run.bat
deleted file mode 100644
index 6b9ca9f2..00000000
--- a/docs/avatars/run.bat
+++ /dev/null
@@ -1 +0,0 @@
-gource gource.log --user-image-dir docs/avatars/ --default-user-image docs/avatars/default.png
\ No newline at end of file
diff --git a/docs/doc1.md b/docs/doc1.md
deleted file mode 100644
index e8aa0f0d..00000000
--- a/docs/doc1.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# 📂 文件及功能介绍 (2025年更新)
-
-## 根目录
-
-- **README.md**: 项目的概述和使用说明。
-- **requirements.txt**: 项目所需的Python依赖包列表。
-- **bot.py**: 主启动文件,负责环境配置加载和NoneBot初始化。
-- **template.env**: 环境变量模板文件。
-- **pyproject.toml**: Python项目配置文件。
-- **docker-compose.yml** 和 **Dockerfile**: Docker配置文件,用于容器化部署。
-- **run_*.bat**: 各种启动脚本,包括数据库、maimai和thinking功能。
-
-## `src/` 目录结构
-
-- **`plugins/` 目录**: 存放不同功能模块的插件。
- - **chat/**: 处理聊天相关的功能,如消息发送和接收。
- - **memory_system/**: 处理机器人的记忆功能。
- - **knowledege/**: 知识库相关功能。
- - **models/**: 模型相关工具。
- - **schedule/**: 处理日程管理的功能。
-
-- **`gui/` 目录**: 存放图形用户界面相关的代码。
- - **reasoning_gui.py**: 负责推理界面的实现,提供用户交互。
-
-- **`common/` 目录**: 存放通用的工具和库。
- - **database.py**: 处理与数据库的交互,负责数据的存储和检索。
- - ****init**.py**: 初始化模块。
-
-## `config/` 目录
-
-- **bot_config_template.toml**: 机器人配置模板。
-- **auto_format.py**: 自动格式化工具。
-
-### `src/plugins/chat/` 目录文件详细介绍
-
-1. **`__init__.py`**:
- - 初始化 `chat` 模块,使其可以作为一个包被导入。
-
-2. **`bot.py`**:
- - 主要的聊天机器人逻辑实现,处理消息的接收、思考和回复。
- - 包含 `ChatBot` 类,负责消息处理流程控制。
- - 集成记忆系统和意愿管理。
-
-3. **`config.py`**:
- - 配置文件,定义了聊天机器人的各种参数和设置。
- - 包含 `BotConfig` 和全局配置对象 `global_config`。
-
-4. **`cq_code.py`**:
- - 处理 CQ 码(CoolQ 码),用于发送和接收特定格式的消息。
-
-5. **`emoji_manager.py`**:
- - 管理表情包的发送和接收,根据情感选择合适的表情。
- - 提供根据情绪获取表情的方法。
-
-6. **`llm_generator.py`**:
- - 生成基于大语言模型的回复,处理用户输入并生成相应的文本。
- - 通过 `ResponseGenerator` 类实现回复生成。
-
-7. **`message.py`**:
- - 定义消息的结构和处理逻辑,包含多种消息类型:
- - `Message`: 基础消息类
- - `MessageSet`: 消息集合
- - `Message_Sending`: 发送中的消息
- - `Message_Thinking`: 思考状态的消息
-
-8. **`message_sender.py`**:
- - 控制消息的发送逻辑,确保消息按照特定规则发送。
- - 包含 `message_manager` 对象,用于管理消息队列。
-
-9. **`prompt_builder.py`**:
- - 构建用于生成回复的提示,优化机器人的响应质量。
-
-10. **`relationship_manager.py`**:
- - 管理用户之间的关系,记录用户的互动和偏好。
- - 提供更新关系和关系值的方法。
-
-11. **`Segment_builder.py`**:
- - 构建消息片段的工具。
-
-12. **`storage.py`**:
- - 处理数据存储,负责将聊天记录和用户信息保存到数据库。
- - 实现 `MessageStorage` 类管理消息存储。
-
-13. **`thinking_idea.py`**:
- - 实现机器人的思考机制。
-
-14. **`topic_identifier.py`**:
- - 识别消息中的主题,帮助机器人理解用户的意图。
-
-15. **`utils.py`** 和 **`utils_*.py`** 系列文件:
- - 存放各种工具函数,提供辅助功能以支持其他模块。
- - 包括 `utils_cq.py`、`utils_image.py`、`utils_user.py` 等专门工具。
-
-16. **`willing_manager.py`**:
- - 管理机器人的回复意愿,动态调整回复概率。
- - 通过多种因素(如被提及、话题兴趣度)影响回复决策。
-
-### `src/plugins/memory_system/` 目录文件介绍
-
-1. **`memory.py`**:
- - 实现记忆管理核心功能,包含 `memory_graph` 对象。
- - 提供相关项目检索,支持多层次记忆关联。
-
-2. **`draw_memory.py`**:
- - 记忆可视化工具。
-
-3. **`memory_manual_build.py`**:
- - 手动构建记忆的工具。
-
-4. **`offline_llm.py`**:
- - 离线大语言模型处理功能。
-
-## 消息处理流程
-
-### 1. 消息接收与预处理
-
-- 通过 `ChatBot.handle_message()` 接收群消息。
-- 进行用户和群组的权限检查。
-- 更新用户关系信息。
-- 创建标准化的 `Message` 对象。
-- 对消息进行过滤和敏感词检测。
-
-### 2. 主题识别与决策
-
-- 使用 `topic_identifier` 识别消息主题。
-- 通过记忆系统检查对主题的兴趣度。
-- `willing_manager` 动态计算回复概率。
-- 根据概率决定是否回复消息。
-
-### 3. 回复生成与发送
-
-- 如需回复,首先创建 `Message_Thinking` 对象表示思考状态。
-- 调用 `ResponseGenerator.generate_response()` 生成回复内容和情感状态。
-- 删除思考消息,创建 `MessageSet` 准备发送回复。
-- 计算模拟打字时间,设置消息发送时间点。
-- 可能附加情感相关的表情包。
-- 通过 `message_manager` 将消息加入发送队列。
-
-### 消息发送控制系统
-
-`message_sender.py` 中实现了消息发送控制系统,采用三层结构:
-
-1. **消息管理**:
- - 支持单条消息和消息集合的发送。
- - 处理思考状态消息,控制思考时间。
- - 模拟人类打字速度,添加自然发送延迟。
-
-2. **情感表达**:
- - 根据生成回复的情感状态选择匹配的表情包。
- - 通过 `emoji_manager` 管理表情资源。
-
-3. **记忆交互**:
- - 通过 `memory_graph` 检索相关记忆。
- - 根据记忆内容影响回复意愿和内容。
-
-## 系统特色功能
-
-1. **智能回复意愿系统**:
- - 动态调整回复概率,模拟真实人类交流特性。
- - 考虑多种因素:被提及、话题兴趣度、用户关系等。
-
-2. **记忆系统集成**:
- - 支持多层次记忆关联和检索。
- - 影响机器人的兴趣和回复内容。
-
-3. **自然交流模拟**:
- - 模拟思考和打字过程,添加合理延迟。
- - 情感表达与表情包结合。
-
-4. **多环境配置支持**:
- - 支持开发环境和生产环境的不同配置。
- - 通过环境变量和配置文件灵活管理设置。
-
-5. **Docker部署支持**:
- - 提供容器化部署方案,简化安装和运行。
diff --git a/docs/docker_deploy.md b/docs/docker_deploy.md
deleted file mode 100644
index 67c787b1..00000000
--- a/docs/docker_deploy.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# 🐳 Docker 部署指南
-
-## 部署步骤 (不一定是最新)
-
-**"更新镜像与容器"部分在本文档 [Part 6](#6-更新镜像与容器)**
-
-### 0. 前提说明
-
-**本文假设读者已具备一定的 Docker 基础知识。若您对 Docker 不熟悉,建议先参考相关教程或文档进行学习,或选择使用 [📦Linux手动部署指南](./manual_deploy_linux.md) 或 [📦Windows手动部署指南](./manual_deploy_windows.md) 。**
-
-
-### 1. 获取Docker配置文件
-
-- 建议先单独创建好一个文件夹并进入,作为工作目录
-
-```bash
-wget https://raw.githubusercontent.com/SengokuCola/MaiMBot/main/docker-compose.yml -O docker-compose.yml
-```
-
-- 若需要启用MongoDB数据库的用户名和密码,可进入docker-compose.yml,取消MongoDB处的注释并修改变量旁 `=` 后方的值为你的用户名和密码\
-修改后请注意在之后配置 `.env` 文件时指定MongoDB数据库的用户名密码
-
-### 2. 启动服务
-
-- **!!! 请在第一次启动前确保当前工作目录下 `.env` 与 `bot_config.toml` 文件存在 !!!**\
-由于Docker文件映射行为的特殊性,若宿主机的映射路径不存在,可能导致意外的目录创建,而不会创建文件,由于此处需要文件映射到文件,需提前确保文件存在且路径正确,可使用如下命令:
-
-```bash
-touch .env
-touch bot_config.toml
-```
-
-- 启动Docker容器:
-
-```bash
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker compose up -d
-# 旧版Docker中可能找不到docker compose,请使用docker-compose工具替代
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker-compose up -d
-```
-
-
-### 3. 修改配置并重启Docker
-
-- 请前往 [🎀 新手配置指南](./installation_cute.md) 或 [⚙️ 标准配置指南](./installation_standard.md) 完成`.env`与`bot_config.toml`配置文件的编写\
-**需要注意`.env`中HOST处IP的填写,Docker中部署和系统中直接安装的配置会有所不同**
-
-- 重启Docker容器:
-
-```bash
-docker restart maimbot # 若修改过容器名称则替换maimbot为你自定的名称
-```
-
-- 下方命令可以但不推荐,只是同时重启NapCat、MongoDB、MaiMBot三个服务
-
-```bash
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker compose restart
-# 旧版Docker中可能找不到docker compose,请使用docker-compose工具替代
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker-compose restart
-```
-
-### 4. 登入NapCat管理页添加反向WebSocket
-
-- 在浏览器地址栏输入 `http://<宿主机IP>:6099/` 进入NapCat的管理Web页,添加一个Websocket客户端
-
-> 网络配置 -> 新建 -> Websocket客户端
-
-- Websocket客户端的名称自定,URL栏填入 `ws://maimbot:8080/onebot/v11/ws`,启用并保存即可\
-(若修改过容器名称则替换maimbot为你自定的名称)
-
-### 5. 部署完成,愉快地和麦麦对话吧!
-
-
-### 6. 更新镜像与容器
-
-- 拉取最新镜像
-
-```bash
-docker-compose pull
-```
-
-- 执行启动容器指令,该指令会自动重建镜像有更新的容器并启动
-
-```bash
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker compose up -d
-# 旧版Docker中可能找不到docker compose,请使用docker-compose工具替代
-NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker-compose up -d
-```
-
-## ⚠️ 注意事项
-
-- 目前部署方案仍在测试中,可能存在未知问题
-- 配置文件中的API密钥请妥善保管,不要泄露
-- 建议先在测试环境中运行,确认无误后再部署到生产环境
diff --git a/docs/fast_q_a.md b/docs/fast_q_a.md
deleted file mode 100644
index 4d03dff4..00000000
--- a/docs/fast_q_a.md
+++ /dev/null
@@ -1,289 +0,0 @@
-## 快速更新Q&A❓
-
-- 这个文件用来记录一些常见的新手问题。
-
-### 完整安装教程
-
-[MaiMbot简易配置教程](https://www.bilibili.com/video/BV1zsQ5YCEE6)
-
-### Api相关问题
-
-- 为什么显示:"缺失必要的API KEY" ❓
-
-
-
->你需要在 [Silicon Flow Api](https://cloud.siliconflow.cn/account/ak) 网站上注册一个账号,然后点击这个链接打开API KEY获取页面。
->
->点击 "新建API密钥" 按钮新建一个给MaiMBot使用的API KEY。不要忘了点击复制。
->
->之后打开MaiMBot在你电脑上的文件根目录,使用记事本或者其他文本编辑器打开 [.env](../.env)
->这个文件。把你刚才复制的API KEY填入到 `SILICONFLOW_KEY=` 这个等号的右边。
->
->在默认情况下,MaiMBot使用的默认Api都是硅基流动的。
-
----
-
-- 我想使用硅基流动之外的Api网站,我应该怎么做 ❓
-
->你需要使用记事本或者其他文本编辑器打开config目录下的 [bot_config.toml](../config/bot_config.toml)
->
->然后修改其中的 `provider = ` 字段。同时不要忘记模仿 [.env](../.env) 文件的写法添加 Api Key 和 Base URL。
->
->举个例子,如果你写了 `provider = "ABC"`,那你需要相应的在 [.env](../.env) 文件里添加形如 `ABC_BASE_URL = https://api.abc.com/v1` 和 `ABC_KEY = sk-1145141919810` 的字段。
->
->**如果你对AI模型没有较深的了解,修改识图模型和嵌入模型的provider字段可能会产生bug,因为你从Api网站调用了一个并不存在的模型**
->
->这个时候,你需要把字段的值改回 `provider = "SILICONFLOW"` 以此解决此问题。
-
-### MongoDB相关问题
-
-- 我应该怎么清空bot内存储的表情包 ❓
->需要先安装`MongoDB Compass`,[下载链接](https://www.mongodb.com/try/download/compass),软件支持`macOS、Windows、Ubuntu、Redhat`系统
->以Windows为例,保持如图所示选项,点击`Download`即可,如果是其他系统,请在`Platform`中自行选择:
->
-
->打开你的MongoDB Compass软件,你会在左上角看到这样的一个界面:
->
->
->
->
->
->点击 "CONNECT" 之后,点击展开 MegBot 标签栏
->
->
->
->
->
->点进 "emoji" 再点击 "DELETE" 删掉所有条目,如图所示
->
->
->
->
->
->你可以用类似的方式手动清空MaiMBot的所有服务器数据。
->
->MaiMBot的所有图片均储存在 [data](../data) 文件夹内,按类型分为 [emoji](../data/emoji) 和 [image](../data/image)
->
->在删除服务器数据时不要忘记清空这些图片。
-
----
-
-- 为什么我连接不上MongoDB服务器 ❓
-
->这个问题比较复杂,但是你可以按照下面的步骤检查,看看具体是什么问题
-
-
->#### Windows
-> 1. 检查有没有把 mongod.exe 所在的目录添加到 path。 具体可参照
->
-> [CSDN-windows10设置环境变量Path详细步骤](https://blog.csdn.net/flame_007/article/details/106401215)
->
-> **需要往path里填入的是 exe 所在的完整目录!不带 exe 本体**
->
->
->
-> 2. 环境变量添加完之后,可以按下`WIN+R`,在弹出的小框中输入`powershell`,回车,进入到powershell界面后,输入`mongod --version`如果有输出信息,就说明你的环境变量添加成功了。
-> 接下来,直接输入`mongod --port 27017`命令(`--port`指定了端口,方便在可视化界面中连接),如果连不上,很大可能会出现
->```shell
->"error":"NonExistentPath: Data directory \\data\\db not found. Create the missing directory or specify another path using (1) the --dbpath command line option, or (2) by adding the 'storage.dbPath' option in the configuration file."
->```
->这是因为你的C盘下没有`data\db`文件夹,mongo不知道将数据库文件存放在哪,不过不建议在C盘中添加,因为这样你的C盘负担会很大,可以通过`mongod --dbpath=PATH --port 27017`来执行,将`PATH`替换成你的自定义文件夹,但是不要放在mongodb的bin文件夹下!例如,你可以在D盘中创建一个mongodata文件夹,然后命令这样写
->```shell
->mongod --dbpath=D:\mongodata --port 27017
->```
->
->如果还是不行,有可能是因为你的27017端口被占用了
->通过命令
->```shell
-> netstat -ano | findstr :27017
->```
->可以查看当前端口是否被占用,如果有输出,其一般的格式是这样的
->```shell
-> TCP 127.0.0.1:27017 0.0.0.0:0 LISTENING 5764
-> TCP 127.0.0.1:27017 127.0.0.1:63387 ESTABLISHED 5764
-> TCP 127.0.0.1:27017 127.0.0.1:63388 ESTABLISHED 5764
-> TCP 127.0.0.1:27017 127.0.0.1:63389 ESTABLISHED 5764
->```
->最后那个数字就是PID,通过以下命令查看是哪些进程正在占用
->```shell
->tasklist /FI "PID eq 5764"
->```
->如果是无关紧要的进程,可以通过`taskkill`命令关闭掉它,例如`Taskkill /F /PID 5764`
->
->如果你对命令行实在不熟悉,可以通过`Ctrl+Shift+Esc`调出任务管理器,在搜索框中输入PID,也可以找到相应的进程。
->
->如果你害怕关掉重要进程,可以修改`.env.dev`中的`MONGODB_PORT`为其它值,并在启动时同时修改`--port`参数为一样的值
->```ini
->MONGODB_HOST=127.0.0.1
->MONGODB_PORT=27017 #修改这里
->DATABASE_NAME=MegBot
->```
-
-
-Linux(点击展开)
-
-#### **1. 检查 MongoDB 服务是否运行**
-- **命令**:
- ```bash
- systemctl status mongod # 检查服务状态(Ubuntu/Debian/CentOS 7+)
- service mongod status # 旧版系统(如 CentOS 6)
- ```
-- **可能结果**:
- - 如果显示 `active (running)`,服务已启动。
- - 如果未运行,启动服务:
- ```bash
- sudo systemctl start mongod # 启动服务
- sudo systemctl enable mongod # 设置开机自启
- ```
-
----
-
-#### **2. 检查 MongoDB 端口监听**
-MongoDB 默认使用 **27017** 端口。
-- **检查端口是否被监听**:
- ```bash
- sudo ss -tulnp | grep 27017
- 或
- sudo netstat -tulnp | grep 27017
- ```
-- **预期结果**:
- ```bash
- tcp LISTEN 0 128 0.0.0.0:27017 0.0.0.0:* users:(("mongod",pid=123,fd=11))
- ```
- - 如果无输出,说明 MongoDB 未监听端口。
-
-
----
-#### **3. 检查防火墙设置**
-- **Ubuntu/Debian(UFW 防火墙)**:
- ```bash
- sudo ufw status # 查看防火墙状态
- sudo ufw allow 27017/tcp # 开放 27017 端口
- sudo ufw reload # 重新加载规则
- ```
-- **CentOS/RHEL(firewalld)**:
- ```bash
- sudo firewall-cmd --list-ports # 查看已开放端口
- sudo firewall-cmd --add-port=27017/tcp --permanent # 永久开放端口
- sudo firewall-cmd --reload # 重新加载
- ```
-- **云服务器用户注意**:检查云平台安全组规则,确保放行 27017 端口。
-
----
-
-#### **4. 检查端口占用**
-如果 MongoDB 服务无法监听端口,可能是其他进程占用了 `27017` 端口。
-- **检查端口占用进程**:
- ```bash
- sudo lsof -i :27017 # 查看占用 27017 端口的进程
- 或
- sudo ss -ltnp 'sport = :27017' # 使用 ss 过滤端口
- ```
-- **结果示例**:
- ```bash
- COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
- java 1234 root 12u IPv4 123456 0t0 TCP *:27017 (LISTEN)
- ```
- - 输出会显示占用端口的 **进程名** 和 **PID**(此处 `PID=1234`)。
-
-- **解决方案**:
- 1. **终止占用进程**(谨慎操作!确保进程非关键):
- ```bash
- sudo kill 1234 # 正常终止进程
- sudo kill -9 1234 # 强制终止(若正常终止无效)
- ```
- 2. **修改端口**:
- 编辑麦麦目录里的`.env.dev`文件,修改端口号:
- ```ini
- MONGODB_HOST=127.0.0.1
- MONGODB_PORT=27017 #修改这里
- DATABASE_NAME=MegBot
- ```
-
-
-##### **注意事项**
-- 终止进程前,务必确认该进程非系统关键服务(如未知进程占用,建议先排查来源),如果你不知道这个进程是否关键,请更改端口使用。
-
-
-
-
-macOS(点击展开)
-
-### **1. 检查 MongoDB 服务状态**
-**问题原因**:MongoDB 服务未启动
-**操作步骤**:
-```bash
-# 查看 MongoDB 是否正在运行(Homebrew 安装的默认服务名)
-brew services list | grep mongodb
-
-# 如果状态为 "stopped" 或 "error",手动启动
-brew services start mongodb-community@8.0
-```
-✅ **预期结果**:输出显示 `started` 或 `running`
-❌ **失败处理**:
-- 若报错 `unrecognized service`,可能未正确安装 MongoDB,建议[重新安装](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#install-mongodb-community-edition)。
-
----
-
-### **2. 检查端口是否被占用**
-**问题原因**:其他程序占用了 MongoDB 的默认端口(`27017`),导致服务无法启动或连接
-**操作步骤**:
-```bash
-# 检查 27017 端口占用情况(需 sudo 权限查看完整信息)
-sudo lsof -i :27017
-
-# 或使用 netstat 快速检测
-netstat -an | grep 27017
-```
-✅ **预期结果**:
-- 若无 MongoDB 运行,应无输出
-- 若 MongoDB 已启动,应显示 `mongod` 进程
-
-❌ **发现端口被占用**:
-#### **解决方案1:终止占用进程**
-1. 从 `lsof` 输出中找到占用端口的 **PID**(进程号)
-2. 强制终止该进程(谨慎操作!确保进程非关键):
- ```bash
- kill -9 PID # 替换 PID 为实际数字(例如 kill -9 12345)
- ```
-3. 重新启动 MongoDB 服务:
- ```bash
- brew services start mongodb-community@8.0
- ```
-
-#### **解决方案2:修改端口**
- 编辑麦麦目录里的`.env.dev`文件,修改端口号:
- ```ini
- MONGODB_HOST=127.0.0.1
- MONGODB_PORT=27017 #修改这里
- DATABASE_NAME=MegBot
- ```
-
----
-
-### **3. 检查防火墙设置**
-**问题原因**:macOS 防火墙阻止连接
-**操作步骤**:
-1. 打开 **系统设置 > 隐私与安全性 > 防火墙**
-2. 临时关闭防火墙测试连接
-3. 若需长期开放,添加 MongoDB 到防火墙允许列表(通过终端或 GUI)。
-
-
----
-### **4. 重置 MongoDB 环境**
-***仅在以上步骤都无效时使用***
-**适用场景**:配置混乱导致无法修复
-```bash
-# 停止服务并删除数据
-brew services stop mongodb-community@8.0
-rm -rf /usr/local/var/mongodb
-
-# 重新初始化(确保目录权限)
-sudo mkdir -p /usr/local/var/mongodb
-sudo chown -R $(whoami) /usr/local/var/mongodb
-
-# 重新启动
-brew services start mongodb-community@8.0
-```
-
-
\ No newline at end of file
diff --git a/docs/installation_cute.md b/docs/installation_cute.md
deleted file mode 100644
index b20954a7..00000000
--- a/docs/installation_cute.md
+++ /dev/null
@@ -1,226 +0,0 @@
-# 🔧 配置指南 喵~
-
-## 👋 你好呀
-
-让咱来告诉你我们要做什么喵:
-
-1. 我们要一起设置一个可爱的AI机器人
-2. 这个机器人可以在QQ上陪你聊天玩耍哦
-3. 需要设置两个文件才能让机器人工作呢
-
-## 📝 需要设置的文件喵
-
-要设置这两个文件才能让机器人跑起来哦:
-
-1. `.env` - 这个文件告诉机器人要用哪些AI服务呢
-2. `bot_config.toml` - 这个文件教机器人怎么和你聊天喵
-
-## 🔑 密钥和域名的对应关系
-
-想象一下,你要进入一个游乐园,需要:
-
-1. 知道游乐园的地址(这就是域名 base_url)
-2. 有入场的门票(这就是密钥 key)
-
-在 `.env` 文件里,我们定义了三个游乐园的地址和门票喵:
-
-```ini
-# 硅基流动游乐园
-SILICONFLOW_KEY=your_key # 硅基流动的门票
-SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1/ # 硅基流动的地址
-
-# DeepSeek游乐园
-DEEP_SEEK_KEY=your_key # DeepSeek的门票
-DEEP_SEEK_BASE_URL=https://api.deepseek.com/v1 # DeepSeek的地址
-
-# ChatAnyWhere游乐园
-CHAT_ANY_WHERE_KEY=your_key # ChatAnyWhere的门票
-CHAT_ANY_WHERE_BASE_URL=https://api.chatanywhere.tech/v1 # ChatAnyWhere的地址
-```
-
-然后在 `bot_config.toml` 里,机器人会用这些门票和地址去游乐园玩耍:
-
-```toml
-[model.llm_reasoning]
-name = "Pro/deepseek-ai/DeepSeek-R1"
-provider = "SILICONFLOW" # 告诉机器人:去硅基流动游乐园玩,机器人会自动用硅基流动的门票进去
-
-[model.llm_normal]
-name = "Pro/deepseek-ai/DeepSeek-V3"
-provider = "SILICONFLOW" # 还是去硅基流动游乐园
-```
-
-### 🎪 举个例子喵
-
-如果你想用DeepSeek官方的服务,就要这样改:
-
-```toml
-[model.llm_reasoning]
-name = "deepseek-reasoner" # 改成对应的模型名称,这里为DeepseekR1
-provider = "DEEP_SEEK" # 改成去DeepSeek游乐园
-
-[model.llm_normal]
-name = "deepseek-chat" # 改成对应的模型名称,这里为DeepseekV3
-provider = "DEEP_SEEK" # 也去DeepSeek游乐园
-```
-
-### 🎯 简单来说
-
-- `.env` 文件就像是你的票夹,存放着各个游乐园的门票和地址
-- `bot_config.toml` 就是告诉机器人:用哪张票去哪个游乐园玩
-- 所有模型都可以用同一个游乐园的票,也可以去不同的游乐园玩耍
-- 如果用硅基流动的服务,就保持默认配置不用改呢~
-
-记住:门票(key)要保管好,不能给别人看哦,不然别人就可以用你的票去玩了喵!
-
-## ---让我们开始吧---
-
-### 第一个文件:环境配置 (.env)
-
-这个文件就像是机器人的"身份证"呢,告诉它要用哪些AI服务喵~
-
-```ini
-# 这些是AI服务的密钥,就像是魔法钥匙一样呢
-# 要把 your_key 换成真正的密钥才行喵
-# 比如说:SILICONFLOW_KEY=sk-123456789abcdef
-SILICONFLOW_KEY=your_key
-SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1/
-DEEP_SEEK_KEY=your_key
-DEEP_SEEK_BASE_URL=https://api.deepseek.com/v1
-CHAT_ANY_WHERE_KEY=your_key
-CHAT_ANY_WHERE_BASE_URL=https://api.chatanywhere.tech/v1
-
-# 如果你不知道这是什么,那么下面这些不用改,保持原样就好啦
-# 如果使用Docker部署,需要改成0.0.0.0喵,不然听不见群友讲话了喵
-HOST=127.0.0.1
-PORT=8080
-
-# 这些是数据库设置,一般也不用改呢
-# 如果使用Docker部署,需要把MONGODB_HOST改成数据库容器的名字喵,默认是mongodb喵
-MONGODB_HOST=127.0.0.1
-MONGODB_PORT=27017
-DATABASE_NAME=MegBot
-# 数据库认证信息,如果需要认证就取消注释并填写下面三行喵
-# MONGODB_USERNAME = ""
-# MONGODB_PASSWORD = ""
-# MONGODB_AUTH_SOURCE = ""
-
-# 也可以使用URI连接数据库,取消注释填写在下面这行喵(URI的优先级比上面的高)
-# MONGODB_URI=mongodb://127.0.0.1:27017/MegBot
-
-# 这里是机器人的插件列表呢
-PLUGINS=["src2.plugins.chat"]
-```
-
-### 第二个文件:机器人配置 (bot_config.toml)
-
-这个文件就像是教机器人"如何说话"的魔法书呢!
-
-```toml
-[bot]
-qq = "把这里改成你的机器人QQ号喵" # 填写你的机器人QQ号
-nickname = "麦麦" # 机器人的名字,你可以改成你喜欢的任何名字哦,建议和机器人QQ名称/群昵称一样哦
-alias_names = ["小麦", "阿麦"] # 也可以用这个招呼机器人,可以不设置呢
-
-[personality]
-# 这里可以设置机器人的性格呢,让它更有趣一些喵
-prompt_personality = [
- "曾经是一个学习地质的女大学生,现在学习心理学和脑科学,你会刷贴吧", # 贴吧风格的性格
- "是一个女大学生,你有黑色头发,你会刷小红书" # 小红书风格的性格
-]
-prompt_schedule = "一个曾经学习地质,现在学习心理学和脑科学的女大学生,喜欢刷qq,贴吧,知乎和小红书" # 用来提示机器人每天干什么的提示词喵
-
-[message]
-min_text_length = 2 # 机器人每次至少要说几个字呢
-max_context_size = 15 # 机器人能记住多少条消息喵
-emoji_chance = 0.2 # 机器人使用表情的概率哦(0.2就是20%的机会呢)
-thinking_timeout = 120 # 机器人思考时间,时间越长能思考的时间越多,但是不要太长喵
-
-response_willing_amplifier = 1 # 机器人回复意愿放大系数,增大会让他更愿意聊天喵
-response_interested_rate_amplifier = 1 # 机器人回复兴趣度放大系数,听到记忆里的内容时意愿的放大系数喵
-down_frequency_rate = 3.5 # 降低回复频率的群组回复意愿降低系数
-ban_words = ["脏话", "不文明用语"] # 在这里填写不让机器人说的词,要用英文逗号隔开,每个词都要用英文双引号括起来喵
-
-[emoji]
-auto_save = true # 是否自动保存看到的表情包呢
-enable_check = false # 是否要检查表情包是不是合适的喵
-check_prompt = "符合公序良俗" # 检查表情包的标准呢
-
-[others]
-enable_kuuki_read = true # 让机器人能够"察言观色"喵
-enable_friend_chat = false # 是否启用好友聊天喵
-
-[groups]
-talk_allowed = [123456, 789012] # 比如:让机器人在群123456和789012里说话
-talk_frequency_down = [345678] # 比如:在群345678里少说点话
-ban_user_id = [111222] # 比如:不回复QQ号为111222的人的消息
-
-# 模型配置部分的详细说明喵~
-
-
-#下面的模型若使用硅基流动则不需要更改,使用ds官方则改成在.env自己指定的密钥和域名,使用自定义模型则选择定位相似的模型自己填写
-
-[model.llm_reasoning] #推理模型R1,用来理解和思考的喵
-name = "Pro/deepseek-ai/DeepSeek-R1" # 模型名字
-# name = "Qwen/QwQ-32B" # 如果想用千问模型,可以把上面那行注释掉,用这个呢
-provider = "SILICONFLOW" # 使用在.env里设置的宏,也就是去掉"_BASE_URL"留下来的字喵
-
-[model.llm_reasoning_minor] #R1蒸馏模型,是个轻量版的推理模型喵
-name = "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B"
-provider = "SILICONFLOW"
-
-[model.llm_normal] #V3模型,用来日常聊天的喵
-name = "Pro/deepseek-ai/DeepSeek-V3"
-provider = "SILICONFLOW"
-
-[model.llm_normal_minor] #V2.5模型,是V3的前代版本呢
-name = "deepseek-ai/DeepSeek-V2.5"
-provider = "SILICONFLOW"
-
-[model.vlm] #图像识别模型,让机器人能看懂图片喵
-name = "deepseek-ai/deepseek-vl2"
-provider = "SILICONFLOW"
-
-[model.embedding] #嵌入模型,帮助机器人理解文本的相似度呢
-name = "BAAI/bge-m3"
-provider = "SILICONFLOW"
-
-# 如果选择了llm方式提取主题,就用这个模型配置喵
-[topic.llm_topic]
-name = "Pro/deepseek-ai/DeepSeek-V3"
-provider = "SILICONFLOW"
-```
-
-## 💡 模型配置说明喵
-
-1. **关于模型服务**:
- - 如果你用硅基流动的服务,这些配置都不用改呢
- - 如果用DeepSeek官方API,要把provider改成你在.env里设置的宏喵
- - 如果要用自定义模型,选择一个相似功能的模型配置来改呢
-
-2. **主要模型功能**:
- - `llm_reasoning`: 负责思考和推理的大脑喵
- - `llm_normal`: 负责日常聊天的嘴巴呢
- - `vlm`: 负责看图片的眼睛哦
- - `embedding`: 负责理解文字含义的理解力喵
- - `topic`: 负责理解对话主题的能力呢
-
-## 🌟 小提示
-
-- 如果你刚开始使用,建议保持默认配置呢
-- 不同的模型有不同的特长,可以根据需要调整它们的使用比例哦
-
-## 🌟 小贴士喵
-
-- 记得要好好保管密钥(key)哦,不要告诉别人呢
-- 配置文件要小心修改,改错了机器人可能就不能和你玩了喵
-- 如果想让机器人更聪明,可以调整 personality 里的设置呢
-- 不想让机器人说某些话,就把那些词放在 ban_words 里面喵
-- QQ群号和QQ号都要用数字填写,不要加引号哦(除了机器人自己的QQ号)
-
-## ⚠️ 注意事项
-
-- 这个机器人还在测试中呢,可能会有一些小问题喵
-- 如果不知道怎么改某个设置,就保持原样不要动它哦~
-- 记得要先有AI服务的密钥,不然机器人就不能和你说话了呢
-- 修改完配置后要重启机器人才能生效喵~
diff --git a/docs/installation_standard.md b/docs/installation_standard.md
deleted file mode 100644
index cc3d3166..00000000
--- a/docs/installation_standard.md
+++ /dev/null
@@ -1,165 +0,0 @@
-# 🔧 配置指南
-
-## 简介
-
-本项目需要配置两个主要文件:
-
-1. `.env` - 配置API服务和系统环境
-2. `bot_config.toml` - 配置机器人行为和模型
-
-## API配置说明
-
-`.env` 和 `bot_config.toml` 中的API配置关系如下:
-
-### 在.env中定义API凭证
-
-```ini
-# API凭证配置
-SILICONFLOW_KEY=your_key # 硅基流动API密钥
-SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1/ # 硅基流动API地址
-
-DEEP_SEEK_KEY=your_key # DeepSeek API密钥
-DEEP_SEEK_BASE_URL=https://api.deepseek.com/v1 # DeepSeek API地址
-
-CHAT_ANY_WHERE_KEY=your_key # ChatAnyWhere API密钥
-CHAT_ANY_WHERE_BASE_URL=https://api.chatanywhere.tech/v1 # ChatAnyWhere API地址
-```
-
-### 在bot_config.toml中引用API凭证
-
-```toml
-[model.llm_reasoning]
-name = "Pro/deepseek-ai/DeepSeek-R1"
-provider = "SILICONFLOW" # 引用.env中定义的宏
-```
-
-如需切换到其他API服务,只需修改引用:
-
-```toml
-[model.llm_reasoning]
-name = "deepseek-reasoner" # 改成对应的模型名称,这里为DeepseekR1
-provider = "DEEP_SEEK" # 使用DeepSeek密钥
-```
-
-## 配置文件详解
-
-### 环境配置文件 (.env)
-
-```ini
-# API配置
-SILICONFLOW_KEY=your_key
-SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1/
-DEEP_SEEK_KEY=your_key
-DEEP_SEEK_BASE_URL=https://api.deepseek.com/v1
-CHAT_ANY_WHERE_KEY=your_key
-CHAT_ANY_WHERE_BASE_URL=https://api.chatanywhere.tech/v1
-
-# 服务配置
-
-HOST=127.0.0.1 # 如果使用Docker部署,需要改成0.0.0.0,否则QQ消息无法传入
-PORT=8080 # 与反向端口相同
-
-# 数据库配置
-MONGODB_HOST=127.0.0.1 # 如果使用Docker部署,需要改成数据库容器的名字,默认是mongodb
-MONGODB_PORT=27017 # MongoDB端口
-
-DATABASE_NAME=MegBot
-# 数据库认证信息,如果需要认证就取消注释并填写下面三行
-# MONGODB_USERNAME = ""
-# MONGODB_PASSWORD = ""
-# MONGODB_AUTH_SOURCE = ""
-
-# 也可以使用URI连接数据库,取消注释填写在下面这行(URI的优先级比上面的高)
-# MONGODB_URI=mongodb://127.0.0.1:27017/MegBot
-
-# 插件配置
-PLUGINS=["src2.plugins.chat"]
-```
-
-### 机器人配置文件 (bot_config.toml)
-
-```toml
-[bot]
-qq = "机器人QQ号" # 机器人的QQ号,必填
-nickname = "麦麦" # 机器人昵称
-# alias_names: 配置机器人可使用的别名。当机器人在群聊或对话中被调用时,别名可以作为直接命令或提及机器人的关键字使用。
-# 该配置项为字符串数组。例如: ["小麦", "阿麦"]
-alias_names = ["小麦", "阿麦"] # 机器人别名
-
-[personality]
-prompt_personality = [
- "曾经是一个学习地质的女大学生,现在学习心理学和脑科学,你会刷贴吧",
- "是一个女大学生,你有黑色头发,你会刷小红书"
-] # 人格提示词
-prompt_schedule = "一个曾经学习地质,现在学习心理学和脑科学的女大学生,喜欢刷qq,贴吧,知乎和小红书" # 日程生成提示词
-
-[message]
-min_text_length = 2 # 最小回复长度
-max_context_size = 15 # 上下文记忆条数
-emoji_chance = 0.2 # 表情使用概率
-thinking_timeout = 120 # 机器人思考时间,时间越长能思考的时间越多,但是不要太长
-
-response_willing_amplifier = 1 # 机器人回复意愿放大系数,增大会更愿意聊天
-response_interested_rate_amplifier = 1 # 机器人回复兴趣度放大系数,听到记忆里的内容时意愿的放大系数
-down_frequency_rate = 3.5 # 降低回复频率的群组回复意愿降低系数
-ban_words = [] # 禁用词列表
-
-[emoji]
-auto_save = true # 自动保存表情
-enable_check = false # 启用表情审核
-check_prompt = "符合公序良俗"
-
-[groups]
-talk_allowed = [] # 允许对话的群号
-talk_frequency_down = [] # 降低回复频率的群号
-ban_user_id = [] # 禁止回复的用户QQ号
-
-[others]
-enable_kuuki_read = true # 是否启用读空气功能
-enable_friend_chat = false # 是否启用好友聊天
-
-# 模型配置
-[model.llm_reasoning] # 推理模型
-name = "Pro/deepseek-ai/DeepSeek-R1"
-provider = "SILICONFLOW"
-
-[model.llm_reasoning_minor] # 轻量推理模型
-name = "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B"
-provider = "SILICONFLOW"
-
-[model.llm_normal] # 对话模型
-name = "Pro/deepseek-ai/DeepSeek-V3"
-provider = "SILICONFLOW"
-
-[model.llm_normal_minor] # 备用对话模型
-name = "deepseek-ai/DeepSeek-V2.5"
-provider = "SILICONFLOW"
-
-[model.vlm] # 图像识别模型
-name = "deepseek-ai/deepseek-vl2"
-provider = "SILICONFLOW"
-
-[model.embedding] # 文本向量模型
-name = "BAAI/bge-m3"
-provider = "SILICONFLOW"
-
-
-[topic.llm_topic]
-name = "Pro/deepseek-ai/DeepSeek-V3"
-provider = "SILICONFLOW"
-```
-
-## 注意事项
-
-1. API密钥安全:
- - 妥善保管API密钥
- - 不要将含有密钥的配置文件上传至公开仓库
-
-2. 配置修改:
- - 修改配置后需重启服务
- - 使用默认服务(硅基流动)时无需修改模型配置
- - QQ号和群号使用数字格式(机器人QQ号除外)
-
-3. 其他说明:
- - 项目处于测试阶段,可能存在未知问题
- - 建议初次使用保持默认配置
diff --git a/docs/linux_deploy_guide_for_beginners.md b/docs/linux_deploy_guide_for_beginners.md
deleted file mode 100644
index 4fe09d30..00000000
--- a/docs/linux_deploy_guide_for_beginners.md
+++ /dev/null
@@ -1,331 +0,0 @@
-# 面向纯新手的Linux服务器麦麦部署指南
-
-
-## 事前准备
-为了能使麦麦不间断的运行,你需要一台一直开着的服务器。
-
-### 如果你想购买服务器
-华为云、阿里云、腾讯云等等都是在国内可以选择的选择。
-
-租一台最低配置的就足敷需要了,按月租大概十几块钱就能租到了。
-
-### 如果你不想购买服务器
-你可以准备一台可以一直开着的电脑/主机,只需要保证能够正常访问互联网即可
-
-**下文将统称它们为`服务器`**
-
-我们假设你已经有了一台Linux架构的服务器。举例使用的是Ubuntu24.04,其他的原理相似。
-
-## 0.我们就从零开始吧
-
-### 网络问题
-
-为访问Github相关界面,推荐去下一款加速器,新手可以试试[Watt Toolkit](https://gitee.com/rmbgame/SteamTools/releases/latest)。
-
-### 安装包下载
-
-#### MongoDB
-进入[MongoDB下载页](https://www.mongodb.com/try/download/community-kubernetes-operator),并选择版本
-
-以Ubuntu24.04 x86为例,保持如图所示选项,点击`Download`即可,如果是其他系统,请在`Platform`中自行选择:
-
-
-
-
-不想使用上述方式?你也可以参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/administration/install-on-linux/#std-label-install-mdb-community-edition-linux)进行安装,进入后选择自己的系统版本即可
-
-#### QQ(可选)/Napcat
-*如果你使用Napcat的脚本安装,可以忽略此步*
-访问https://github.com/NapNeko/NapCatQQ/releases/latest
-在图中所示区域可以找到QQ的下载链接,选择对应版本下载即可
-从这里下载,可以保证你下载到的QQ版本兼容最新版Napcat
-
-如果你不想使用Napcat的脚本安装,还需参考[Napcat-Linux手动安装](https://www.napcat.wiki/guide/boot/Shell-Linux-SemiAuto)
-
-#### 麦麦
-
-先打开https://github.com/MaiM-with-u/MaiBot/releases
-往下滑找到这个
-
-下载箭头所指这个压缩包。
-
-### 路径
-
-我把麦麦相关文件放在了/moi/mai里面,你可以凭喜好更改,记得适当调整下面涉及到的部分即可。
-
-文件结构:
-
-```
-moi
-└─ mai
- ├─ linuxqq_3.2.16-32793_amd64.deb # linuxqq安装包
- ├─ mongodb-org-server_8.0.5_amd64.deb # MongoDB的安装包
- └─ bot
- └─ MaiMBot-0.5.8-alpha.zip # 麦麦的压缩包
-```
-
-### 网络
-
-你可以在你的服务器控制台网页更改防火墙规则,允许6099,8080,27017这几个端口的出入。
-
-## 1.正式开始!
-
-远程连接你的服务器,你会看到一个黑框框闪着白方格,这就是我们要进行设置的场所——终端了。以下的bash命令都是在这里输入。
-
-## 2. Python的安装
-
-- 导入 Python 的稳定版 PPA(Ubuntu需执行此步,Debian可忽略):
-
-```bash
-sudo add-apt-repository ppa:deadsnakes/ppa
-```
-
-- 导入 PPA 后,更新 APT 缓存:
-
-```bash
-sudo apt update
-```
-
-- 在「终端」中执行以下命令来安装 Python 3.12:
-
-```bash
-sudo apt install python3.12
-```
-
-- 验证安装是否成功:
-
-```bash
-python3.12 --version
-```
-- (可选)更新替代方案,设置 python3.12 为默认的 python3 版本:
-```bash
-sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1
-sudo update-alternatives --config python3
-```
-
-- 在「终端」中,执行以下命令安装 pip:
-
-```bash
-sudo apt install python3-pip
-```
-
-- 检查Pip是否安装成功:
-
-```bash
-pip --version
-```
-
-- 安装必要组件
-
-``` bash
-sudo apt install python-is-python3
-```
-
-## 3.MongoDB的安装
-*如果你是参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/administration/install-on-linux/#std-label-install-mdb-community-edition-linux)进行安装的,可跳过此步*
-
-``` bash
-cd /moi/mai
-```
-
-``` bash
-dpkg -i mongodb-org-server_8.0.5_amd64.deb
-```
-
-``` bash
-mkdir -p /root/data/mongodb/{data,log}
-```
-
-## 4.MongoDB的运行
-
-```bash
-service mongod start
-```
-
-```bash
-systemctl status mongod #通过这条指令检查运行状态
-```
-
-有需要的话可以把这个服务注册成开机自启
-
-```bash
-sudo systemctl enable mongod
-```
-
-## 5.Napcat的安装
-
-``` bash
-# 该脚本适用于支持Ubuntu 20+/Debian 10+/Centos9
-curl -o napcat.sh https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh && sudo bash napcat.sh
-```
-执行后,脚本会自动帮你部署好QQ及Napcat
-*注:如果你已经手动安装了Napcat和QQ,可忽略此步*
-
-成功的标志是输入``` napcat ```出来炫酷的彩虹色界面
-
-## 6.Napcat的运行
-
-此时你就可以根据提示在```napcat```里面登录你的QQ号了。
-
-```bash
-napcat start <你的QQ号>
-napcat status #检查运行状态
-```
-
-然后你就可以登录napcat的webui进行设置了:
-
-```http://<你服务器的公网IP>:6099/webui?token=napcat```
-
-如果你部署在自己的电脑上:
-```http://127.0.0.1:6099/webui?token=napcat```
-
-> [!WARNING]
-> 如果你的麦麦部署在公网,请**务必**修改Napcat的默认密码
-
-
-第一次是这个,后续改了密码之后token就会对应修改。你也可以使用```napcat log <你的QQ号>```来查看webui地址。把里面的```127.0.0.1```改成<你服务器的公网IP>即可。
-
-登录上之后在网络配置界面添加websocket客户端,名称随便输一个,url改成`ws://127.0.0.1:8080/onebot/v11/ws`保存之后点启用,就大功告成了。
-
-## 7.麦麦的安装
-
-### step 1 安装解压软件
-
-```bash
-sudo apt-get install unzip
-```
-
-### step 2 解压文件
-
-```bash
-cd /moi/mai/bot # 注意:要切换到压缩包的目录中去
-unzip MaiMBot-0.5.8-alpha.zip
-```
-
-### step 3 进入虚拟环境安装库
-
-```bash
-cd /moi/mai/bot
-python -m venv venv
-source venv/bin/activate
-pip install -r requirements.txt
-```
-
-### step 4 试运行
-
-```bash
-cd /moi/mai/bot
-python -m venv venv
-source venv/bin/activate
-python bot.py
-```
-
-肯定运行不成功,不过你会发现结束之后多了一些文件
-
-```
-bot
-├─ .env
-└─ config
- └─ bot_config.toml
-```
-
-你可以使用vim、nano等编辑器直接在终端里修改这些配置文件,但如果你不熟悉它们的操作,也可以使用带图形界面的编辑器。
-如果你的麦麦部署在远程服务器,也可以把它们下载到本地改好再传上去
-
-### step 5 文件配置
-
-本项目需要配置两个主要文件:
-
-1. `.env` - 配置API服务和系统环境
-2. `bot_config.toml` - 配置机器人行为和模型
-
-#### API
-
-你可以注册一个硅基流动的账号,通过邀请码注册有14块钱的免费额度:https://cloud.siliconflow.cn/i/7Yld7cfg。
-
-#### 修改配置文件
-请参考
-- [🎀 新手配置指南](./installation_cute.md) - 通俗易懂的配置教程,适合初次使用的猫娘
-- [⚙️ 标准配置指南](./installation_standard.md) - 简明专业的配置说明,适合有经验的用户
-
-
-### step 6 运行
-
-现在再运行
-
-```bash
-cd /moi/mai/bot
-python -m venv venv
-source venv/bin/activate
-python bot.py
-```
-
-应该就能运行成功了。
-
-## 8.事后配置
-
-可是现在还有个问题:只要你一关闭终端,bot.py就会停止运行。那该怎么办呢?我们可以把bot.py注册成服务。
-
-重启服务器,打开MongoDB和napcat服务。
-
-新建一个文件,名为`bot.service`,内容如下
-
-```
-[Unit]
-Description=maimai bot
-
-[Service]
-WorkingDirectory=/moi/mai/bot
-ExecStart=/moi/mai/bot/venv/bin/python /moi/mai/bot/bot.py
-Restart=on-failure
-User=root
-
-[Install]
-WantedBy=multi-user.target
-```
-
-里面的路径视自己的情况更改。
-
-把它放到`/etc/systemd/system`里面。
-
-重新加载 `systemd` 配置:
-
-```bash
-sudo systemctl daemon-reload
-```
-
-启动服务:
-
-```bash
-sudo systemctl start bot.service # 启动服务
-sudo systemctl restart bot.service # 或者重启服务
-```
-
-检查服务状态:
-
-```bash
-sudo systemctl status bot.service
-```
-
-现在再关闭终端,检查麦麦能不能正常回复QQ信息。如果可以的话就大功告成了!
-
-## 9.命令速查
-
-```bash
-service mongod start # 启动mongod服务
-napcat start <你的QQ号> # 登录napcat
-cd /moi/mai/bot # 切换路径
-python -m venv venv # 创建虚拟环境
-source venv/bin/activate # 激活虚拟环境
-
-sudo systemctl daemon-reload # 重新加载systemd配置
-sudo systemctl start bot.service # 启动bot服务
-sudo systemctl enable bot.service # 启动bot服务
-
-sudo systemctl status bot.service # 检查bot服务状态
-```
-
-```bash
-python bot.py # 运行麦麦
-```
-
diff --git a/docs/manual_deploy_linux.md b/docs/manual_deploy_linux.md
deleted file mode 100644
index fb6e7872..00000000
--- a/docs/manual_deploy_linux.md
+++ /dev/null
@@ -1,201 +0,0 @@
-# 📦 Linux系统如何手动部署MaiMbot麦麦?
-
-## 准备工作
-
-- 一台联网的Linux设备(本教程以Ubuntu/Debian系为例)
-- QQ小号(QQ框架的使用可能导致qq被风控,严重(小概率)可能会导致账号封禁,强烈不推荐使用大号)
-- 可用的大模型API
-- 一个AI助手,网上随便搜一家打开来用都行,可以帮你解决一些不懂的问题
-- 以下内容假设你对Linux系统有一定的了解,如果觉得难以理解,请直接用Windows系统部署[Windows系统部署指南](./manual_deploy_windows.md)或[使用Windows一键包部署](https://github.com/MaiM-with-u/MaiBot/releases/tag/EasyInstall-windows)
-
-## 你需要知道什么?
-
-- 如何正确向AI助手提问,来学习新知识
-
-- Python是什么
-
-- Python的虚拟环境是什么?如何创建虚拟环境
-
-- 命令行是什么
-
-- 数据库是什么?如何安装并启动MongoDB
-
-- 如何运行一个QQ机器人,以及NapCat框架是什么
-
----
-
-## 环境配置
-
-### 1️⃣ **确认Python版本**
-
-需确保Python版本为3.9及以上
-
-```bash
-python --version
-# 或
-python3 --version
-```
-
-如果版本低于3.9,请更新Python版本,目前建议使用python3.12
-
-```bash
-# Debian
-sudo apt update
-sudo apt install python3.12
-# Ubuntu
-sudo add-apt-repository ppa:deadsnakes/ppa
-sudo apt update
-sudo apt install python3.12
-
-# 执行完以上命令后,建议在执行时将python3指向python3.12
-# 更新替代方案,设置 python3.12 为默认的 python3 版本:
-sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1
-sudo update-alternatives --config python3
-```
-建议再执行以下命令,使后续运行命令中的`python3`等同于`python`
-```bash
-sudo apt install python-is-python3
-```
-
-### 2️⃣ **创建虚拟环境**
-
-```bash
-# 方法1:使用venv(推荐)
-python3 -m venv maimbot
-source maimbot/bin/activate # 激活环境
-
-# 方法2:使用conda(需先安装Miniconda)
-wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
-bash Miniconda3-latest-Linux-x86_64.sh
-conda create -n maimbot python=3.9
-conda activate maimbot
-
-# 通过以上方法创建并进入虚拟环境后,再执行以下命令
-
-# 安装依赖(任选一种环境)
-pip install -r requirements.txt
-```
-
----
-
-## 数据库配置
-
-### 3️⃣ **安装并启动MongoDB**
-
-- 安装与启动:请参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/administration/install-on-linux/#std-label-install-mdb-community-edition-linux),进入后选择自己的系统版本即可
-- 默认连接本地27017端口
-
----
-
-## NapCat配置
-
-### 4️⃣ **安装NapCat框架**
-
-- 执行NapCat的Linux一键使用脚本(支持Ubuntu 20+/Debian 10+/Centos9)
-```bash
-curl -o napcat.sh https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh && sudo bash napcat.sh
-```
-- 如果你不想使用Napcat的脚本安装,可参考[Napcat-Linux手动安装](https://www.napcat.wiki/guide/boot/Shell-Linux-SemiAuto)
-
-- 使用QQ小号登录,添加反向WS地址: `ws://127.0.0.1:8080/onebot/v11/ws`
-
----
-
-## 配置文件设置
-
-### 5️⃣ **配置文件设置,让麦麦Bot正常工作**
-可先运行一次
-```bash
-# 在项目目录下操作
-nb run
-# 或
-python3 bot.py
-```
-之后你就可以找到`.env`和`bot_config.toml`这两个文件了
-关于文件内容的配置请参考:
-- [🎀 新手配置指南](./installation_cute.md) - 通俗易懂的配置教程,适合初次使用的猫娘
-- [⚙️ 标准配置指南](./installation_standard.md) - 简明专业的配置说明,适合有经验的用户
-
----
-
-## 启动机器人
-
-### 6️⃣ **启动麦麦机器人**
-
-```bash
-# 在项目目录下操作
-nb run
-# 或
-python3 bot.py
-```
-
----
-
-### 7️⃣ **使用systemctl管理maimbot**
-
-使用以下命令添加服务文件:
-
-```bash
-sudo nano /etc/systemd/system/maimbot.service
-```
-
-输入以下内容:
-
-``:你的maimbot目录
-
-``:你的venv环境(就是上文创建环境后,执行的代码`source maimbot/bin/activate`中source后面的路径的绝对路径)
-
-```ini
-[Unit]
-Description=MaiMbot 麦麦
-After=network.target mongod.service
-
-[Service]
-Type=simple
-WorkingDirectory=
-ExecStart=/python3 bot.py
-ExecStop=/bin/kill -2 $MAINPID
-Restart=always
-RestartSec=10s
-
-[Install]
-WantedBy=multi-user.target
-```
-
-输入以下命令重新加载systemd:
-
-```bash
-sudo systemctl daemon-reload
-```
-
-启动并设置开机自启:
-
-```bash
-sudo systemctl start maimbot
-sudo systemctl enable maimbot
-```
-
-输入以下命令查看日志:
-
-```bash
-sudo journalctl -xeu maimbot
-```
-
----
-
-## **其他组件(可选)**
-
-- 直接运行 knowledge.py生成知识库
-
----
-
-## 常见问题
-
-🔧 权限问题:在命令前加`sudo`
-🔌 端口占用:使用`sudo lsof -i :8080`查看端口占用
-🛡️ 防火墙:确保8080/27017端口开放
-
-```bash
-sudo ufw allow 8080/tcp
-sudo ufw allow 27017/tcp
-```
diff --git a/docs/manual_deploy_macos.md b/docs/manual_deploy_macos.md
deleted file mode 100644
index e5178a83..00000000
--- a/docs/manual_deploy_macos.md
+++ /dev/null
@@ -1,201 +0,0 @@
-# 📦 macOS系统手动部署MaiMbot麦麦指南
-
-## 准备工作
-
-- 一台搭载了macOS系统的设备(macOS 12.0 或以上)
-- QQ小号(QQ框架的使用可能导致qq被风控,严重(小概率)可能会导致账号封禁,强烈不推荐使用大号)
-- Homebrew包管理器
- - 如未安装,你可以在https://github.com/Homebrew/brew/releases/latest 找到.pkg格式的安装包
-- 可用的大模型API
-- 一个AI助手,网上随便搜一家打开来用都行,可以帮你解决一些不懂的问题
-- 以下内容假设你对macOS系统有一定的了解,如果觉得难以理解,请直接用Windows系统部署[Windows系统部署指南](./manual_deploy_windows.md)或[使用Windows一键包部署](https://github.com/MaiM-with-u/MaiBot/releases/tag/EasyInstall-windows)
-- 终端应用(iTerm2等)
-
----
-
-## 环境配置
-
-### 1️⃣ **Python环境配置**
-
-```bash
-# 检查Python版本(macOS自带python可能为2.7)
-python3 --version
-
-# 通过Homebrew安装Python
-brew install python@3.12
-
-# 设置环境变量(如使用zsh)
-echo 'export PATH="/usr/local/opt/python@3.12/bin:$PATH"' >> ~/.zshrc
-source ~/.zshrc
-
-# 验证安装
-python3 --version # 应显示3.12.x
-pip3 --version # 应关联3.12版本
-```
-
-### 2️⃣ **创建虚拟环境**
-
-```bash
-# 方法1:使用venv(推荐)
-python3 -m venv maimbot-venv
-source maimbot-venv/bin/activate # 激活虚拟环境
-
-# 方法2:使用conda
-brew install --cask miniconda
-conda create -n maimbot python=3.9
-conda activate maimbot # 激活虚拟环境
-
-# 安装项目依赖
-# 请确保已经进入虚拟环境再执行
-pip install -r requirements.txt
-```
-
----
-
-## 数据库配置
-
-### 3️⃣ **安装MongoDB**
-
-请参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/tutorial/install-mongodb-on-os-x/#install-mongodb-community-edition)
-
----
-
-## NapCat
-
-### 4️⃣ **安装与配置Napcat**
-- 安装
-可以使用Napcat官方提供的[macOS安装工具](https://github.com/NapNeko/NapCat-Mac-Installer/releases/)
-由于权限问题,补丁过程需要手动替换 package.json,请注意备份原文件~
-- 配置
-使用QQ小号登录,添加反向WS地址: `ws://127.0.0.1:8080/onebot/v11/ws`
-
----
-
-## 配置文件设置
-
-### 5️⃣ **生成配置文件**
-可先运行一次
-```bash
-# 在项目目录下操作
-nb run
-# 或
-python3 bot.py
-```
-
-之后你就可以找到`.env`和`bot_config.toml`这两个文件了
-
-关于文件内容的配置请参考:
-- [🎀 新手配置指南](./installation_cute.md) - 通俗易懂的配置教程,适合初次使用的猫娘
-- [⚙️ 标准配置指南](./installation_standard.md) - 简明专业的配置说明,适合有经验的用户
-
-
----
-
-## 启动机器人
-
-### 6️⃣ **启动麦麦机器人**
-
-```bash
-# 在项目目录下操作
-nb run
-# 或
-python3 bot.py
-```
-
-## 启动管理
-
-### 7️⃣ **通过launchd管理服务**
-
-创建plist文件:
-
-```bash
-nano ~/Library/LaunchAgents/com.maimbot.plist
-```
-
-内容示例(需替换实际路径):
-
-```xml
-
-
-
-
- Label
- com.maimbot
-
- ProgramArguments
-
- /path/to/maimbot-venv/bin/python
- /path/to/MaiMbot/bot.py
-
-
- WorkingDirectory
- /path/to/MaiMbot
-
- StandardOutPath
- /tmp/maimbot.log
- StandardErrorPath
- /tmp/maimbot.err
-
- RunAtLoad
-
- KeepAlive
-
-
-
-```
-
-加载服务:
-
-```bash
-launchctl load ~/Library/LaunchAgents/com.maimbot.plist
-launchctl start com.maimbot
-```
-
-查看日志:
-
-```bash
-tail -f /tmp/maimbot.log
-```
-
----
-
-## 常见问题处理
-
-1. **权限问题**
-```bash
-# 遇到文件权限错误时
-chmod -R 755 ~/Documents/MaiMbot
-```
-
-2. **Python模块缺失**
-```bash
-# 确保在虚拟环境中
-source maimbot-venv/bin/activate # 或 conda 激活
-pip install --force-reinstall -r requirements.txt
-```
-
-3. **MongoDB连接失败**
-```bash
-# 检查服务状态
-brew services list
-# 重置数据库权限
-mongosh --eval "db.adminCommand({setFeatureCompatibilityVersion: '5.0'})"
-```
-
----
-
-## 系统优化建议
-
-1. **关闭App Nap**
-```bash
-# 防止系统休眠NapCat进程
-defaults write NSGlobalDomain NSAppSleepDisabled -bool YES
-```
-
-2. **电源管理设置**
-```bash
-# 防止睡眠影响机器人运行
-sudo systemsetup -setcomputersleep Never
-```
-
----
diff --git a/docs/manual_deploy_windows.md b/docs/manual_deploy_windows.md
deleted file mode 100644
index b5ed71d8..00000000
--- a/docs/manual_deploy_windows.md
+++ /dev/null
@@ -1,110 +0,0 @@
-# 📦 Windows系统如何手动部署MaiMbot麦麦?
-
-## 你需要什么?
-
-- 一台电脑,能够上网的那种
-
-- 一个QQ小号(QQ框架的使用可能导致qq被风控,严重(小概率)可能会导致账号封禁,强烈不推荐使用大号)
-
-- 可用的大模型API
-
-- 一个AI助手,网上随便搜一家打开来用都行,可以帮你解决一些不懂的问题
-
-## 你需要知道什么?
-
-- 如何正确向AI助手提问,来学习新知识
-
-- Python是什么
-
-- Python的虚拟环境是什么?如何创建虚拟环境
-
-- 命令行是什么
-
-- 数据库是什么?如何安装并启动MongoDB
-
-- 如何运行一个QQ机器人,以及NapCat框架是什么
-
-## 如果准备好了,就可以开始部署了
-
-### 1️⃣ **首先,我们需要安装正确版本的Python**
-
-在创建虚拟环境之前,请确保你的电脑上安装了Python 3.9及以上版本。如果没有,可以按以下步骤安装:
-
-1. 访问Python官网下载页面:
-2. 下载Windows安装程序 (64-bit): `python-3.9.13-amd64.exe`
-3. 运行安装程序,并确保勾选"Add Python 3.9 to PATH"选项
-4. 点击"Install Now"开始安装
-
-或者使用PowerShell自动下载安装(需要管理员权限):
-
-```powershell
-# 下载并安装Python 3.9.13
-$pythonUrl = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe"
-$pythonInstaller = "$env:TEMP\python-3.9.13-amd64.exe"
-Invoke-WebRequest -Uri $pythonUrl -OutFile $pythonInstaller
-Start-Process -Wait -FilePath $pythonInstaller -ArgumentList "/quiet", "InstallAllUsers=0", "PrependPath=1" -Verb RunAs
-```
-
-### 2️⃣ **创建Python虚拟环境来运行程序**
-
-> 你可以选择使用以下两种方法之一来创建Python环境:
-
-```bash
-# ---方法1:使用venv(Python自带)
-# 在命令行中创建虚拟环境(环境名为maimbot)
-# 这会让你在运行命令的目录下创建一个虚拟环境
-# 请确保你已通过cd命令前往到了对应路径,不然之后你可能找不到你的python环境
-python -m venv maimbot
-
-maimbot\\Scripts\\activate
-
-# 安装依赖
-pip install -r requirements.txt
-```
-
-```bash
-# ---方法2:使用conda
-# 创建一个新的conda环境(环境名为maimbot)
-# Python版本为3.9
-conda create -n maimbot python=3.9
-
-# 激活环境
-conda activate maimbot
-
-# 安装依赖
-pip install -r requirements.txt
-```
-
-### 3️⃣ **然后你需要启动MongoDB数据库,来存储信息**
-
-- 安装并启动MongoDB服务
-- 默认连接本地27017端口
-
-### 4️⃣ **配置NapCat,让麦麦bot与qq取得联系**
-
-- 安装并登录NapCat(用你的qq小号)
-- 添加反向WS: `ws://127.0.0.1:8080/onebot/v11/ws`
-
-### 5️⃣ **配置文件设置,让麦麦Bot正常工作**
-
-- 修改环境配置文件:`.env`
-- 修改机器人配置文件:`bot_config.toml`
-
-### 6️⃣ **启动麦麦机器人**
-
-- 打开命令行,cd到对应路径
-
-```bash
-nb run
-```
-
-- 或者cd到对应路径后
-
-```bash
-python bot.py
-```
-
-### 7️⃣ **其他组件(可选)**
-
-- `run_thingking.bat`: 启动可视化推理界面(未完善)
-- 直接运行 knowledge.py生成知识库
diff --git a/docs/pic/API_KEY.png b/docs/pic/API_KEY.png
deleted file mode 100644
index 901d1d13..00000000
Binary files a/docs/pic/API_KEY.png and /dev/null differ
diff --git a/docs/pic/MONGO_DB_0.png b/docs/pic/MONGO_DB_0.png
deleted file mode 100644
index 8d91d37d..00000000
Binary files a/docs/pic/MONGO_DB_0.png and /dev/null differ
diff --git a/docs/pic/MONGO_DB_1.png b/docs/pic/MONGO_DB_1.png
deleted file mode 100644
index 0ef3b559..00000000
Binary files a/docs/pic/MONGO_DB_1.png and /dev/null differ
diff --git a/docs/pic/MONGO_DB_2.png b/docs/pic/MONGO_DB_2.png
deleted file mode 100644
index e59cc879..00000000
Binary files a/docs/pic/MONGO_DB_2.png and /dev/null differ
diff --git a/docs/pic/MongoDB_Ubuntu_guide.png b/docs/pic/MongoDB_Ubuntu_guide.png
deleted file mode 100644
index abd47c28..00000000
Binary files a/docs/pic/MongoDB_Ubuntu_guide.png and /dev/null differ
diff --git a/docs/pic/QQ_Download_guide_Linux.png b/docs/pic/QQ_Download_guide_Linux.png
deleted file mode 100644
index 1d47e9d2..00000000
Binary files a/docs/pic/QQ_Download_guide_Linux.png and /dev/null differ
diff --git a/docs/pic/compass_downloadguide.png b/docs/pic/compass_downloadguide.png
deleted file mode 100644
index 06a08b52..00000000
Binary files a/docs/pic/compass_downloadguide.png and /dev/null differ
diff --git a/docs/pic/linux_beginner_downloadguide.png b/docs/pic/linux_beginner_downloadguide.png
deleted file mode 100644
index 4c6fbf01..00000000
Binary files a/docs/pic/linux_beginner_downloadguide.png and /dev/null differ
diff --git a/docs/pic/synology_.env.prod.png b/docs/pic/synology_.env.prod.png
deleted file mode 100644
index 0bdcacdf..00000000
Binary files a/docs/pic/synology_.env.prod.png and /dev/null differ
diff --git a/docs/pic/synology_create_project.png b/docs/pic/synology_create_project.png
deleted file mode 100644
index f716d460..00000000
Binary files a/docs/pic/synology_create_project.png and /dev/null differ
diff --git a/docs/pic/synology_docker-compose.png b/docs/pic/synology_docker-compose.png
deleted file mode 100644
index f70003e2..00000000
Binary files a/docs/pic/synology_docker-compose.png and /dev/null differ
diff --git a/docs/pic/synology_how_to_download.png b/docs/pic/synology_how_to_download.png
deleted file mode 100644
index 011f9887..00000000
Binary files a/docs/pic/synology_how_to_download.png and /dev/null differ
diff --git a/docs/pic/video.png b/docs/pic/video.png
deleted file mode 100644
index 95754a0c..00000000
Binary files a/docs/pic/video.png and /dev/null differ
diff --git a/docs/synology_deploy.md b/docs/synology_deploy.md
deleted file mode 100644
index 307f0bb5..00000000
--- a/docs/synology_deploy.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# 群晖 NAS 部署指南
-
-**笔者使用的是 DSM 7.2.2,其他 DSM 版本的操作可能不完全一样**
-**需要使用 Container Manager,群晖的部分部分入门级 NAS 可能不支持**
-
-## 部署步骤
-
-### 创建配置文件目录
-
-打开 `DSM ➡️ 控制面板 ➡️ 共享文件夹`,点击 `新增` ,创建一个共享文件夹
-只需要设置名称,其他设置均保持默认即可。如果你已经有 docker 专用的共享文件夹了,就跳过这一步
-
-打开 `DSM ➡️ FileStation`, 在共享文件夹中创建一个 `MaiMBot` 文件夹
-
-### 准备配置文件
-
-docker-compose.yml: https://github.com/SengokuCola/MaiMBot/blob/main/docker-compose.yml
-下载后打开,将 `services-mongodb-image` 修改为 `mongo:4.4.24`。这是因为最新的 MongoDB 强制要求 AVX 指令集,而群晖似乎不支持这个指令集
-
-
-bot_config.toml: https://github.com/SengokuCola/MaiMBot/blob/main/template/bot_config_template.toml
-下载后,重命名为 `bot_config.toml`
-打开它,按自己的需求填写配置文件
-
-.env: https://github.com/SengokuCola/MaiMBot/blob/main/template.env
-下载后,重命名为 `.env`
-将 `HOST` 修改为 `0.0.0.0`,确保 maimbot 能被 napcat 访问
-按下图修改 mongodb 设置,使用 `MONGODB_URI`
-
-
-把 `bot_config.toml` 和 `.env` 放入之前创建的 `MaiMBot`文件夹
-
-#### 如何下载?
-
-点这里!
-
-### 创建项目
-
-打开 `DSM ➡️ ContainerManager ➡️ 项目`,点击 `新增` 创建项目,填写以下内容:
-
-- 项目名称: `maimbot`
-- 路径:之前创建的 `MaiMBot` 文件夹
-- 来源: `上传 docker-compose.yml`
-- 文件:之前下载的 `docker-compose.yml` 文件
-
-图例:
-
-
-
-一路点下一步,等待项目创建完成
-
-### 设置 Napcat
-
-1. 登陆 napcat
- 打开 napcat: `http://<你的nas地址>:6099` ,输入token登陆
- token可以打开 `DSM ➡️ ContainerManager ➡️ 项目 ➡️ MaiMBot ➡️ 容器 ➡️ Napcat ➡️ 日志`,找到类似 `[WebUi] WebUi Local Panel Url: http://127.0.0.1:6099/webui?token=xxxx` 的日志
- 这个 `token=` 后面的就是你的 napcat token
-
-2. 按提示,登陆你给麦麦准备的QQ小号
-
-3. 设置 websocket 客户端
- `网络配置 -> 新建 -> Websocket客户端`,名称自定,URL栏填入 `ws://maimbot:8080/onebot/v11/ws`,启用并保存即可。
- 若修改过容器名称,则替换 `maimbot` 为你自定的名称
-
-### 部署完成
-
-找个群,发送 `麦麦,你在吗` 之类的
-如果一切正常,应该能正常回复了
\ No newline at end of file
diff --git a/emoji_reviewer.py b/emoji_reviewer.py
deleted file mode 100644
index 5e8a0040..00000000
--- a/emoji_reviewer.py
+++ /dev/null
@@ -1,382 +0,0 @@
-import json
-import re
-import warnings
-import gradio as gr
-import os
-import signal
-import sys
-import requests
-import tomli
-
-from dotenv import load_dotenv
-from src.common.database import db
-
-try:
- from src.common.logger import get_module_logger
-
- logger = get_module_logger("emoji_reviewer")
-except ImportError:
- from loguru import logger
-
- # 检查并创建日志目录
- log_dir = "logs/emoji_reviewer"
- if not os.path.exists(log_dir):
- os.makedirs(log_dir, exist_ok=True)
- # 配置控制台输出格式
- logger.remove() # 移除默认的处理器
- logger.add(sys.stderr, format="{time:MM-DD HH:mm} | emoji_reviewer | {message}") # 添加控制台输出
- logger.add(
- "logs/emoji_reviewer/{time:YYYY-MM-DD}.log",
- rotation="00:00",
- format="{time:MM-DD HH:mm} | emoji_reviewer | {message}"
- )
- logger.warning("检测到src.common.logger并未导入,将使用默认loguru作为日志记录器")
- logger.warning("如果你是用的是低版本(0.5.13)麦麦,请忽略此警告")
-# 忽略 gradio 版本警告
-warnings.filterwarnings("ignore", message="IMPORTANT: You are using gradio version.*")
-
-root_dir = os.path.dirname(os.path.abspath(__file__))
-bot_config_path = os.path.join(root_dir, "config/bot_config.toml")
-if os.path.exists(bot_config_path):
- with open(bot_config_path, "rb") as f:
- try:
- toml_dict = tomli.load(f)
- embedding_config = toml_dict['model']['embedding']
- embedding_name = embedding_config["name"]
- embedding_provider = embedding_config["provider"]
- except tomli.TOMLDecodeError as e:
- logger.critical(f"配置文件bot_config.toml填写有误,请检查第{e.lineno}行第{e.colno}处:{e.msg}")
- exit(1)
- except KeyError:
- logger.critical("配置文件bot_config.toml缺少model.embedding设置,请补充后再编辑表情包")
- exit(1)
-else:
- logger.critical(f"没有找到配置文件{bot_config_path}")
- exit(1)
-env_path = os.path.join(root_dir, ".env")
-if not os.path.exists(env_path):
- logger.critical(f"没有找到环境变量文件{env_path}")
- exit(1)
-load_dotenv(env_path)
-
-tags_choices = ["无", "包括", "排除"]
-tags = {
- "reviewed": ("已审查", "排除"),
- "blacklist": ("黑名单", "排除"),
-}
-format_choices = ["包括", "无"]
-formats = ["jpg", "jpeg", "png", "gif", "其它"]
-
-
-def signal_handler(signum, frame):
- """处理 Ctrl+C 信号"""
- logger.info("收到终止信号,正在关闭 Gradio 服务器...")
- sys.exit(0)
-
-
-# 注册信号处理器
-signal.signal(signal.SIGINT, signal_handler)
-required_fields = ["_id", "path", "description", "hash", *tags.keys()] # 修复拼写错误的时候记得把这里的一起改了
-
-emojis_db = list(db.emoji.find({}, {k: 1 for k in required_fields}))
-emoji_filtered = []
-emoji_show = None
-
-max_num = 20
-neglect_update = 0
-
-
-async def get_embedding(text):
- try:
- base_url = os.environ.get(f"{embedding_provider}_BASE_URL")
- if base_url.endswith('/'):
- url = base_url + 'embeddings'
- else:
- url = base_url + '/embeddings'
- key = os.environ.get(f"{embedding_provider}_KEY")
- headers = {
- "Authorization": f"Bearer {key}",
- "Content-Type": "application/json"
- }
- payload = {
- "model": embedding_name,
- "input": text,
- "encoding_format": "float"
- }
- response = requests.post(url, headers=headers, data=json.dumps(payload))
- if response.status_code == 200:
- result = response.json()
- embedding = result["data"][0]["embedding"]
- return embedding
- else:
- return f"网络错误{response.status_code}"
- except Exception:
- return None
-
-
-def set_max_num(slider):
- global max_num
- max_num = slider
-
-
-def filter_emojis(tag_filters, format_filters):
- global emoji_filtered
- e_filtered = emojis_db
-
- format_include = []
- for format, value in format_filters.items():
- if value:
- format_include.append(format)
-
- if len(format_include) == 0:
- return []
-
- for tag, value in tag_filters.items():
- if value == "包括":
- e_filtered = [d for d in e_filtered if tag in d]
- elif value == "排除":
- e_filtered = [d for d in e_filtered if tag not in d]
-
- if '其它' in format_include:
- exclude = [f for f in formats if f not in format_include]
- if exclude:
- ff = '|'.join(exclude)
- compiled_pattern = re.compile(rf"\.({ff})$", re.IGNORECASE)
- e_filtered = [d for d in e_filtered if not compiled_pattern.search(d.get("path", ""), re.IGNORECASE)]
- else:
- ff = '|'.join(format_include)
- compiled_pattern = re.compile(rf"\.({ff})$", re.IGNORECASE)
- e_filtered = [d for d in e_filtered if compiled_pattern.search(d.get("path", ""), re.IGNORECASE)]
-
- emoji_filtered = e_filtered
-
-
-def update_gallery(from_latest, *filter_values):
- global emoji_filtered
- tf = filter_values[:len(tags)]
- ff = filter_values[len(tags):]
- filter_emojis({k: v for k, v in zip(tags.keys(), tf)}, {k: v for k, v in zip(formats, ff)})
- if from_latest:
- emoji_filtered.reverse()
- if len(emoji_filtered) > max_num:
- info = f"已筛选{len(emoji_filtered)}个表情包中的{max_num}个。"
- emoji_filtered = emoji_filtered[:max_num]
- else:
- info = f"已筛选{len(emoji_filtered)}个表情包。"
- global emoji_show
- emoji_show = None
- return [gr.update(value=[], selected_index=None, allow_preview=False), info]
-
-
-def update_gallery2():
- thumbnails = [e.get("path", "") for e in emoji_filtered]
- return gr.update(value=thumbnails, allow_preview=True)
-
-
-def on_select(evt: gr.SelectData, *tag_values):
- new_index = evt.index
- print(new_index)
- global emoji_show, neglect_update
- if new_index is None:
- emoji_show = None
- targets = []
- for current_value in tag_values:
- if current_value:
- neglect_update += 1
- targets.append(False)
- else:
- targets.append(gr.update())
- return [
- gr.update(selected_index=new_index),
- "",
- *targets
- ]
- else:
- emoji_show = emoji_filtered[new_index]
- targets = []
- neglect_update = 0
- for current_value, tag in zip(tag_values, tags.keys()):
- target = tag in emoji_show
- if current_value != target:
- neglect_update += 1
- targets.append(target)
- else:
- targets.append(gr.update())
- return [
- gr.update(selected_index=new_index),
- emoji_show.get("description", ""),
- *targets
- ]
-
-
-def desc_change(desc, edited):
- if emoji_show and desc != emoji_show.get("description", ""):
- if edited:
- return [gr.update(), True]
- else:
- return ["(尚未保存)", True]
- if edited:
- return ["", False]
- else:
- return [gr.update(), False]
-
-
-def revert_desc():
- if emoji_show:
- return emoji_show.get("description", "")
- else:
- return ""
-
-
-async def save_desc(desc):
- if emoji_show:
- try:
- yield ["正在构建embedding,请勿关闭页面...", gr.update(interactive=False), gr.update(interactive=False)]
- embedding = await get_embedding(desc)
- if embedding is None or isinstance(embedding, str):
- yield [
- f"获取embeddings失败!{embedding}",
- gr.update(interactive=True),
- gr.update(interactive=True)
- ]
- else:
- e_id = emoji_show["_id"]
- update_dict = {"$set": {"embedding": embedding, "description": desc}}
- db.emoji.update_one({"_id": e_id}, update_dict)
-
- e_hash = emoji_show["hash"]
- update_dict = {"$set": {"description": desc}}
- db.images.update_one({"hash": e_hash}, update_dict)
- db.image_descriptions.update_one({"hash": e_hash}, update_dict)
- emoji_show["description"] = desc
-
- logger.info(f'Update description and embeddings: {e_id}(hash={hash})')
- yield ["保存完成", gr.update(value=desc, interactive=True), gr.update(interactive=True)]
- except Exception as e:
- yield [
- f"出现异常: {e}",
- gr.update(interactive=True),
- gr.update(interactive=True)
- ]
-
- else:
- yield ["没有选中表情包", gr.update()]
-
-
-def change_tag(*tag_values):
- if not emoji_show:
- return gr.update()
- global neglect_update
- if neglect_update > 0:
- neglect_update -= 1
- return gr.update()
- set_dict = {}
- unset_dict = {}
- e_id = emoji_show["_id"]
- for value, tag in zip(tag_values, tags.keys()):
- if value:
- if tag not in emoji_show:
- set_dict[tag] = True
- emoji_show[tag] = True
- logger.info(f'Add tag "{tag}" to {e_id}')
- else:
- if tag in emoji_show:
- unset_dict[tag] = ""
- del emoji_show[tag]
- logger.info(f'Delete tag "{tag}" from {e_id}')
-
- update_dict = {"$set": set_dict, "$unset": unset_dict}
- db.emoji.update_one({"_id": e_id}, update_dict)
- return "已更新标签状态"
-
-
-with gr.Blocks(title="MaimBot表情包审查器") as app:
- desc_edit = gr.State(value=False)
- gr.Markdown(
- value="""
- # MaimBot表情包审查器
- """
- )
- gr.Markdown(value="---") # 添加分割线
- gr.Markdown(value="""
- ## 审查器说明\n
- 该审查器用于人工修正识图模型对表情包的识别偏差,以及管理表情包黑名单:\n
- 每一个表情包都有描述以及“已审查”和“黑名单”两个标签。描述可以编辑并保存。“黑名单”标签可以禁止麦麦使用该表情包。\n
- 作者:遗世紫丁香(HexatomicRing)
- """)
- gr.Markdown(value="---")
-
- with gr.Row():
- with gr.Column(scale=2):
- info_label = gr.Markdown("")
- gallery = gr.Gallery(label="表情包列表", columns=4, rows=6)
- description = gr.Textbox(label="描述", interactive=True)
- description_label = gr.Markdown("")
- tag_boxes = {
- tag: gr.Checkbox(label=name, interactive=True)
- for tag, (name, _) in tags.items()
- }
-
- with gr.Row():
- revert_btn = gr.Button("还原描述")
- save_btn = gr.Button("保存描述")
-
- with gr.Column(scale=1):
- max_num_slider = gr.Slider(label="最大显示数量", minimum=1, maximum=500, value=max_num, interactive=True)
- check_from_latest = gr.Checkbox(label="由新到旧", interactive=True)
- tag_filters = {
- tag: gr.Dropdown(tags_choices, value=value, label=f"{name}筛选")
- for tag, (name, value) in tags.items()
- }
- gr.Markdown(value="---")
- gr.Markdown(value="格式筛选:")
- format_filters = {
- f: gr.Checkbox(label=f, value=True)
- for f in formats
- }
- refresh_btn = gr.Button("刷新筛选")
- filters = list(tag_filters.values()) + list(format_filters.values())
-
- max_num_slider.change(set_max_num, max_num_slider, None)
- description.change(desc_change, [description, desc_edit], [description_label, desc_edit])
- for component in filters:
- component.change(
- fn=update_gallery,
- inputs=[check_from_latest, *filters],
- outputs=[gallery, info_label],
- preprocess=False
- ).then(
- fn=update_gallery2,
- inputs=None,
- outputs=gallery)
- refresh_btn.click(
- fn=update_gallery,
- inputs=[check_from_latest, *filters],
- outputs=[gallery, info_label],
- preprocess=False
- ).then(
- fn=update_gallery2,
- inputs=None,
- outputs=gallery)
- gallery.select(fn=on_select, inputs=list(tag_boxes.values()), outputs=[gallery, description, *tag_boxes.values()])
- revert_btn.click(fn=revert_desc, inputs=None, outputs=description)
- save_btn.click(fn=save_desc, inputs=description, outputs=[description_label, description, save_btn])
- for box in tag_boxes.values():
- box.change(fn=change_tag, inputs=list(tag_boxes.values()), outputs=description_label)
- app.load(
- fn=update_gallery,
- inputs=[check_from_latest, *filters],
- outputs=[gallery, info_label],
- preprocess=False
- ).then(
- fn=update_gallery2,
- inputs=None,
- outputs=gallery)
- app.queue().launch(
- server_name="0.0.0.0",
- inbrowser=True,
- share=False,
- server_port=7001,
- debug=True,
- quiet=True,
- )
diff --git a/requirements.txt b/requirements.txt
index 0dfd7514..cea511f1 100644
Binary files a/requirements.txt and b/requirements.txt differ
diff --git a/run-WebUI.bat b/run-WebUI.bat
deleted file mode 100644
index 8fbbe3db..00000000
--- a/run-WebUI.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-CHCP 65001
-@echo off
-python webui.py
-pause
\ No newline at end of file
diff --git a/run.bat b/run.bat
deleted file mode 100644
index 91904bc3..00000000
--- a/run.bat
+++ /dev/null
@@ -1,10 +0,0 @@
-@ECHO OFF
-chcp 65001
-if not exist "venv" (
- python -m venv venv
- call venv\Scripts\activate.bat
- pip install -i https://mirrors.aliyun.com/pypi/simple --upgrade -r requirements.txt
- ) else (
- call venv\Scripts\activate.bat
-)
-python run.py
\ No newline at end of file
diff --git a/run.py b/run.py
deleted file mode 100644
index 43bdcd91..00000000
--- a/run.py
+++ /dev/null
@@ -1,137 +0,0 @@
-import os
-import subprocess
-import zipfile
-import sys
-import requests
-from tqdm import tqdm
-
-
-def extract_files(zip_path, target_dir):
- """
- 解压
-
- Args:
- zip_path: 源ZIP压缩包路径(需确保是有效压缩包)
- target_dir: 目标文件夹路径(会自动创建不存在的目录)
- """
- # 打开ZIP压缩包(上下文管理器自动处理关闭)
- with zipfile.ZipFile(zip_path) as zip_ref:
- # 通过第一个文件路径推断顶层目录名(格式如:top_dir/)
- top_dir = zip_ref.namelist()[0].split("/")[0] + "/"
-
- # 遍历压缩包内所有文件条目
- for file in zip_ref.namelist():
- # 跳过目录条目,仅处理文件
- if file.startswith(top_dir) and not file.endswith("/"):
- # 截取顶层目录后的相对路径(如:sub_dir/file.txt)
- rel_path = file[len(top_dir) :]
-
- # 创建目标目录结构(含多级目录)
- os.makedirs(
- os.path.dirname(f"{target_dir}/{rel_path}"),
- exist_ok=True, # 忽略已存在目录的错误
- )
-
- # 读取压缩包内文件内容并写入目标路径
- with open(f"{target_dir}/{rel_path}", "wb") as f:
- f.write(zip_ref.read(file))
-
-
-def run_cmd(command: str, open_new_window: bool = True):
- """
- 运行 cmd 命令
-
- Args:
- command (str): 指定要运行的命令
- open_new_window (bool): 指定是否新建一个 cmd 窗口运行
- """
- if open_new_window:
- command = "start " + command
- subprocess.Popen(command, shell=True)
-
-
-def run_maimbot():
- run_cmd(r"napcat\NapCatWinBootMain.exe 10001", False)
- if not os.path.exists(r"mongodb\db"):
- os.makedirs(r"mongodb\db")
- run_cmd(r"mongodb\bin\mongod.exe --dbpath=" + os.getcwd() + r"\mongodb\db --port 27017")
- run_cmd("nb run")
-
-
-def install_mongodb():
- """
- 安装 MongoDB
- """
- print("下载 MongoDB")
- resp = requests.get(
- "https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-latest.zip",
- stream=True,
- )
- total = int(resp.headers.get("content-length", 0)) # 计算文件大小
- with (
- open("mongodb.zip", "w+b") as file,
- tqdm( # 展示下载进度条,并解压文件
- desc="mongodb.zip",
- total=total,
- unit="iB",
- unit_scale=True,
- unit_divisor=1024,
- ) as bar,
- ):
- for data in resp.iter_content(chunk_size=1024):
- size = file.write(data)
- bar.update(size)
- extract_files("mongodb.zip", "mongodb")
- print("MongoDB 下载完成")
- os.remove("mongodb.zip")
- choice = input("是否安装 MongoDB Compass?此软件可以以可视化的方式修改数据库,建议安装(Y/n)").upper()
- if choice == "Y" or choice == "":
- install_mongodb_compass()
-
-
-def install_mongodb_compass():
- run_cmd(r"powershell Start-Process powershell -Verb runAs 'Set-ExecutionPolicy RemoteSigned'")
- input("请在弹出的用户账户控制中点击“是”后按任意键继续安装")
- run_cmd(r"powershell mongodb\bin\Install-Compass.ps1")
- input("按任意键启动麦麦")
- input("如不需要启动此窗口可直接关闭,无需等待 Compass 安装完成")
- run_maimbot()
-
-
-def install_napcat():
- run_cmd("start https://github.com/NapNeko/NapCatQQ/releases", False)
- print("请检查弹出的浏览器窗口,点击**第一个**蓝色的“Win64无头” 下载 napcat")
- napcat_filename = input(
- "下载完成后请把文件复制到此文件夹,并将**不包含后缀的文件名**输入至此窗口,如 NapCat.32793.Shell:"
- )
- if napcat_filename[-4:] == ".zip":
- napcat_filename = napcat_filename[:-4]
- extract_files(napcat_filename + ".zip", "napcat")
- print("NapCat 安装完成")
- os.remove(napcat_filename + ".zip")
-
-
-if __name__ == "__main__":
- os.system("cls")
- if sys.version_info < (3, 9):
- print("当前 Python 版本过低,最低版本为 3.9,请更新 Python 版本")
- print("按任意键退出")
- input()
- exit(1)
- choice = input("请输入要进行的操作:\n1.首次安装\n2.运行麦麦\n")
- os.system("cls")
- if choice == "1":
- confirm = input("首次安装将下载并配置所需组件\n1.确认\n2.取消\n")
- if confirm == "1":
- install_napcat()
- install_mongodb()
- else:
- print("已取消安装")
- elif choice == "2":
- run_maimbot()
- choice = input("是否启动推理可视化?(未完善)(y/N)").upper()
- if choice == "Y":
- run_cmd(r"python src\gui\reasoning_gui.py")
- choice = input("是否启动记忆可视化?(未完善)(y/N)").upper()
- if choice == "Y":
- run_cmd(r"python src/plugins/memory_system/memory_manual_build.py")
diff --git a/run.sh b/run.sh
deleted file mode 100644
index d34552fc..00000000
--- a/run.sh
+++ /dev/null
@@ -1,571 +0,0 @@
-#!/bin/bash
-
-# 麦麦Bot一键安装脚本 by Cookie_987
-# 适用于Arch/Ubuntu 24.10/Debian 12/CentOS 9
-# 请小心使用任何一键脚本!
-
-INSTALLER_VERSION="0.0.3"
-LANG=C.UTF-8
-
-# 如无法访问GitHub请修改此处镜像地址
-GITHUB_REPO="https://ghfast.top/https://github.com/SengokuCola/MaiMBot.git"
-
-# 颜色输出
-GREEN="\e[32m"
-RED="\e[31m"
-RESET="\e[0m"
-
-# 需要的基本软件包
-
-declare -A REQUIRED_PACKAGES=(
- ["common"]="git sudo python3 curl gnupg"
- ["debian"]="python3-venv python3-pip"
- ["ubuntu"]="python3-venv python3-pip"
- ["centos"]="python3-pip"
- ["arch"]="python-virtualenv python-pip"
-)
-
-# 默认项目目录
-DEFAULT_INSTALL_DIR="/opt/maimbot"
-
-# 服务名称
-SERVICE_NAME="maimbot-daemon"
-SERVICE_NAME_WEB="maimbot-web"
-
-IS_INSTALL_MONGODB=false
-IS_INSTALL_NAPCAT=false
-IS_INSTALL_DEPENDENCIES=false
-
-# 检查是否已安装
-check_installed() {
- [[ -f /etc/systemd/system/${SERVICE_NAME}.service ]]
-}
-
-# 加载安装信息
-load_install_info() {
- if [[ -f /etc/maimbot_install.conf ]]; then
- source /etc/maimbot_install.conf
- else
- INSTALL_DIR="$DEFAULT_INSTALL_DIR"
- BRANCH="main"
- fi
-}
-
-# 显示管理菜单
-show_menu() {
- while true; do
- choice=$(whiptail --title "麦麦Bot管理菜单" --menu "请选择要执行的操作:" 15 60 7 \
- "1" "启动麦麦Bot" \
- "2" "停止麦麦Bot" \
- "3" "重启麦麦Bot" \
- "4" "启动WebUI" \
- "5" "停止WebUI" \
- "6" "重启WebUI" \
- "7" "更新麦麦Bot及其依赖" \
- "8" "切换分支" \
- "9" "更新配置文件" \
- "10" "退出" 3>&1 1>&2 2>&3)
-
- [[ $? -ne 0 ]] && exit 0
-
- case "$choice" in
- 1)
- systemctl start ${SERVICE_NAME}
- whiptail --msgbox "✅麦麦Bot已启动" 10 60
- ;;
- 2)
- systemctl stop ${SERVICE_NAME}
- whiptail --msgbox "🛑麦麦Bot已停止" 10 60
- ;;
- 3)
- systemctl restart ${SERVICE_NAME}
- whiptail --msgbox "🔄麦麦Bot已重启" 10 60
- ;;
- 4)
- systemctl start ${SERVICE_NAME_WEB}
- whiptail --msgbox "✅WebUI已启动" 10 60
- ;;
- 5)
- systemctl stop ${SERVICE_NAME_WEB}
- whiptail --msgbox "🛑WebUI已停止" 10 60
- ;;
- 6)
- systemctl restart ${SERVICE_NAME_WEB}
- whiptail --msgbox "🔄WebUI已重启" 10 60
- ;;
- 7)
- update_dependencies
- ;;
- 8)
- switch_branch
- ;;
- 9)
- update_config
- ;;
- 10)
- exit 0
- ;;
- *)
- whiptail --msgbox "无效选项!" 10 60
- ;;
- esac
- done
-}
-
-# 更新依赖
-update_dependencies() {
- cd "${INSTALL_DIR}/repo" || {
- whiptail --msgbox "🚫 无法进入安装目录!" 10 60
- return 1
- }
- if ! git pull origin "${BRANCH}"; then
- whiptail --msgbox "🚫 代码更新失败!" 10 60
- return 1
- fi
- source "${INSTALL_DIR}/venv/bin/activate"
- if ! pip install -r requirements.txt; then
- whiptail --msgbox "🚫 依赖安装失败!" 10 60
- deactivate
- return 1
- fi
- deactivate
- systemctl restart ${SERVICE_NAME}
- whiptail --msgbox "✅ 依赖已更新并重启服务!" 10 60
-}
-
-# 切换分支
-switch_branch() {
- new_branch=$(whiptail --inputbox "请输入要切换的分支名称:" 10 60 "${BRANCH}" 3>&1 1>&2 2>&3)
- [[ -z "$new_branch" ]] && {
- whiptail --msgbox "🚫 分支名称不能为空!" 10 60
- return 1
- }
-
- cd "${INSTALL_DIR}/repo" || {
- whiptail --msgbox "🚫 无法进入安装目录!" 10 60
- return 1
- }
-
- if ! git ls-remote --exit-code --heads origin "${new_branch}" >/dev/null 2>&1; then
- whiptail --msgbox "🚫 分支 ${new_branch} 不存在!" 10 60
- return 1
- fi
-
- if ! git checkout "${new_branch}"; then
- whiptail --msgbox "🚫 分支切换失败!" 10 60
- return 1
- fi
-
- if ! git pull origin "${new_branch}"; then
- whiptail --msgbox "🚫 代码拉取失败!" 10 60
- return 1
- fi
-
- source "${INSTALL_DIR}/venv/bin/activate"
- pip install -r requirements.txt
- deactivate
-
- sed -i "s/^BRANCH=.*/BRANCH=${new_branch}/" /etc/maimbot_install.conf
- BRANCH="${new_branch}"
- check_eula
- systemctl restart ${SERVICE_NAME}
- whiptail --msgbox "✅ 已切换到分支 ${new_branch} 并重启服务!" 10 60
-}
-
-# 更新配置文件
-update_config() {
- cd "${INSTALL_DIR}/repo" || {
- whiptail --msgbox "🚫 无法进入安装目录!" 10 60
- return 1
- }
- if [[ -f config/bot_config.toml ]]; then
- cp config/bot_config.toml config/bot_config.toml.bak
- whiptail --msgbox "📁 原配置文件已备份为 bot_config.toml.bak" 10 60
- source "${INSTALL_DIR}/venv/bin/activate"
- python3 config/auto_update.py
- deactivate
- whiptail --msgbox "🆕 已更新配置文件,请重启麦麦Bot!" 10 60
- return 0
- else
- whiptail --msgbox "🚫 未找到配置文件 bot_config.toml\n 请先运行一次麦麦Bot" 10 60
- return 1
- fi
-}
-
-check_eula() {
- # 首先计算当前EULA的MD5值
- current_md5=$(md5sum "${INSTALL_DIR}/repo/EULA.md" | awk '{print $1}')
-
- # 首先计算当前隐私条款文件的哈希值
- current_md5_privacy=$(md5sum "${INSTALL_DIR}/repo/PRIVACY.md" | awk '{print $1}')
-
- # 如果当前的md5值为空,则直接返回
- if [[ -z $current_md5 || -z $current_md5_privacy ]]; then
- whiptail --msgbox "🚫 未找到使用协议\n 请检查PRIVACY.md和EULA.md是否存在" 10 60
- fi
-
- # 检查eula.confirmed文件是否存在
- if [[ -f ${INSTALL_DIR}/repo/eula.confirmed ]]; then
- # 如果存在则检查其中包含的md5与current_md5是否一致
- confirmed_md5=$(cat ${INSTALL_DIR}/repo/eula.confirmed)
- else
- confirmed_md5=""
- fi
-
- # 检查privacy.confirmed文件是否存在
- if [[ -f ${INSTALL_DIR}/repo/privacy.confirmed ]]; then
- # 如果存在则检查其中包含的md5与current_md5是否一致
- confirmed_md5_privacy=$(cat ${INSTALL_DIR}/repo/privacy.confirmed)
- else
- confirmed_md5_privacy=""
- fi
-
- # 如果EULA或隐私条款有更新,提示用户重新确认
- if [[ $current_md5 != $confirmed_md5 || $current_md5_privacy != $confirmed_md5_privacy ]]; then
- whiptail --title "📜 使用协议更新" --yesno "检测到麦麦Bot EULA或隐私条款已更新。\nhttps://github.com/SengokuCola/MaiMBot/blob/main/EULA.md\nhttps://github.com/SengokuCola/MaiMBot/blob/main/PRIVACY.md\n\n您是否同意上述协议? \n\n " 12 70
- if [[ $? -eq 0 ]]; then
- echo -n $current_md5 > ${INSTALL_DIR}/repo/eula.confirmed
- echo -n $current_md5_privacy > ${INSTALL_DIR}/repo/privacy.confirmed
- else
- exit 1
- fi
- fi
-
-}
-
-# ----------- 主安装流程 -----------
-run_installation() {
- # 1/6: 检测是否安装 whiptail
- if ! command -v whiptail &>/dev/null; then
- echo -e "${RED}[1/6] whiptail 未安装,正在安装...${RESET}"
-
- # 这里的多系统适配很神人,但是能用()
-
- apt update && apt install -y whiptail
-
- pacman -S --noconfirm libnewt
-
- yum install -y newt
- fi
-
- # 协议确认
- if ! (whiptail --title "ℹ️ [1/6] 使用协议" --yes-button "我同意" --no-button "我拒绝" --yesno "使用麦麦Bot及此脚本前请先阅读EULA协议及隐私协议\nhttps://github.com/SengokuCola/MaiMBot/blob/main/EULA.md\nhttps://github.com/SengokuCola/MaiMBot/blob/main/PRIVACY.md\n\n您是否同意上述协议?" 12 70); then
- exit 1
- fi
-
- # 欢迎信息
- whiptail --title "[2/6] 欢迎使用麦麦Bot一键安装脚本 by Cookie987" --msgbox "检测到您未安装麦麦Bot,将自动进入安装流程,安装完成后再次运行此脚本即可进入管理菜单。\n\n项目处于活跃开发阶段,代码可能随时更改\n文档未完善,有问题可以提交 Issue 或者 Discussion\nQQ机器人存在被限制风险,请自行了解,谨慎使用\n由于持续迭代,可能存在一些已知或未知的bug\n由于开发中,可能消耗较多token\n\n本脚本可能更新不及时,如遇到bug请优先尝试手动部署以确定是否为脚本问题" 17 60
-
- # 系统检查
- check_system() {
- if [[ "$(id -u)" -ne 0 ]]; then
- whiptail --title "🚫 权限不足" --msgbox "请使用 root 用户运行此脚本!\n执行方式: sudo bash $0" 10 60
- exit 1
- fi
-
- if [[ -f /etc/os-release ]]; then
- source /etc/os-release
- if [[ "$ID" == "debian" && "$VERSION_ID" == "12" ]]; then
- return
- elif [[ "$ID" == "ubuntu" && "$VERSION_ID" == "24.10" ]]; then
- return
- elif [[ "$ID" == "centos" && "$VERSION_ID" == "9" ]]; then
- return
- elif [[ "$ID" == "arch" ]]; then
- whiptail --title "⚠️ 兼容性警告" --msgbox "NapCat无可用的 Arch Linux 官方安装方法,将无法自动安装NapCat。\n\n您可尝试在AUR中搜索相关包。" 10 60
- whiptail --title "⚠️ 兼容性警告" --msgbox "MongoDB无可用的 Arch Linux 官方安装方法,将无法自动安装MongoDB。\n\n您可尝试在AUR中搜索相关包。" 10 60
- return
- else
- whiptail --title "🚫 不支持的系统" --msgbox "此脚本仅支持 Arch/Debian 12 (Bookworm)/Ubuntu 24.10 (Oracular Oriole)/CentOS9!\n当前系统: $PRETTY_NAME\n安装已终止。" 10 60
- exit 1
- fi
- else
- whiptail --title "⚠️ 无法检测系统" --msgbox "无法识别系统版本,安装已终止。" 10 60
- exit 1
- fi
- }
- check_system
-
- # 设置包管理器
- case "$ID" in
- debian|ubuntu)
- PKG_MANAGER="apt"
- ;;
- centos)
- PKG_MANAGER="yum"
- ;;
- arch)
- # 添加arch包管理器
- PKG_MANAGER="pacman"
- ;;
- esac
-
- # 检查MongoDB
- check_mongodb() {
- if command -v mongod &>/dev/null; then
- MONGO_INSTALLED=true
- else
- MONGO_INSTALLED=false
- fi
- }
- check_mongodb
-
- # 检查NapCat
- check_napcat() {
- if command -v napcat &>/dev/null; then
- NAPCAT_INSTALLED=true
- else
- NAPCAT_INSTALLED=false
- fi
- }
- check_napcat
-
- # 安装必要软件包
- install_packages() {
- missing_packages=()
- # 检查 common 及当前系统专属依赖
- for package in ${REQUIRED_PACKAGES["common"]} ${REQUIRED_PACKAGES["$ID"]}; do
- case "$PKG_MANAGER" in
- apt)
- dpkg -s "$package" &>/dev/null || missing_packages+=("$package")
- ;;
- yum)
- rpm -q "$package" &>/dev/null || missing_packages+=("$package")
- ;;
- pacman)
- pacman -Qi "$package" &>/dev/null || missing_packages+=("$package")
- ;;
- esac
- done
-
- if [[ ${#missing_packages[@]} -gt 0 ]]; then
- whiptail --title "📦 [3/6] 依赖检查" --yesno "以下软件包缺失:\n${missing_packages[*]}\n\n是否自动安装?" 10 60
- if [[ $? -eq 0 ]]; then
- IS_INSTALL_DEPENDENCIES=true
- else
- whiptail --title "⚠️ 注意" --yesno "未安装某些依赖,可能影响运行!\n是否继续?" 10 60 || exit 1
- fi
- fi
- }
- install_packages
-
- # 安装MongoDB
- install_mongodb() {
- [[ $MONGO_INSTALLED == true ]] && return
- whiptail --title "📦 [3/6] 软件包检查" --yesno "检测到未安装MongoDB,是否安装?\n如果您想使用远程数据库,请跳过此步。" 10 60 && {
- IS_INSTALL_MONGODB=true
- }
- }
-
- # 仅在非Arch系统上安装MongoDB
- [[ "$ID" != "arch" ]] && install_mongodb
-
-
- # 安装NapCat
- install_napcat() {
- [[ $NAPCAT_INSTALLED == true ]] && return
- whiptail --title "📦 [3/6] 软件包检查" --yesno "检测到未安装NapCat,是否安装?\n如果您想使用远程NapCat,请跳过此步。" 10 60 && {
- IS_INSTALL_NAPCAT=true
- }
- }
-
- # 仅在非Arch系统上安装NapCat
- [[ "$ID" != "arch" ]] && install_napcat
-
- # Python版本检查
- check_python() {
- PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
- if ! python3 -c "import sys; exit(0) if sys.version_info >= (3,9) else exit(1)"; then
- whiptail --title "⚠️ [4/6] Python 版本过低" --msgbox "检测到 Python 版本为 $PYTHON_VERSION,需要 3.9 或以上!\n请升级 Python 后重新运行本脚本。" 10 60
- exit 1
- fi
- }
-
- # 如果没安装python则不检查python版本
- if command -v python3 &>/dev/null; then
- check_python
- fi
-
-
- # 选择分支
- choose_branch() {
- BRANCH=$(whiptail --title "🔀 [5/6] 选择麦麦Bot分支" --menu "请选择要安装的麦麦Bot分支:" 15 60 2 \
- "main" "稳定版本(推荐,供下载使用)" \
- "main-fix" "生产环境紧急修复" 3>&1 1>&2 2>&3)
- [[ -z "$BRANCH" ]] && BRANCH="main"
- }
- choose_branch
-
- # 选择安装路径
- choose_install_dir() {
- INSTALL_DIR=$(whiptail --title "📂 [6/6] 选择安装路径" --inputbox "请输入麦麦Bot的安装目录:" 10 60 "$DEFAULT_INSTALL_DIR" 3>&1 1>&2 2>&3)
- [[ -z "$INSTALL_DIR" ]] && {
- whiptail --title "⚠️ 取消输入" --yesno "未输入安装路径,是否退出安装?" 10 60 && exit 1
- INSTALL_DIR="$DEFAULT_INSTALL_DIR"
- }
- }
- choose_install_dir
-
- # 确认安装
- confirm_install() {
- local confirm_msg="请确认以下信息:\n\n"
- confirm_msg+="📂 安装麦麦Bot到: $INSTALL_DIR\n"
- confirm_msg+="🔀 分支: $BRANCH\n"
- [[ $IS_INSTALL_DEPENDENCIES == true ]] && confirm_msg+="📦 安装依赖:${missing_packages[@]}\n"
- [[ $IS_INSTALL_MONGODB == true || $IS_INSTALL_NAPCAT == true ]] && confirm_msg+="📦 安装额外组件:\n"
-
- [[ $IS_INSTALL_MONGODB == true ]] && confirm_msg+=" - MongoDB\n"
- [[ $IS_INSTALL_NAPCAT == true ]] && confirm_msg+=" - NapCat\n"
- confirm_msg+="\n注意:本脚本默认使用ghfast.top为GitHub进行加速,如不想使用请手动修改脚本开头的GITHUB_REPO变量。"
-
- whiptail --title "🔧 安装确认" --yesno "$confirm_msg" 20 60 || exit 1
- }
- confirm_install
-
- # 开始安装
- echo -e "${GREEN}安装${missing_packages[@]}...${RESET}"
-
- if [[ $IS_INSTALL_DEPENDENCIES == true ]]; then
- case "$PKG_MANAGER" in
- apt)
- apt update && apt install -y "${missing_packages[@]}"
- ;;
- yum)
- yum install -y "${missing_packages[@]}" --nobest
- ;;
- pacman)
- pacman -S --noconfirm "${missing_packages[@]}"
- ;;
- esac
- fi
-
- if [[ $IS_INSTALL_MONGODB == true ]]; then
- echo -e "${GREEN}安装 MongoDB...${RESET}"
- case "$ID" in
- debian)
- curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
- echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] http://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list
- apt update
- apt install -y mongodb-org
- systemctl enable --now mongod
- ;;
- ubuntu)
- curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
- echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] http://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list
- apt update
- apt install -y mongodb-org
- systemctl enable --now mongod
- ;;
- centos)
- cat > /etc/yum.repos.d/mongodb-org-8.0.repo < repo/eula.confirmed
- echo -n $current_md5_privacy > repo/privacy.confirmed
-
- echo -e "${GREEN}创建系统服务...${RESET}"
- cat > /etc/systemd/system/${SERVICE_NAME}.service < /etc/systemd/system/${SERVICE_NAME_WEB}.service < /etc/maimbot_install.conf
- echo "INSTALL_DIR=${INSTALL_DIR}" >> /etc/maimbot_install.conf
- echo "BRANCH=${BRANCH}" >> /etc/maimbot_install.conf
-
- whiptail --title "🎉 安装完成" --msgbox "麦麦Bot安装完成!\n已创建系统服务:${SERVICE_NAME},${SERVICE_NAME_WEB}\n\n使用以下命令管理服务:\n启动服务:systemctl start ${SERVICE_NAME}\n查看状态:systemctl status ${SERVICE_NAME}" 14 60
-}
-
-# ----------- 主执行流程 -----------
-# 检查root权限
-[[ $(id -u) -ne 0 ]] && {
- echo -e "${RED}请使用root用户运行此脚本!${RESET}"
- exit 1
-}
-
-# 如果已安装显示菜单,并检查协议是否更新
-if check_installed; then
- load_install_info
- check_eula
- show_menu
-else
- run_installation
- # 安装完成后询问是否启动
- if whiptail --title "安装完成" --yesno "是否立即启动麦麦Bot服务?" 10 60; then
- systemctl start ${SERVICE_NAME}
- whiptail --msgbox "✅ 服务已启动!\n使用 systemctl status ${SERVICE_NAME} 查看状态" 10 60
- fi
-fi
diff --git a/run_memory_vis.bat b/run_memory_vis.bat
deleted file mode 100644
index b1feb0cb..00000000
--- a/run_memory_vis.bat
+++ /dev/null
@@ -1,29 +0,0 @@
-@echo on
-chcp 65001 > nul
-set /p CONDA_ENV="请输入要激活的 conda 环境名称: "
-call conda activate %CONDA_ENV%
-if errorlevel 1 (
- echo 激活 conda 环境失败
- pause
- exit /b 1
-)
-echo Conda 环境 "%CONDA_ENV%" 激活成功
-
-set /p OPTION="请选择运行选项 (1: 运行全部绘制, 2: 运行简单绘制): "
-if "%OPTION%"=="1" (
- python src/plugins/memory_system/memory_manual_build.py
-) else if "%OPTION%"=="2" (
- python src/plugins/memory_system/draw_memory.py
-) else (
- echo 无效的选项
- pause
- exit /b 1
-)
-
-if errorlevel 1 (
- echo 命令执行失败,错误代码 %errorlevel%
- pause
- exit /b 1
-)
-echo 脚本成功完成
-pause
\ No newline at end of file
diff --git a/script/run_db.bat b/script/run_db.bat
deleted file mode 100644
index 1741dfd3..00000000
--- a/script/run_db.bat
+++ /dev/null
@@ -1 +0,0 @@
-mongod --dbpath="mongodb" --port 27017
\ No newline at end of file
diff --git a/script/run_maimai.bat b/script/run_maimai.bat
deleted file mode 100644
index 3a099fd7..00000000
--- a/script/run_maimai.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-chcp 65001
-call conda activate maimbot
-cd .
-
-REM 执行nb run命令
-nb run
-pause
\ No newline at end of file
diff --git a/script/run_thingking.bat b/script/run_thingking.bat
deleted file mode 100644
index 0806e46e..00000000
--- a/script/run_thingking.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@REM call conda activate niuniu
-cd ../src\gui
-start /b ../../venv/scripts/python.exe reasoning_gui.py
-exit
-
diff --git a/script/run_windows.bat b/script/run_windows.bat
deleted file mode 100644
index bea397dd..00000000
--- a/script/run_windows.bat
+++ /dev/null
@@ -1,68 +0,0 @@
-@echo off
-setlocal enabledelayedexpansion
-chcp 65001
-
-REM 修正路径获取逻辑
-cd /d "%~dp0" || (
- echo 错误:切换目录失败
- exit /b 1
-)
-
-if not exist "venv\" (
- echo 正在初始化虚拟环境...
-
- where python >nul 2>&1
- if %errorlevel% neq 0 (
- echo 未找到Python解释器
- exit /b 1
- )
-
- for /f "tokens=2" %%a in ('python --version 2^>^&1') do set version=%%a
- for /f "tokens=1,2 delims=." %%b in ("!version!") do (
- set major=%%b
- set minor=%%c
- )
-
- if !major! lss 3 (
- echo 需要Python大于等于3.0,当前版本 !version!
- exit /b 1
- )
-
- if !major! equ 3 if !minor! lss 9 (
- echo 需要Python大于等于3.9,当前版本 !version!
- exit /b 1
- )
-
- echo 正在安装virtualenv...
- python -m pip install virtualenv || (
- echo virtualenv安装失败
- exit /b 1
- )
-
- echo 正在创建虚拟环境...
- python -m virtualenv venv || (
- echo 虚拟环境创建失败
- exit /b 1
- )
-
- call venv\Scripts\activate.bat
-
-) else (
- call venv\Scripts\activate.bat
-)
-
-echo 正在更新依赖...
-pip install -r requirements.txt
-
-echo 当前代理设置:
-echo HTTP_PROXY=%HTTP_PROXY%
-echo HTTPS_PROXY=%HTTPS_PROXY%
-
-set HTTP_PROXY=
-set HTTPS_PROXY=
-echo 代理已取消。
-
-set no_proxy=0.0.0.0/32
-
-call nb run
-pause
\ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 6222dbb5..00000000
--- a/setup.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from setuptools import find_packages, setup
-
-setup(
- name="maimai-bot",
- version="0.1",
- packages=find_packages(),
- install_requires=[
- "python-dotenv",
- "pymongo",
- ],
-)
diff --git a/webui.py b/webui.py
deleted file mode 100644
index cffd9904..00000000
--- a/webui.py
+++ /dev/null
@@ -1,2246 +0,0 @@
-import warnings
-import gradio as gr
-import os
-import toml
-import signal
-import sys
-import requests
-import socket
-try:
- from src.common.logger import get_module_logger
-
- logger = get_module_logger("webui")
-except ImportError:
- from loguru import logger
-
- # 检查并创建日志目录
- log_dir = "logs/webui"
- if not os.path.exists(log_dir):
- os.makedirs(log_dir, exist_ok=True)
- # 配置控制台输出格式
- logger.remove() # 移除默认的处理器
- logger.add(sys.stderr, format="{time:MM-DD HH:mm} | webui | {message}") # 添加控制台输出
- logger.add("logs/webui/{time:YYYY-MM-DD}.log", rotation="00:00", format="{time:MM-DD HH:mm} | webui | {message}")
- logger.warning("检测到src.common.logger并未导入,将使用默认loguru作为日志记录器")
- logger.warning("如果你是用的是低版本(0.5.13)麦麦,请忽略此警告")
-import shutil
-import ast
-from packaging import version
-from decimal import Decimal
-# 忽略 gradio 版本警告
-warnings.filterwarnings("ignore", message="IMPORTANT: You are using gradio version.*")
-
-def signal_handler(signum, frame):
- """处理 Ctrl+C 信号"""
- logger.info("收到终止信号,正在关闭 Gradio 服务器...")
- sys.exit(0)
-
-
-# 注册信号处理器
-signal.signal(signal.SIGINT, signal_handler)
-
-is_share = False
-debug = False
-
-def init_model_pricing():
- """初始化模型价格配置"""
- model_list = [
- "llm_reasoning",
- "llm_reasoning_minor",
- "llm_normal",
- "llm_topic_judge",
- "llm_summary_by_topic",
- "llm_emotion_judge",
- "vlm",
- "embedding",
- "moderation"
- ]
-
- for model in model_list:
- if model in config_data["model"]:
- # 检查是否已有pri_in和pri_out配置
- has_pri_in = "pri_in" in config_data["model"][model]
- has_pri_out = "pri_out" in config_data["model"][model]
-
- # 只在缺少配置时添加默认值
- if not has_pri_in:
- config_data["model"][model]["pri_in"] = 0
- logger.info(f"为模型 {model} 添加默认输入价格配置")
- if not has_pri_out:
- config_data["model"][model]["pri_out"] = 0
- logger.info(f"为模型 {model} 添加默认输出价格配置")
-
-# ==============================================
-# env环境配置文件读取部分
-def parse_env_config(config_file):
- """
- 解析配置文件并将配置项存储到相应的变量中(变量名以env_为前缀)。
- """
- env_variables = {}
-
- # 读取配置文件
- with open(config_file, "r", encoding="utf-8") as f:
- lines = f.readlines()
-
- # 逐行处理配置
- for line in lines:
- line = line.strip()
- # 忽略空行和注释行
- if not line or line.startswith("#"):
- continue
-
- # 处理行尾注释
- if "#" in line:
- line = line.split("#")[0].strip()
-
- # 拆分键值对
- key, value = line.split("=", 1)
-
- # 去掉空格并去除两端引号(如果有的话)
- key = key.strip()
- value = value.strip().strip('"').strip("'")
-
- # 将配置项存入以env_为前缀的变量
- env_variable = f"env_{key}"
- env_variables[env_variable] = value
-
- # 动态创建环境变量
- os.environ[env_variable] = value
-
- return env_variables
-
-
-# 检查配置文件是否存在
-if not os.path.exists("config/bot_config.toml"):
- logger.error("配置文件 bot_config.toml 不存在,请检查配置文件路径")
- raise FileNotFoundError("配置文件 bot_config.toml 不存在,请检查配置文件路径")
-else:
- config_data = toml.load("config/bot_config.toml")
- init_model_pricing()
-
-if not os.path.exists(".env"):
- logger.error("环境配置文件 .env 不存在,请检查配置文件路径")
- raise FileNotFoundError("环境配置文件 .env 不存在,请检查配置文件路径")
-else:
- # 载入env文件并解析
- env_config_file = ".env" # 配置文件路径
- env_config_data = parse_env_config(env_config_file)
-
-# 增加最低支持版本
-MIN_SUPPORT_VERSION = version.parse("0.0.8")
-MIN_SUPPORT_MAIMAI_VERSION = version.parse("0.5.13")
-
-if "inner" in config_data:
- CONFIG_VERSION = config_data["inner"]["version"]
- PARSED_CONFIG_VERSION = version.parse(CONFIG_VERSION)
- if PARSED_CONFIG_VERSION < MIN_SUPPORT_VERSION:
- logger.error("您的麦麦版本过低!!已经不再支持,请更新到最新版本!!")
- logger.error("最低支持的麦麦版本:" + str(MIN_SUPPORT_MAIMAI_VERSION))
- raise Exception("您的麦麦版本过低!!已经不再支持,请更新到最新版本!!")
-else:
- logger.error("您的麦麦版本过低!!已经不再支持,请更新到最新版本!!")
- logger.error("最低支持的麦麦版本:" + str(MIN_SUPPORT_MAIMAI_VERSION))
- raise Exception("您的麦麦版本过低!!已经不再支持,请更新到最新版本!!")
-
-# 添加麦麦版本
-
-if "mai_version" in config_data:
- MAI_VERSION = version.parse(str(config_data["mai_version"]["version"]))
- logger.info("您的麦麦版本为:" + str(MAI_VERSION))
-else:
- logger.info("检测到配置文件中并没有定义麦麦版本,将使用默认版本")
- MAI_VERSION = version.parse("0.5.15")
- logger.info("您的麦麦版本为:" + str(MAI_VERSION))
-
-# 增加在线状态更新版本
-HAVE_ONLINE_STATUS_VERSION = version.parse("0.0.9")
-# 增加日程设置重构版本
-SCHEDULE_CHANGED_VERSION = version.parse("0.0.11")
-
-# 定义意愿模式可选项
-WILLING_MODE_CHOICES = [
- "classical",
- "dynamic",
- "custom",
-]
-
-
-# 添加WebUI配置文件版本
-WEBUI_VERSION = version.parse("0.0.11")
-
-
-
-
-
-# env环境配置文件保存函数
-def save_to_env_file(env_variables, filename=".env"):
- """
- 将修改后的变量保存到指定的.env文件中,并在第一次保存前备份文件(如果备份文件不存在)。
- """
- backup_filename = f"{filename}.bak"
-
- # 如果备份文件不存在,则备份原文件
- if not os.path.exists(backup_filename):
- if os.path.exists(filename):
- logger.info(f"{filename} 已存在,正在备份到 {backup_filename}...")
- shutil.copy(filename, backup_filename) # 备份文件
- logger.success(f"文件已备份到 {backup_filename}")
- else:
- logger.warning(f"{filename} 不存在,无法进行备份。")
-
- # 保存新配置
- with open(filename, "w", encoding="utf-8") as f:
- for var, value in env_variables.items():
- f.write(f"{var[4:]}={value}\n") # 移除env_前缀
- logger.info(f"配置已保存到 {filename}")
-
-
-# 载入env文件并解析
-env_config_file = ".env" # 配置文件路径
-env_config_data = parse_env_config(env_config_file)
-if "env_VOLCENGINE_BASE_URL" in env_config_data:
- logger.info("VOLCENGINE_BASE_URL 已存在,使用默认值")
- env_config_data["env_VOLCENGINE_BASE_URL"] = "https://ark.cn-beijing.volces.com/api/v3"
-else:
- logger.info("VOLCENGINE_BASE_URL 不存在,已创建并使用默认值")
- env_config_data["env_VOLCENGINE_BASE_URL"] = "https://ark.cn-beijing.volces.com/api/v3"
-
-if "env_VOLCENGINE_KEY" in env_config_data:
- logger.info("VOLCENGINE_KEY 已存在,保持不变")
-else:
- logger.info("VOLCENGINE_KEY 不存在,已创建并使用默认值")
- env_config_data["env_VOLCENGINE_KEY"] = "volc_key"
-save_to_env_file(env_config_data, env_config_file)
-
-
-def parse_model_providers(env_vars):
- """
- 从环境变量中解析模型提供商列表
- 参数:
- env_vars: 包含环境变量的字典
- 返回:
- list: 模型提供商列表
- """
- providers = []
- for key in env_vars.keys():
- if key.startswith("env_") and key.endswith("_BASE_URL"):
- # 提取中间部分作为提供商名称
- provider = key[4:-9] # 移除"env_"前缀和"_BASE_URL"后缀
- providers.append(provider)
- return providers
-
-
-def add_new_provider(provider_name, current_providers):
- """
- 添加新的提供商到列表中
- 参数:
- provider_name: 新的提供商名称
- current_providers: 当前的提供商列表
- 返回:
- tuple: (更新后的提供商列表, 更新后的下拉列表选项)
- """
- if not provider_name or provider_name in current_providers:
- return current_providers, gr.update(choices=current_providers)
-
- # 添加新的提供商到环境变量中
- env_config_data[f"env_{provider_name}_BASE_URL"] = ""
- env_config_data[f"env_{provider_name}_KEY"] = ""
-
- # 更新提供商列表
- updated_providers = current_providers + [provider_name]
-
- # 保存到环境文件
- save_to_env_file(env_config_data)
-
- return updated_providers, gr.update(choices=updated_providers)
-
-
-# 从环境变量中解析并更新提供商列表
-MODEL_PROVIDER_LIST = parse_model_providers(env_config_data)
-
-# env读取保存结束
-# ==============================================
-
-# 获取在线麦麦数量
-
-
-def get_online_maimbot(url="http://hyybuth.xyz:10058/api/clients/details", timeout=10):
- """
- 获取在线客户端详细信息。
-
- 参数:
- url (str): API 请求地址,默认值为 "http://hyybuth.xyz:10058/api/clients/details"。
- timeout (int): 请求超时时间,默认值为 10 秒。
-
- 返回:
- dict: 解析后的 JSON 数据。
-
- 异常:
- 如果请求失败或数据格式不正确,将返回 None 并记录错误信息。
- """
- try:
- response = requests.get(url, timeout=timeout)
- # 检查 HTTP 响应状态码是否为 200
- if response.status_code == 200:
- # 尝试解析 JSON 数据
- return response.json()
- else:
- logger.error(f"请求失败,状态码: {response.status_code}")
- return None
- except requests.exceptions.Timeout:
- logger.error("请求超时,请检查网络连接或增加超时时间。")
- return None
- except requests.exceptions.ConnectionError:
- logger.error("连接错误,请检查网络或API地址是否正确。")
- return None
- except ValueError: # 包括 json.JSONDecodeError
- logger.error("无法解析返回的JSON数据,请检查API返回内容。")
- return None
-
-
-online_maimbot_data = get_online_maimbot()
-
-
-# ==============================================
-# env环境文件中插件修改更新函数
-def add_item(new_item, current_list):
- updated_list = current_list.copy()
- if new_item.strip():
- updated_list.append(new_item.strip())
- return [
- updated_list, # 更新State
- "\n".join(updated_list), # 更新TextArea
- gr.update(choices=updated_list), # 更新Dropdown
- ", ".join(updated_list), # 更新最终结果
- ]
-
-
-def delete_item(selected_item, current_list):
- updated_list = current_list.copy()
- if selected_item in updated_list:
- updated_list.remove(selected_item)
- return [updated_list, "\n".join(updated_list), gr.update(choices=updated_list), ", ".join(updated_list)]
-
-
-def add_int_item(new_item, current_list):
- updated_list = current_list.copy()
- stripped_item = new_item.strip()
- if stripped_item:
- try:
- item = int(stripped_item)
- updated_list.append(item)
- except ValueError:
- pass
- return [
- updated_list, # 更新State
- "\n".join(map(str, updated_list)), # 更新TextArea
- gr.update(choices=updated_list), # 更新Dropdown
- ", ".join(map(str, updated_list)), # 更新最终结果
- ]
-
-
-def delete_int_item(selected_item, current_list):
- updated_list = current_list.copy()
- if selected_item in updated_list:
- updated_list.remove(selected_item)
- return [
- updated_list,
- "\n".join(map(str, updated_list)),
- gr.update(choices=updated_list),
- ", ".join(map(str, updated_list)),
- ]
-
-
-# env文件中插件值处理函数
-def parse_list_str(input_str):
- """
- 将形如["src2.plugins.chat"]的字符串解析为Python列表
- parse_list_str('["src2.plugins.chat"]')
- ['src2.plugins.chat']
- parse_list_str("['plugin1', 'plugin2']")
- ['plugin1', 'plugin2']
- """
- try:
- return ast.literal_eval(input_str.strip())
- except (ValueError, SyntaxError):
- # 处理不符合Python列表格式的字符串
- cleaned = input_str.strip(" []") # 去除方括号
- return [item.strip(" '\"") for item in cleaned.split(",") if item.strip()]
-
-
-def format_list_to_str(lst):
- """
- 将Python列表转换为形如["src2.plugins.chat"]的字符串格式
- format_list_to_str(['src2.plugins.chat'])
- '["src2.plugins.chat"]'
- format_list_to_str([1, "two", 3.0])
- '[1, "two", 3.0]'
- """
- resarr = lst.split(", ")
- res = ""
- for items in resarr:
- temp = '"' + str(items) + '"'
- res += temp + ","
-
- res = res[:-1]
- return "[" + res + "]"
-
-
-# env保存函数
-def save_trigger(
- server_address,
- server_port,
- final_result_list,
- t_mongodb_host,
- t_mongodb_port,
- t_mongodb_database_name,
- t_console_log_level,
- t_file_log_level,
- t_default_console_log_level,
- t_default_file_log_level,
- t_api_provider,
- t_api_base_url,
- t_api_key,
-):
- final_result_lists = format_list_to_str(final_result_list)
- env_config_data["env_HOST"] = server_address
- env_config_data["env_PORT"] = server_port
- env_config_data["env_PLUGINS"] = final_result_lists
- env_config_data["env_MONGODB_HOST"] = t_mongodb_host
- env_config_data["env_MONGODB_PORT"] = t_mongodb_port
- env_config_data["env_DATABASE_NAME"] = t_mongodb_database_name
-
- # 保存日志配置
- env_config_data["env_CONSOLE_LOG_LEVEL"] = t_console_log_level
- env_config_data["env_FILE_LOG_LEVEL"] = t_file_log_level
- env_config_data["env_DEFAULT_CONSOLE_LOG_LEVEL"] = t_default_console_log_level
- env_config_data["env_DEFAULT_FILE_LOG_LEVEL"] = t_default_file_log_level
-
- # 保存选中的API提供商的配置
- env_config_data[f"env_{t_api_provider}_BASE_URL"] = t_api_base_url
- env_config_data[f"env_{t_api_provider}_KEY"] = t_api_key
-
- save_to_env_file(env_config_data)
- logger.success("配置已保存到 .env 文件中")
- return "配置已保存"
-
-
-def update_api_inputs(provider):
- """
- 根据选择的提供商更新Base URL和API Key输入框的值
- """
- base_url = env_config_data.get(f"env_{provider}_BASE_URL", "")
- api_key = env_config_data.get(f"env_{provider}_KEY", "")
- return base_url, api_key
-
-
-# 绑定下拉列表的change事件
-
-
-# ==============================================
-
-
-# ==============================================
-# 主要配置文件保存函数
-def save_config_to_file(t_config_data):
- filename = "config/bot_config.toml"
- backup_filename = f"{filename}.bak"
- if not os.path.exists(backup_filename):
- if os.path.exists(filename):
- logger.info(f"{filename} 已存在,正在备份到 {backup_filename}...")
- shutil.copy(filename, backup_filename) # 备份文件
- logger.success(f"文件已备份到 {backup_filename}")
- else:
- logger.warning(f"{filename} 不存在,无法进行备份。")
-
- with open(filename, "w", encoding="utf-8") as f:
- toml.dump(t_config_data, f)
- logger.success("配置已保存到 bot_config.toml 文件中")
-
-
-def save_bot_config(t_qqbot_qq, t_nickname, t_nickname_final_result):
- config_data["bot"]["qq"] = int(t_qqbot_qq)
- config_data["bot"]["nickname"] = t_nickname
- config_data["bot"]["alias_names"] = t_nickname_final_result
- save_config_to_file(config_data)
- logger.info("Bot配置已保存")
- return "Bot配置已保存"
-
-
-# 监听滑块的值变化,确保总和不超过 1,并显示警告
-def adjust_personality_greater_probabilities(
- t_personality_1_probability, t_personality_2_probability, t_personality_3_probability
-):
- total = (
- Decimal(str(t_personality_1_probability))
- + Decimal(str(t_personality_2_probability))
- + Decimal(str(t_personality_3_probability))
- )
- if total > Decimal("1.0"):
- warning_message = (
- f"警告: 人格1、人格2和人格3的概率总和为 {float(total):.2f},超过了 1.0!请调整滑块使总和等于 1.0。"
- )
- return warning_message
- return "" # 没有警告时返回空字符串
-
-
-def adjust_personality_less_probabilities(
- t_personality_1_probability, t_personality_2_probability, t_personality_3_probability
-):
- total = (
- Decimal(str(t_personality_1_probability))
- + Decimal(str(t_personality_2_probability))
- + Decimal(str(t_personality_3_probability))
- )
- if total < Decimal("1.0"):
- warning_message = (
- f"警告: 人格1、人格2和人格3的概率总和为 {float(total):.2f},小于 1.0!请调整滑块使总和等于 1.0。"
- )
- return warning_message
- return "" # 没有警告时返回空字符串
-
-
-def adjust_model_greater_probabilities(t_model_1_probability, t_model_2_probability, t_model_3_probability):
- total = (
- Decimal(str(t_model_1_probability)) + Decimal(str(t_model_2_probability)) + Decimal(str(t_model_3_probability))
- )
- if total > Decimal("1.0"):
- warning_message = (
- f"警告: 选择模型1、模型2和模型3的概率总和为 {float(total):.2f},超过了 1.0!请调整滑块使总和等于 1.0。"
- )
- return warning_message
- return "" # 没有警告时返回空字符串
-
-
-def adjust_model_less_probabilities(t_model_1_probability, t_model_2_probability, t_model_3_probability):
- total = (
- Decimal(str(t_model_1_probability)) + Decimal(str(t_model_2_probability)) + Decimal(str(t_model_3_probability))
- )
- if total < Decimal("1.0"):
- warning_message = (
- f"警告: 选择模型1、模型2和模型3的概率总和为 {float(total):.2f},小于了 1.0!请调整滑块使总和等于 1.0。"
- )
- return warning_message
- return "" # 没有警告时返回空字符串
-
-
-# ==============================================
-# 人格保存函数
-def save_personality_config(
- t_prompt_personality_1,
- t_prompt_personality_2,
- t_prompt_personality_3,
- t_enable_schedule_gen,
- t_prompt_schedule_gen,
- t_schedule_doing_update_interval,
- t_personality_1_probability,
- t_personality_2_probability,
- t_personality_3_probability,
-):
- # 保存人格提示词
- config_data["personality"]["prompt_personality"][0] = t_prompt_personality_1
- config_data["personality"]["prompt_personality"][1] = t_prompt_personality_2
- config_data["personality"]["prompt_personality"][2] = t_prompt_personality_3
-
- # 保存日程生成部分
- if PARSED_CONFIG_VERSION >= SCHEDULE_CHANGED_VERSION:
- config_data["schedule"]["enable_schedule_gen"] = t_enable_schedule_gen
- config_data["schedule"]["prompt_schedule_gen"] = t_prompt_schedule_gen
- config_data["schedule"]["schedule_doing_update_interval"] = t_schedule_doing_update_interval
- else:
- config_data["personality"]["prompt_schedule"] = t_prompt_schedule_gen
-
- # 保存三个人格的概率
- config_data["personality"]["personality_1_probability"] = t_personality_1_probability
- config_data["personality"]["personality_2_probability"] = t_personality_2_probability
- config_data["personality"]["personality_3_probability"] = t_personality_3_probability
-
- save_config_to_file(config_data)
- logger.info("人格配置已保存到 bot_config.toml 文件中")
- return "人格配置已保存"
-
-
-def save_message_and_emoji_config(
- t_min_text_length,
- t_max_context_size,
- t_emoji_chance,
- t_thinking_timeout,
- t_response_willing_amplifier,
- t_response_interested_rate_amplifier,
- t_down_frequency_rate,
- t_ban_words_final_result,
- t_ban_msgs_regex_final_result,
- t_check_interval,
- t_register_interval,
- t_auto_save,
- t_enable_check,
- t_check_prompt,
-):
- if PARSED_CONFIG_VERSION < version.parse("0.0.11"):
- config_data["message"]["min_text_length"] = t_min_text_length
- config_data["message"]["max_context_size"] = t_max_context_size
- config_data["message"]["emoji_chance"] = t_emoji_chance
- config_data["message"]["thinking_timeout"] = t_thinking_timeout
- if PARSED_CONFIG_VERSION < version.parse("0.0.11"):
- config_data["message"]["response_willing_amplifier"] = t_response_willing_amplifier
- config_data["message"]["response_interested_rate_amplifier"] = t_response_interested_rate_amplifier
- config_data["message"]["down_frequency_rate"] = t_down_frequency_rate
- config_data["message"]["ban_words"] = t_ban_words_final_result
- config_data["message"]["ban_msgs_regex"] = t_ban_msgs_regex_final_result
- config_data["emoji"]["check_interval"] = t_check_interval
- config_data["emoji"]["register_interval"] = t_register_interval
- config_data["emoji"]["auto_save"] = t_auto_save
- config_data["emoji"]["enable_check"] = t_enable_check
- config_data["emoji"]["check_prompt"] = t_check_prompt
- save_config_to_file(config_data)
- logger.info("消息和表情配置已保存到 bot_config.toml 文件中")
- return "消息和表情配置已保存"
-
-def save_willing_config(
- t_willing_mode,
- t_response_willing_amplifier,
- t_response_interested_rate_amplifier,
- t_down_frequency_rate,
- t_emoji_response_penalty,
-):
- config_data["willing"]["willing_mode"] = t_willing_mode
- config_data["willing"]["response_willing_amplifier"] = t_response_willing_amplifier
- config_data["willing"]["response_interested_rate_amplifier"] = t_response_interested_rate_amplifier
- config_data["willing"]["down_frequency_rate"] = t_down_frequency_rate
- config_data["willing"]["emoji_response_penalty"] = t_emoji_response_penalty
- save_config_to_file(config_data)
- logger.info("willinng配置已保存到 bot_config.toml 文件中")
- return "willinng配置已保存"
-
-def save_response_model_config(
- t_willing_mode,
- t_model_r1_probability,
- t_model_r2_probability,
- t_model_r3_probability,
- t_max_response_length,
- t_model1_name,
- t_model1_provider,
- t_model1_pri_in,
- t_model1_pri_out,
- t_model2_name,
- t_model2_provider,
- t_model2_pri_in,
- t_model2_pri_out,
- t_model3_name,
- t_model3_provider,
- t_model3_pri_in,
- t_model3_pri_out,
- t_emotion_model_name,
- t_emotion_model_provider,
- t_emotion_model_pri_in,
- t_emotion_model_pri_out,
- t_topic_judge_model_name,
- t_topic_judge_model_provider,
- t_topic_judge_model_pri_in,
- t_topic_judge_model_pri_out,
- t_summary_by_topic_model_name,
- t_summary_by_topic_model_provider,
- t_summary_by_topic_model_pri_in,
- t_summary_by_topic_model_pri_out,
- t_vlm_model_name,
- t_vlm_model_provider,
- t_vlm_model_pri_in,
- t_vlm_model_pri_out,
-):
- if PARSED_CONFIG_VERSION >= version.parse("0.0.10"):
- config_data["willing"]["willing_mode"] = t_willing_mode
- config_data["response"]["model_r1_probability"] = t_model_r1_probability
- config_data["response"]["model_v3_probability"] = t_model_r2_probability
- config_data["response"]["model_r1_distill_probability"] = t_model_r3_probability
- if PARSED_CONFIG_VERSION <= version.parse("0.0.10"):
- config_data["response"]["max_response_length"] = t_max_response_length
-
- # 保存模型1配置
- config_data["model"]["llm_reasoning"]["name"] = t_model1_name
- config_data["model"]["llm_reasoning"]["provider"] = t_model1_provider
- config_data["model"]["llm_reasoning"]["pri_in"] = t_model1_pri_in
- config_data["model"]["llm_reasoning"]["pri_out"] = t_model1_pri_out
-
- # 保存模型2配置
- config_data["model"]["llm_normal"]["name"] = t_model2_name
- config_data["model"]["llm_normal"]["provider"] = t_model2_provider
- config_data["model"]["llm_normal"]["pri_in"] = t_model2_pri_in
- config_data["model"]["llm_normal"]["pri_out"] = t_model2_pri_out
-
- # 保存模型3配置
- config_data["model"]["llm_reasoning_minor"]["name"] = t_model3_name
- config_data["model"]["llm_reasoning_minor"]["provider"] = t_model3_provider
- config_data["model"]["llm_reasoning_minor"]["pri_in"] = t_model3_pri_in
- config_data["model"]["llm_reasoning_minor"]["pri_out"] = t_model3_pri_out
-
- # 保存情感模型配置
- config_data["model"]["llm_emotion_judge"]["name"] = t_emotion_model_name
- config_data["model"]["llm_emotion_judge"]["provider"] = t_emotion_model_provider
- config_data["model"]["llm_emotion_judge"]["pri_in"] = t_emotion_model_pri_in
- config_data["model"]["llm_emotion_judge"]["pri_out"] = t_emotion_model_pri_out
-
- # 保存主题判断模型配置
- config_data["model"]["llm_topic_judge"]["name"] = t_topic_judge_model_name
- config_data["model"]["llm_topic_judge"]["provider"] = t_topic_judge_model_provider
- config_data["model"]["llm_topic_judge"]["pri_in"] = t_topic_judge_model_pri_in
- config_data["model"]["llm_topic_judge"]["pri_out"] = t_topic_judge_model_pri_out
-
- # 保存主题总结模型配置
- config_data["model"]["llm_summary_by_topic"]["name"] = t_summary_by_topic_model_name
- config_data["model"]["llm_summary_by_topic"]["provider"] = t_summary_by_topic_model_provider
- config_data["model"]["llm_summary_by_topic"]["pri_in"] = t_summary_by_topic_model_pri_in
- config_data["model"]["llm_summary_by_topic"]["pri_out"] = t_summary_by_topic_model_pri_out
-
- # 保存识图模型配置
- config_data["model"]["vlm"]["name"] = t_vlm_model_name
- config_data["model"]["vlm"]["provider"] = t_vlm_model_provider
- config_data["model"]["vlm"]["pri_in"] = t_vlm_model_pri_in
- config_data["model"]["vlm"]["pri_out"] = t_vlm_model_pri_out
-
- save_config_to_file(config_data)
- logger.info("回复&模型设置已保存到 bot_config.toml 文件中")
- return "回复&模型设置已保存"
-
-
-def save_memory_mood_config(
- t_build_memory_interval,
- t_memory_compress_rate,
- t_forget_memory_interval,
- t_memory_forget_time,
- t_memory_forget_percentage,
- t_memory_ban_words_final_result,
- t_mood_update_interval,
- t_mood_decay_rate,
- t_mood_intensity_factor,
- t_build_memory_dist1_mean,
- t_build_memory_dist1_std,
- t_build_memory_dist1_weight,
- t_build_memory_dist2_mean,
- t_build_memory_dist2_std,
- t_build_memory_dist2_weight,
-):
- config_data["memory"]["build_memory_interval"] = t_build_memory_interval
- config_data["memory"]["memory_compress_rate"] = t_memory_compress_rate
- config_data["memory"]["forget_memory_interval"] = t_forget_memory_interval
- config_data["memory"]["memory_forget_time"] = t_memory_forget_time
- config_data["memory"]["memory_forget_percentage"] = t_memory_forget_percentage
- config_data["memory"]["memory_ban_words"] = t_memory_ban_words_final_result
- if PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- config_data["memory"]["build_memory_distribution"] = [
- t_build_memory_dist1_mean,
- t_build_memory_dist1_std,
- t_build_memory_dist1_weight,
- t_build_memory_dist2_mean,
- t_build_memory_dist2_std,
- t_build_memory_dist2_weight,
- ]
- config_data["mood"]["update_interval"] = t_mood_update_interval
- config_data["mood"]["decay_rate"] = t_mood_decay_rate
- config_data["mood"]["intensity_factor"] = t_mood_intensity_factor
- save_config_to_file(config_data)
- logger.info("记忆和心情设置已保存到 bot_config.toml 文件中")
- return "记忆和心情设置已保存"
-
-
-def save_other_config(
- t_keywords_reaction_enabled,
- t_enable_advance_output,
- t_enable_kuuki_read,
- t_enable_debug_output,
- t_enable_friend_chat,
- t_chinese_typo_enabled,
- t_error_rate,
- t_min_freq,
- t_tone_error_rate,
- t_word_replace_rate,
- t_remote_status,
- t_enable_response_spliter,
- t_max_response_length,
- t_max_sentence_num,
-):
- config_data["keywords_reaction"]["enable"] = t_keywords_reaction_enabled
- config_data["others"]["enable_advance_output"] = t_enable_advance_output
- config_data["others"]["enable_kuuki_read"] = t_enable_kuuki_read
- config_data["others"]["enable_debug_output"] = t_enable_debug_output
- config_data["others"]["enable_friend_chat"] = t_enable_friend_chat
- config_data["chinese_typo"]["enable"] = t_chinese_typo_enabled
- config_data["chinese_typo"]["error_rate"] = t_error_rate
- config_data["chinese_typo"]["min_freq"] = t_min_freq
- config_data["chinese_typo"]["tone_error_rate"] = t_tone_error_rate
- config_data["chinese_typo"]["word_replace_rate"] = t_word_replace_rate
- if PARSED_CONFIG_VERSION > HAVE_ONLINE_STATUS_VERSION:
- config_data["remote"]["enable"] = t_remote_status
- if PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- config_data["response_spliter"]["enable_response_spliter"] = t_enable_response_spliter
- config_data["response_spliter"]["response_max_length"] = t_max_response_length
- config_data["response_spliter"]["response_max_sentence_num"] = t_max_sentence_num
- save_config_to_file(config_data)
- logger.info("其他设置已保存到 bot_config.toml 文件中")
- return "其他设置已保存"
-
-
-def save_group_config(
- t_talk_allowed_final_result,
- t_talk_frequency_down_final_result,
- t_ban_user_id_final_result,
-):
- config_data["groups"]["talk_allowed"] = t_talk_allowed_final_result
- config_data["groups"]["talk_frequency_down"] = t_talk_frequency_down_final_result
- config_data["groups"]["ban_user_id"] = t_ban_user_id_final_result
- save_config_to_file(config_data)
- logger.info("群聊设置已保存到 bot_config.toml 文件中")
- return "群聊设置已保存"
-
-with gr.Blocks(title="MaimBot配置文件编辑") as app:
- gr.Markdown(
- value="""
- # 欢迎使用由墨梓柒MotricSeven编写的MaimBot配置文件编辑器\n
- 感谢ZureTz大佬提供的人格保存部分修复!
- """
- )
- gr.Markdown(value="---") # 添加分割线
- gr.Markdown(value="""
- ## 注意!!!\n
- 由于Gradio的限制,在保存配置文件时,请不要刷新浏览器窗口!!\n
- 您的配置文件在点击保存按钮的时候就已经成功保存!!
- """)
- gr.Markdown(value="---") # 添加分割线
- gr.Markdown(value="## 全球在线MaiMBot数量: " + str((online_maimbot_data or {}).get("online_clients", 0)))
- gr.Markdown(value="## 当前WebUI版本: " + str(WEBUI_VERSION))
- gr.Markdown(value="## 配置文件版本:" + config_data["inner"]["version"])
- gr.Markdown(value="---") # 添加分割线
- with gr.Tabs():
- with gr.TabItem("0-环境设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- gr.Markdown(
- value="""
- MaimBot服务器地址,默认127.0.0.1\n
- 不熟悉配置的不要轻易改动此项!!\n
- """
- )
- with gr.Row():
- server_address = gr.Textbox(
- label="服务器地址", value=env_config_data["env_HOST"], interactive=True
- )
- with gr.Row():
- server_port = gr.Textbox(
- label="服务器端口", value=env_config_data["env_PORT"], interactive=True
- )
- with gr.Row():
- plugin_list = parse_list_str(env_config_data["env_PLUGINS"])
- with gr.Blocks():
- list_state = gr.State(value=plugin_list.copy())
-
- with gr.Row():
- list_display = gr.TextArea(
- value="\n".join(plugin_list), label="插件列表", interactive=False, lines=5
- )
- with gr.Row():
- with gr.Column(scale=3):
- new_item_input = gr.Textbox(label="添加新插件")
- add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- item_to_delete = gr.Dropdown(choices=plugin_list, label="选择要删除的插件")
- delete_btn = gr.Button("删除", scale=1)
-
- final_result = gr.Text(label="修改后的列表")
- add_btn.click(
- add_item,
- inputs=[new_item_input, list_state],
- outputs=[list_state, list_display, item_to_delete, final_result],
- )
-
- delete_btn.click(
- delete_item,
- inputs=[item_to_delete, list_state],
- outputs=[list_state, list_display, item_to_delete, final_result],
- )
- with gr.Row():
- gr.Markdown(
- """MongoDB设置项\n
- 保持默认即可,如果你有能力承担修改过后的后果(简称能改回来(笑))\n
- 可以对以下配置项进行修改\n
- """
- )
- with gr.Row():
- mongodb_host = gr.Textbox(
- label="MongoDB服务器地址", value=env_config_data["env_MONGODB_HOST"], interactive=True
- )
- with gr.Row():
- mongodb_port = gr.Textbox(
- label="MongoDB服务器端口", value=env_config_data["env_MONGODB_PORT"], interactive=True
- )
- with gr.Row():
- mongodb_database_name = gr.Textbox(
- label="MongoDB数据库名称", value=env_config_data["env_DATABASE_NAME"], interactive=True
- )
- with gr.Row():
- gr.Markdown(
- """日志设置\n
- 配置日志输出级别\n
- 改完了记得保存!!!
- """
- )
- with gr.Row():
- console_log_level = gr.Dropdown(
- choices=["INFO", "DEBUG", "WARNING", "ERROR", "SUCCESS"],
- label="控制台日志级别",
- value=env_config_data.get("env_CONSOLE_LOG_LEVEL", "INFO"),
- interactive=True,
- )
- with gr.Row():
- file_log_level = gr.Dropdown(
- choices=["INFO", "DEBUG", "WARNING", "ERROR", "SUCCESS"],
- label="文件日志级别",
- value=env_config_data.get("env_FILE_LOG_LEVEL", "DEBUG"),
- interactive=True,
- )
- with gr.Row():
- default_console_log_level = gr.Dropdown(
- choices=["INFO", "DEBUG", "WARNING", "ERROR", "SUCCESS", "NONE"],
- label="默认控制台日志级别",
- value=env_config_data.get("env_DEFAULT_CONSOLE_LOG_LEVEL", "SUCCESS"),
- interactive=True,
- )
- with gr.Row():
- default_file_log_level = gr.Dropdown(
- choices=["INFO", "DEBUG", "WARNING", "ERROR", "SUCCESS", "NONE"],
- label="默认文件日志级别",
- value=env_config_data.get("env_DEFAULT_FILE_LOG_LEVEL", "DEBUG"),
- interactive=True,
- )
- with gr.Row():
- gr.Markdown(
- """API设置\n
- 选择API提供商并配置相应的BaseURL和Key\n
- 改完了记得保存!!!
- """
- )
- with gr.Row():
- with gr.Column(scale=3):
- new_provider_input = gr.Textbox(label="添加新提供商", placeholder="输入新提供商名称")
- add_provider_btn = gr.Button("添加提供商", scale=1)
- with gr.Row():
- api_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- label="选择API提供商",
- value=MODEL_PROVIDER_LIST[0] if MODEL_PROVIDER_LIST else None,
- )
-
- with gr.Row():
- api_base_url = gr.Textbox(
- label="Base URL",
- value=env_config_data.get(f"env_{MODEL_PROVIDER_LIST[0]}_BASE_URL", "")
- if MODEL_PROVIDER_LIST
- else "",
- interactive=True,
- )
- with gr.Row():
- api_key = gr.Textbox(
- label="API Key",
- value=env_config_data.get(f"env_{MODEL_PROVIDER_LIST[0]}_KEY", "")
- if MODEL_PROVIDER_LIST
- else "",
- interactive=True,
- )
- api_provider.change(update_api_inputs, inputs=[api_provider], outputs=[api_base_url, api_key])
- with gr.Row():
- save_env_btn = gr.Button("保存环境配置", variant="primary")
- with gr.Row():
- save_env_btn.click(
- save_trigger,
- inputs=[
- server_address,
- server_port,
- final_result,
- mongodb_host,
- mongodb_port,
- mongodb_database_name,
- console_log_level,
- file_log_level,
- default_console_log_level,
- default_file_log_level,
- api_provider,
- api_base_url,
- api_key,
- ],
- outputs=[gr.Textbox(label="保存结果", interactive=False)],
- )
-
- # 绑定添加提供商按钮的点击事件
- add_provider_btn.click(
- add_new_provider,
- inputs=[new_provider_input, gr.State(value=MODEL_PROVIDER_LIST)],
- outputs=[gr.State(value=MODEL_PROVIDER_LIST), api_provider],
- ).then(
- lambda x: (
- env_config_data.get(f"env_{x}_BASE_URL", ""),
- env_config_data.get(f"env_{x}_KEY", ""),
- ),
- inputs=[api_provider],
- outputs=[api_base_url, api_key],
- )
- with gr.TabItem("1-Bot基础设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- qqbot_qq = gr.Textbox(label="QQ机器人QQ号", value=config_data["bot"]["qq"], interactive=True)
- with gr.Row():
- nickname = gr.Textbox(label="昵称", value=config_data["bot"]["nickname"], interactive=True)
- with gr.Row():
- nickname_list = config_data["bot"]["alias_names"]
- with gr.Blocks():
- nickname_list_state = gr.State(value=nickname_list.copy())
-
- with gr.Row():
- nickname_list_display = gr.TextArea(
- value="\n".join(nickname_list), label="别名列表", interactive=False, lines=5
- )
- with gr.Row():
- with gr.Column(scale=3):
- nickname_new_item_input = gr.Textbox(label="添加新别名")
- nickname_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- nickname_item_to_delete = gr.Dropdown(choices=nickname_list, label="选择要删除的别名")
- nickname_delete_btn = gr.Button("删除", scale=1)
-
- nickname_final_result = gr.Text(label="修改后的列表")
- nickname_add_btn.click(
- add_item,
- inputs=[nickname_new_item_input, nickname_list_state],
- outputs=[
- nickname_list_state,
- nickname_list_display,
- nickname_item_to_delete,
- nickname_final_result,
- ],
- )
-
- nickname_delete_btn.click(
- delete_item,
- inputs=[nickname_item_to_delete, nickname_list_state],
- outputs=[
- nickname_list_state,
- nickname_list_display,
- nickname_item_to_delete,
- nickname_final_result,
- ],
- )
- gr.Button(
- "保存Bot配置", variant="primary", elem_id="save_bot_btn", elem_classes="save_bot_btn"
- ).click(
- save_bot_config,
- inputs=[qqbot_qq, nickname, nickname_list_state],
- outputs=[gr.Textbox(label="保存Bot结果")],
- )
- with gr.TabItem("2-人格设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- prompt_personality_1 = gr.Textbox(
- label="人格1提示词",
- value=config_data["personality"]["prompt_personality"][0],
- interactive=True,
- )
- with gr.Row():
- prompt_personality_2 = gr.Textbox(
- label="人格2提示词",
- value=config_data["personality"]["prompt_personality"][1],
- interactive=True,
- )
- with gr.Row():
- prompt_personality_3 = gr.Textbox(
- label="人格3提示词",
- value=config_data["personality"]["prompt_personality"][2],
- interactive=True,
- )
- with gr.Column(scale=3):
- # 创建三个滑块, 代表三个人格的概率
- personality_1_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["personality"]["personality_1_probability"],
- label="人格1概率",
- )
- personality_2_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["personality"]["personality_2_probability"],
- label="人格2概率",
- )
- personality_3_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["personality"]["personality_3_probability"],
- label="人格3概率",
- )
-
- # 用于显示警告消息
- warning_greater_text = gr.Markdown()
- warning_less_text = gr.Markdown()
-
- # 绑定滑块的值变化事件,确保总和必须等于 1.0
-
- # 输入的 3 个概率
- personality_probability_change_inputs = [
- personality_1_probability,
- personality_2_probability,
- personality_3_probability,
- ]
-
- # 绑定滑块的值变化事件,确保总和不大于 1.0
- personality_1_probability.change(
- adjust_personality_greater_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_greater_text],
- )
- personality_2_probability.change(
- adjust_personality_greater_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_greater_text],
- )
- personality_3_probability.change(
- adjust_personality_greater_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_greater_text],
- )
-
- # 绑定滑块的值变化事件,确保总和不小于 1.0
- personality_1_probability.change(
- adjust_personality_less_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_less_text],
- )
- personality_2_probability.change(
- adjust_personality_less_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_less_text],
- )
- personality_3_probability.change(
- adjust_personality_less_probabilities,
- inputs=personality_probability_change_inputs,
- outputs=[warning_less_text],
- )
- with gr.Row():
- gr.Markdown("---")
- with gr.Row():
- gr.Markdown("麦麦提示词设置")
- if PARSED_CONFIG_VERSION >= SCHEDULE_CHANGED_VERSION:
- with gr.Row():
- enable_schedule_gen = gr.Checkbox(value=config_data["schedule"]["enable_schedule_gen"],
- label="是否开启麦麦日程生成(尚未完成)",
- interactive=True
- )
- with gr.Row():
- prompt_schedule_gen = gr.Textbox(
- label="日程生成提示词", value=config_data["schedule"]["prompt_schedule_gen"], interactive=True
- )
- with gr.Row():
- schedule_doing_update_interval = gr.Number(
- value=config_data["schedule"]["schedule_doing_update_interval"],
- label="日程表更新间隔 单位秒",
- interactive=True
- )
- else:
- with gr.Row():
- prompt_schedule_gen = gr.Textbox(
- label="日程生成提示词", value=config_data["personality"]["prompt_schedule"], interactive=True
- )
- enable_schedule_gen = gr.Checkbox(value=False,visible=False,interactive=False)
- schedule_doing_update_interval = gr.Number(value=0,visible=False,interactive=False)
- with gr.Row():
- personal_save_btn = gr.Button(
- "保存人格配置",
- variant="primary",
- elem_id="save_personality_btn",
- elem_classes="save_personality_btn",
- )
- with gr.Row():
- personal_save_message = gr.Textbox(label="保存人格结果")
- personal_save_btn.click(
- save_personality_config,
- inputs=[
- prompt_personality_1,
- prompt_personality_2,
- prompt_personality_3,
- enable_schedule_gen,
- prompt_schedule_gen,
- schedule_doing_update_interval,
- personality_1_probability,
- personality_2_probability,
- personality_3_probability,
- ],
- outputs=[personal_save_message],
- )
- with gr.TabItem("3-消息&表情包设置"):
- with gr.Row():
- with gr.Column(scale=3):
- if PARSED_CONFIG_VERSION < version.parse("0.0.11"):
- with gr.Row():
- min_text_length = gr.Number(
- value=config_data["message"]["min_text_length"],
- label="与麦麦聊天时麦麦只会回答文本大于等于此数的消息",
- )
- else:
- min_text_length = gr.Number(visible=False,value=0,interactive=False)
- with gr.Row():
- max_context_size = gr.Number(
- value=config_data["message"]["max_context_size"], label="麦麦获得的上文数量"
- )
- with gr.Row():
- emoji_chance = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["message"]["emoji_chance"],
- label="麦麦使用表情包的概率",
- )
- with gr.Row():
- thinking_timeout = gr.Number(
- value=config_data["message"]["thinking_timeout"],
- label="麦麦正在思考时,如果超过此秒数,则停止思考",
- )
- if PARSED_CONFIG_VERSION < version.parse("0.0.11"):
- with gr.Row():
- response_willing_amplifier = gr.Number(
- value=config_data["message"]["response_willing_amplifier"],
- label="麦麦回复意愿放大系数,一般为1",
- )
- with gr.Row():
- response_interested_rate_amplifier = gr.Number(
- value=config_data["message"]["response_interested_rate_amplifier"],
- label="麦麦回复兴趣度放大系数,听到记忆里的内容时放大系数",
- )
- with gr.Row():
- down_frequency_rate = gr.Number(
- value=config_data["message"]["down_frequency_rate"],
- label="降低回复频率的群组回复意愿降低系数",
- )
- else:
- response_willing_amplifier = gr.Number(visible=False,value=0,interactive=False)
- response_interested_rate_amplifier = gr.Number(visible=False,value=0,interactive=False)
- down_frequency_rate = gr.Number(visible=False,value=0,interactive=False)
-
- with gr.Row():
- gr.Markdown("### 违禁词列表")
- with gr.Row():
- ban_words_list = config_data["message"]["ban_words"]
- with gr.Blocks():
- ban_words_list_state = gr.State(value=ban_words_list.copy())
- with gr.Row():
- ban_words_list_display = gr.TextArea(
- value="\n".join(ban_words_list), label="违禁词列表", interactive=False, lines=5
- )
- with gr.Row():
- with gr.Column(scale=3):
- ban_words_new_item_input = gr.Textbox(label="添加新违禁词")
- ban_words_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- ban_words_item_to_delete = gr.Dropdown(
- choices=ban_words_list, label="选择要删除的违禁词"
- )
- ban_words_delete_btn = gr.Button("删除", scale=1)
-
- ban_words_final_result = gr.Text(label="修改后的违禁词")
- ban_words_add_btn.click(
- add_item,
- inputs=[ban_words_new_item_input, ban_words_list_state],
- outputs=[
- ban_words_list_state,
- ban_words_list_display,
- ban_words_item_to_delete,
- ban_words_final_result,
- ],
- )
-
- ban_words_delete_btn.click(
- delete_item,
- inputs=[ban_words_item_to_delete, ban_words_list_state],
- outputs=[
- ban_words_list_state,
- ban_words_list_display,
- ban_words_item_to_delete,
- ban_words_final_result,
- ],
- )
- with gr.Row():
- gr.Markdown("### 检测违禁消息正则表达式列表")
- with gr.Row():
- gr.Markdown(
- """
- 需要过滤的消息(原始消息)匹配的正则表达式,匹配到的消息将被过滤(支持CQ码),若不了解正则表达式请勿修改\n
- "https?://[^\\s]+", # 匹配https链接\n
- "\\d{4}-\\d{2}-\\d{2}", # 匹配日期\n
- "\\[CQ:at,qq=\\d+\\]" # 匹配@\n
- """
- )
- with gr.Row():
- ban_msgs_regex_list = config_data["message"]["ban_msgs_regex"]
- with gr.Blocks():
- ban_msgs_regex_list_state = gr.State(value=ban_msgs_regex_list.copy())
- with gr.Row():
- ban_msgs_regex_list_display = gr.TextArea(
- value="\n".join(ban_msgs_regex_list),
- label="违禁消息正则列表",
- interactive=False,
- lines=5,
- )
- with gr.Row():
- with gr.Column(scale=3):
- ban_msgs_regex_new_item_input = gr.Textbox(label="添加新违禁消息正则")
- ban_msgs_regex_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- ban_msgs_regex_item_to_delete = gr.Dropdown(
- choices=ban_msgs_regex_list, label="选择要删除的违禁消息正则"
- )
- ban_msgs_regex_delete_btn = gr.Button("删除", scale=1)
-
- ban_msgs_regex_final_result = gr.Text(label="修改后的违禁消息正则")
- ban_msgs_regex_add_btn.click(
- add_item,
- inputs=[ban_msgs_regex_new_item_input, ban_msgs_regex_list_state],
- outputs=[
- ban_msgs_regex_list_state,
- ban_msgs_regex_list_display,
- ban_msgs_regex_item_to_delete,
- ban_msgs_regex_final_result,
- ],
- )
-
- ban_msgs_regex_delete_btn.click(
- delete_item,
- inputs=[ban_msgs_regex_item_to_delete, ban_msgs_regex_list_state],
- outputs=[
- ban_msgs_regex_list_state,
- ban_msgs_regex_list_display,
- ban_msgs_regex_item_to_delete,
- ban_msgs_regex_final_result,
- ],
- )
- with gr.Row():
- check_interval = gr.Number(
- value=config_data["emoji"]["check_interval"], label="检查表情包的时间间隔"
- )
- with gr.Row():
- register_interval = gr.Number(
- value=config_data["emoji"]["register_interval"], label="注册表情包的时间间隔"
- )
- with gr.Row():
- auto_save = gr.Checkbox(value=config_data["emoji"]["auto_save"], label="自动保存表情包")
- with gr.Row():
- enable_check = gr.Checkbox(value=config_data["emoji"]["enable_check"], label="启用表情包检查")
- with gr.Row():
- check_prompt = gr.Textbox(value=config_data["emoji"]["check_prompt"], label="表情包过滤要求")
- with gr.Row():
- emoji_save_btn = gr.Button(
- "保存消息&表情包设置",
- variant="primary",
- elem_id="save_personality_btn",
- elem_classes="save_personality_btn",
- )
- with gr.Row():
- emoji_save_message = gr.Textbox(label="消息&表情包设置保存结果")
- emoji_save_btn.click(
- save_message_and_emoji_config,
- inputs=[
- min_text_length,
- max_context_size,
- emoji_chance,
- thinking_timeout,
- response_willing_amplifier,
- response_interested_rate_amplifier,
- down_frequency_rate,
- ban_words_list_state,
- ban_msgs_regex_list_state,
- check_interval,
- register_interval,
- auto_save,
- enable_check,
- check_prompt,
- ],
- outputs=[emoji_save_message],
- )
- with gr.TabItem("4-意愿设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- gr.Markdown("""### 回复设置""")
- if PARSED_CONFIG_VERSION >= version.parse("0.0.10"):
- with gr.Row():
- gr.Markdown("""#### 回复意愿模式""")
- with gr.Row():
- gr.Markdown("""回复意愿模式说明:\n
- classical为经典回复意愿管理器\n
- dynamic为动态意愿管理器\n
- custom为自定义意愿管理器
- """)
- with gr.Row():
- willing_mode = gr.Dropdown(
- choices=WILLING_MODE_CHOICES,
- value=config_data["willing"]["willing_mode"],
- label="回复意愿模式",
- )
- else:
- willing_mode = gr.Textbox(visible=False, value="disabled")
- if PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- with gr.Row():
- response_willing_amplifier = gr.Number(
- value=config_data["willing"]["response_willing_amplifier"],
- label="麦麦回复意愿放大系数,一般为1",
- )
- with gr.Row():
- response_interested_rate_amplifier = gr.Number(
- value=config_data["willing"]["response_interested_rate_amplifier"],
- label="麦麦回复兴趣度放大系数,听到记忆里的内容时放大系数",
- )
- with gr.Row():
- down_frequency_rate = gr.Number(
- value=config_data["willing"]["down_frequency_rate"],
- label="降低回复频率的群组回复意愿降低系数",
- )
- with gr.Row():
- emoji_response_penalty = gr.Number(
- value=config_data["willing"]["emoji_response_penalty"],
- label="表情包回复惩罚系数,设为0为不回复单个表情包,减少单独回复表情包的概率",
- )
- else:
- response_willing_amplifier = gr.Number(visible=False, value=1.0)
- response_interested_rate_amplifier = gr.Number(visible=False, value=1.0)
- down_frequency_rate = gr.Number(visible=False, value=1.0)
- emoji_response_penalty = gr.Number(visible=False, value=1.0)
- with gr.Row():
- willing_save_btn = gr.Button(
- "保存意愿设置设置",
- variant="primary",
- elem_id="save_personality_btn",
- elem_classes="save_personality_btn",
- )
- with gr.Row():
- willing_save_message = gr.Textbox(label="意愿设置保存结果")
- willing_save_btn.click(
- save_willing_config,
- inputs=[
- willing_mode,
- response_willing_amplifier,
- response_interested_rate_amplifier,
- down_frequency_rate,
- emoji_response_penalty,
- ],
- outputs=[emoji_save_message],
- )
- with gr.TabItem("4-回复&模型设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- model_r1_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["response"]["model_r1_probability"],
- label="麦麦回答时选择主要回复模型1 模型的概率",
- )
- with gr.Row():
- model_r2_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["response"]["model_v3_probability"],
- label="麦麦回答时选择主要回复模型2 模型的概率",
- )
- with gr.Row():
- model_r3_probability = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["response"]["model_r1_distill_probability"],
- label="麦麦回答时选择主要回复模型3 模型的概率",
- )
- # 用于显示警告消息
- with gr.Row():
- model_warning_greater_text = gr.Markdown()
- model_warning_less_text = gr.Markdown()
-
- # 绑定滑块的值变化事件,确保总和必须等于 1.0
- model_r1_probability.change(
- adjust_model_greater_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_greater_text],
- )
- model_r2_probability.change(
- adjust_model_greater_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_greater_text],
- )
- model_r3_probability.change(
- adjust_model_greater_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_greater_text],
- )
- model_r1_probability.change(
- adjust_model_less_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_less_text],
- )
- model_r2_probability.change(
- adjust_model_less_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_less_text],
- )
- model_r3_probability.change(
- adjust_model_less_probabilities,
- inputs=[model_r1_probability, model_r2_probability, model_r3_probability],
- outputs=[model_warning_less_text],
- )
- if PARSED_CONFIG_VERSION <= version.parse("0.0.10"):
- with gr.Row():
- max_response_length = gr.Number(
- value=config_data["response"]["max_response_length"], label="麦麦回答的最大token数"
- )
- else:
- max_response_length = gr.Number(visible=False,value=0)
- with gr.Row():
- gr.Markdown("""### 模型设置""")
- with gr.Row():
- gr.Markdown(
- """### 注意\n
- 如果你是用的是火山引擎的API,建议查看[这篇文档](https://zxmucttizt8.feishu.cn/wiki/MQj7wp6dki6X8rkplApc2v6Enkd)中的修改火山API部分\n
- 因为修改至火山API涉及到修改源码部分,由于自己修改源码造成的问题MaiMBot官方并不因此负责!\n
- 感谢理解,感谢你使用MaiMBot
- """
- )
- with gr.Tabs():
- with gr.TabItem("1-主要回复模型"):
- with gr.Row():
- model1_name = gr.Textbox(
- value=config_data["model"]["llm_reasoning"]["name"], label="模型1的名称"
- )
- with gr.Row():
- model1_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_reasoning"]["provider"],
- label="模型1(主要回复模型)提供商",
- )
- with gr.Row():
- model1_pri_in = gr.Number(
- value=config_data["model"]["llm_reasoning"]["pri_in"],
- label="模型1(主要回复模型)的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- model1_pri_out = gr.Number(
- value=config_data["model"]["llm_reasoning"]["pri_out"],
- label="模型1(主要回复模型)的输出价格(非必填,可以记录消耗)",
- )
- with gr.TabItem("2-次要回复模型"):
- with gr.Row():
- model2_name = gr.Textbox(
- value=config_data["model"]["llm_normal"]["name"], label="模型2的名称"
- )
- with gr.Row():
- model2_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_normal"]["provider"],
- label="模型2提供商",
- )
- with gr.Row():
- model2_pri_in = gr.Number(
- value=config_data["model"]["llm_normal"]["pri_in"],
- label="模型2(次要回复模型)的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- model2_pri_out = gr.Number(
- value=config_data["model"]["llm_normal"]["pri_out"],
- label="模型2(次要回复模型)的输出价格(非必填,可以记录消耗)",
- )
- with gr.TabItem("3-次要模型"):
- with gr.Row():
- model3_name = gr.Textbox(
- value=config_data["model"]["llm_reasoning_minor"]["name"], label="模型3的名称"
- )
- with gr.Row():
- model3_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_reasoning_minor"]["provider"],
- label="模型3提供商",
- )
- with gr.Row():
- model3_pri_in = gr.Number(
- value=config_data["model"]["llm_reasoning_minor"]["pri_in"],
- label="模型3(次要回复模型)的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- model3_pri_out = gr.Number(
- value=config_data["model"]["llm_reasoning_minor"]["pri_out"],
- label="模型3(次要回复模型)的输出价格(非必填,可以记录消耗)",
- )
- with gr.TabItem("4-情感&主题模型"):
- with gr.Row():
- gr.Markdown("""### 情感模型设置""")
- with gr.Row():
- emotion_model_name = gr.Textbox(
- value=config_data["model"]["llm_emotion_judge"]["name"], label="情感模型名称"
- )
- with gr.Row():
- emotion_model_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_emotion_judge"]["provider"],
- label="情感模型提供商",
- )
- with gr.Row():
- emotion_model_pri_in = gr.Number(
- value=config_data["model"]["llm_emotion_judge"]["pri_in"],
- label="情感模型的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- emotion_model_pri_out = gr.Number(
- value=config_data["model"]["llm_emotion_judge"]["pri_out"],
- label="情感模型的输出价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- gr.Markdown("""### 主题模型设置""")
- with gr.Row():
- topic_judge_model_name = gr.Textbox(
- value=config_data["model"]["llm_topic_judge"]["name"], label="主题判断模型名称"
- )
- with gr.Row():
- topic_judge_model_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_topic_judge"]["provider"],
- label="主题判断模型提供商",
- )
- with gr.Row():
- topic_judge_model_pri_in = gr.Number(
- value=config_data["model"]["llm_topic_judge"]["pri_in"],
- label="主题判断模型的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- topic_judge_model_pri_out = gr.Number(
- value=config_data["model"]["llm_topic_judge"]["pri_out"],
- label="主题判断模型的输出价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- gr.Markdown("""### 主题总结模型设置""")
- with gr.Row():
- summary_by_topic_model_name = gr.Textbox(
- value=config_data["model"]["llm_summary_by_topic"]["name"], label="主题总结模型名称"
- )
- with gr.Row():
- summary_by_topic_model_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["llm_summary_by_topic"]["provider"],
- label="主题总结模型提供商",
- )
- with gr.Row():
- summary_by_topic_model_pri_in = gr.Number(
- value=config_data["model"]["llm_summary_by_topic"]["pri_in"],
- label="主题总结模型的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- summary_by_topic_model_pri_out = gr.Number(
- value=config_data["model"]["llm_summary_by_topic"]["pri_out"],
- label="主题总结模型的输出价格(非必填,可以记录消耗)",
- )
- with gr.TabItem("5-识图模型"):
- with gr.Row():
- gr.Markdown("""### 识图模型设置""")
- with gr.Row():
- vlm_model_name = gr.Textbox(
- value=config_data["model"]["vlm"]["name"], label="识图模型名称"
- )
- with gr.Row():
- vlm_model_provider = gr.Dropdown(
- choices=MODEL_PROVIDER_LIST,
- value=config_data["model"]["vlm"]["provider"],
- label="识图模型提供商",
- )
- with gr.Row():
- vlm_model_pri_in = gr.Number(
- value=config_data["model"]["vlm"]["pri_in"],
- label="识图模型的输入价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- vlm_model_pri_out = gr.Number(
- value=config_data["model"]["vlm"]["pri_out"],
- label="识图模型的输出价格(非必填,可以记录消耗)",
- )
- with gr.Row():
- save_model_btn = gr.Button("保存回复&模型设置", variant="primary", elem_id="save_model_btn")
- with gr.Row():
- save_btn_message = gr.Textbox()
- save_model_btn.click(
- save_response_model_config,
- inputs=[
- willing_mode,
- model_r1_probability,
- model_r2_probability,
- model_r3_probability,
- max_response_length,
- model1_name,
- model1_provider,
- model1_pri_in,
- model1_pri_out,
- model2_name,
- model2_provider,
- model2_pri_in,
- model2_pri_out,
- model3_name,
- model3_provider,
- model3_pri_in,
- model3_pri_out,
- emotion_model_name,
- emotion_model_provider,
- emotion_model_pri_in,
- emotion_model_pri_out,
- topic_judge_model_name,
- topic_judge_model_provider,
- topic_judge_model_pri_in,
- topic_judge_model_pri_out,
- summary_by_topic_model_name,
- summary_by_topic_model_provider,
- summary_by_topic_model_pri_in,
- summary_by_topic_model_pri_out,
- vlm_model_name,
- vlm_model_provider,
- vlm_model_pri_in,
- vlm_model_pri_out,
- ],
- outputs=[save_btn_message],
- )
- with gr.TabItem("5-记忆&心情设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- gr.Markdown("""### 记忆设置""")
- with gr.Row():
- build_memory_interval = gr.Number(
- value=config_data["memory"]["build_memory_interval"],
- label="记忆构建间隔 单位秒,间隔越低,麦麦学习越多,但是冗余信息也会增多",
- )
- if PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- with gr.Row():
- gr.Markdown("---")
- with gr.Row():
- gr.Markdown("""### 记忆构建分布设置""")
- with gr.Row():
- gr.Markdown("""记忆构建分布参数说明:\n
- 分布1均值:第一个正态分布的均值\n
- 分布1标准差:第一个正态分布的标准差\n
- 分布1权重:第一个正态分布的权重\n
- 分布2均值:第二个正态分布的均值\n
- 分布2标准差:第二个正态分布的标准差\n
- 分布2权重:第二个正态分布的权重
- """)
- with gr.Row():
- with gr.Column(scale=1):
- build_memory_dist1_mean = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[0],
- label="分布1均值",
- )
- with gr.Column(scale=1):
- build_memory_dist1_std = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[1],
- label="分布1标准差",
- )
- with gr.Column(scale=1):
- build_memory_dist1_weight = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[2],
- label="分布1权重",
- )
- with gr.Row():
- with gr.Column(scale=1):
- build_memory_dist2_mean = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[3],
- label="分布2均值",
- )
- with gr.Column(scale=1):
- build_memory_dist2_std = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[4],
- label="分布2标准差",
- )
- with gr.Column(scale=1):
- build_memory_dist2_weight = gr.Number(
- value=config_data["memory"].get(
- "build_memory_distribution",
- [4.0,2.0,0.6,24.0,8.0,0.4]
- )[5],
- label="分布2权重",
- )
- with gr.Row():
- gr.Markdown("---")
- else:
- build_memory_dist1_mean = gr.Number(value=0.0,visible=False,interactive=False)
- build_memory_dist1_std = gr.Number(value=0.0,visible=False,interactive=False)
- build_memory_dist1_weight = gr.Number(value=0.0,visible=False,interactive=False)
- build_memory_dist2_mean = gr.Number(value=0.0,visible=False,interactive=False)
- build_memory_dist2_std = gr.Number(value=0.0,visible=False,interactive=False)
- build_memory_dist2_weight = gr.Number(value=0.0,visible=False,interactive=False)
- with gr.Row():
- memory_compress_rate = gr.Number(
- value=config_data["memory"]["memory_compress_rate"],
- label="记忆压缩率 控制记忆精简程度 建议保持默认,调高可以获得更多信息,但是冗余信息也会增多",
- )
- with gr.Row():
- forget_memory_interval = gr.Number(
- value=config_data["memory"]["forget_memory_interval"],
- label="记忆遗忘间隔 单位秒 间隔越低,麦麦遗忘越频繁,记忆更精简,但更难学习",
- )
- with gr.Row():
- memory_forget_time = gr.Number(
- value=config_data["memory"]["memory_forget_time"],
- label="多长时间后的记忆会被遗忘 单位小时 ",
- )
- with gr.Row():
- memory_forget_percentage = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["memory"]["memory_forget_percentage"],
- label="记忆遗忘比例 控制记忆遗忘程度 越大遗忘越多 建议保持默认",
- )
- with gr.Row():
- memory_ban_words_list = config_data["memory"]["memory_ban_words"]
- with gr.Blocks():
- memory_ban_words_list_state = gr.State(value=memory_ban_words_list.copy())
-
- with gr.Row():
- memory_ban_words_list_display = gr.TextArea(
- value="\n".join(memory_ban_words_list),
- label="不希望记忆词列表",
- interactive=False,
- lines=5,
- )
- with gr.Row():
- with gr.Column(scale=3):
- memory_ban_words_new_item_input = gr.Textbox(label="添加不希望记忆词")
- memory_ban_words_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- memory_ban_words_item_to_delete = gr.Dropdown(
- choices=memory_ban_words_list, label="选择要删除的不希望记忆词"
- )
- memory_ban_words_delete_btn = gr.Button("删除", scale=1)
-
- memory_ban_words_final_result = gr.Text(label="修改后的不希望记忆词列表")
- memory_ban_words_add_btn.click(
- add_item,
- inputs=[memory_ban_words_new_item_input, memory_ban_words_list_state],
- outputs=[
- memory_ban_words_list_state,
- memory_ban_words_list_display,
- memory_ban_words_item_to_delete,
- memory_ban_words_final_result,
- ],
- )
-
- memory_ban_words_delete_btn.click(
- delete_item,
- inputs=[memory_ban_words_item_to_delete, memory_ban_words_list_state],
- outputs=[
- memory_ban_words_list_state,
- memory_ban_words_list_display,
- memory_ban_words_item_to_delete,
- memory_ban_words_final_result,
- ],
- )
- with gr.Row():
- mood_update_interval = gr.Number(
- value=config_data["mood"]["mood_update_interval"], label="心情更新间隔 单位秒"
- )
- with gr.Row():
- mood_decay_rate = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["mood"]["mood_decay_rate"],
- label="心情衰减率",
- )
- with gr.Row():
- mood_intensity_factor = gr.Number(
- value=config_data["mood"]["mood_intensity_factor"], label="心情强度因子"
- )
- with gr.Row():
- save_memory_mood_btn = gr.Button("保存记忆&心情设置", variant="primary")
- with gr.Row():
- save_memory_mood_message = gr.Textbox()
- with gr.Row():
- save_memory_mood_btn.click(
- save_memory_mood_config,
- inputs=[
- build_memory_interval,
- memory_compress_rate,
- forget_memory_interval,
- memory_forget_time,
- memory_forget_percentage,
- memory_ban_words_list_state,
- mood_update_interval,
- mood_decay_rate,
- mood_intensity_factor,
- build_memory_dist1_mean,
- build_memory_dist1_std,
- build_memory_dist1_weight,
- build_memory_dist2_mean,
- build_memory_dist2_std,
- build_memory_dist2_weight,
- ],
- outputs=[save_memory_mood_message],
- )
- with gr.TabItem("6-群组设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- gr.Markdown("""## 群组设置""")
- with gr.Row():
- gr.Markdown("""### 可以回复消息的群""")
- with gr.Row():
- talk_allowed_list = config_data["groups"]["talk_allowed"]
- with gr.Blocks():
- talk_allowed_list_state = gr.State(value=talk_allowed_list.copy())
-
- with gr.Row():
- talk_allowed_list_display = gr.TextArea(
- value="\n".join(map(str, talk_allowed_list)),
- label="可以回复消息的群列表",
- interactive=False,
- lines=5,
- )
- with gr.Row():
- with gr.Column(scale=3):
- talk_allowed_new_item_input = gr.Textbox(label="添加新群")
- talk_allowed_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- talk_allowed_item_to_delete = gr.Dropdown(
- choices=talk_allowed_list, label="选择要删除的群"
- )
- talk_allowed_delete_btn = gr.Button("删除", scale=1)
-
- talk_allowed_final_result = gr.Text(label="修改后的可以回复消息的群列表")
- talk_allowed_add_btn.click(
- add_int_item,
- inputs=[talk_allowed_new_item_input, talk_allowed_list_state],
- outputs=[
- talk_allowed_list_state,
- talk_allowed_list_display,
- talk_allowed_item_to_delete,
- talk_allowed_final_result,
- ],
- )
-
- talk_allowed_delete_btn.click(
- delete_int_item,
- inputs=[talk_allowed_item_to_delete, talk_allowed_list_state],
- outputs=[
- talk_allowed_list_state,
- talk_allowed_list_display,
- talk_allowed_item_to_delete,
- talk_allowed_final_result,
- ],
- )
- with gr.Row():
- talk_frequency_down_list = config_data["groups"]["talk_frequency_down"]
- with gr.Blocks():
- talk_frequency_down_list_state = gr.State(value=talk_frequency_down_list.copy())
-
- with gr.Row():
- talk_frequency_down_list_display = gr.TextArea(
- value="\n".join(map(str, talk_frequency_down_list)),
- label="降低回复频率的群列表",
- interactive=False,
- lines=5,
- )
- with gr.Row():
- with gr.Column(scale=3):
- talk_frequency_down_new_item_input = gr.Textbox(label="添加新群")
- talk_frequency_down_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- talk_frequency_down_item_to_delete = gr.Dropdown(
- choices=talk_frequency_down_list, label="选择要删除的群"
- )
- talk_frequency_down_delete_btn = gr.Button("删除", scale=1)
-
- talk_frequency_down_final_result = gr.Text(label="修改后的降低回复频率的群列表")
- talk_frequency_down_add_btn.click(
- add_int_item,
- inputs=[talk_frequency_down_new_item_input, talk_frequency_down_list_state],
- outputs=[
- talk_frequency_down_list_state,
- talk_frequency_down_list_display,
- talk_frequency_down_item_to_delete,
- talk_frequency_down_final_result,
- ],
- )
-
- talk_frequency_down_delete_btn.click(
- delete_int_item,
- inputs=[talk_frequency_down_item_to_delete, talk_frequency_down_list_state],
- outputs=[
- talk_frequency_down_list_state,
- talk_frequency_down_list_display,
- talk_frequency_down_item_to_delete,
- talk_frequency_down_final_result,
- ],
- )
- with gr.Row():
- ban_user_id_list = config_data["groups"]["ban_user_id"]
- with gr.Blocks():
- ban_user_id_list_state = gr.State(value=ban_user_id_list.copy())
-
- with gr.Row():
- ban_user_id_list_display = gr.TextArea(
- value="\n".join(map(str, ban_user_id_list)),
- label="禁止回复消息的QQ号列表",
- interactive=False,
- lines=5,
- )
- with gr.Row():
- with gr.Column(scale=3):
- ban_user_id_new_item_input = gr.Textbox(label="添加新QQ号")
- ban_user_id_add_btn = gr.Button("添加", scale=1)
-
- with gr.Row():
- with gr.Column(scale=3):
- ban_user_id_item_to_delete = gr.Dropdown(
- choices=ban_user_id_list, label="选择要删除的QQ号"
- )
- ban_user_id_delete_btn = gr.Button("删除", scale=1)
-
- ban_user_id_final_result = gr.Text(label="修改后的禁止回复消息的QQ号列表")
- ban_user_id_add_btn.click(
- add_int_item,
- inputs=[ban_user_id_new_item_input, ban_user_id_list_state],
- outputs=[
- ban_user_id_list_state,
- ban_user_id_list_display,
- ban_user_id_item_to_delete,
- ban_user_id_final_result,
- ],
- )
-
- ban_user_id_delete_btn.click(
- delete_int_item,
- inputs=[ban_user_id_item_to_delete, ban_user_id_list_state],
- outputs=[
- ban_user_id_list_state,
- ban_user_id_list_display,
- ban_user_id_item_to_delete,
- ban_user_id_final_result,
- ],
- )
- with gr.Row():
- save_group_btn = gr.Button("保存群组设置", variant="primary")
- with gr.Row():
- save_group_btn_message = gr.Textbox()
- with gr.Row():
- save_group_btn.click(
- save_group_config,
- inputs=[
- talk_allowed_list_state,
- talk_frequency_down_list_state,
- ban_user_id_list_state,
- ],
- outputs=[save_group_btn_message],
- )
- with gr.TabItem("7-其他设置"):
- with gr.Row():
- with gr.Column(scale=3):
- with gr.Row():
- gr.Markdown("""### 其他设置""")
- with gr.Row():
- keywords_reaction_enabled = gr.Checkbox(
- value=config_data["keywords_reaction"]["enable"], label="是否针对某个关键词作出反应"
- )
- if PARSED_CONFIG_VERSION <= version.parse("0.0.10"):
- with gr.Row():
- enable_advance_output = gr.Checkbox(
- value=config_data["others"]["enable_advance_output"], label="是否开启高级输出"
- )
- with gr.Row():
- enable_kuuki_read = gr.Checkbox(
- value=config_data["others"]["enable_kuuki_read"], label="是否启用读空气功能"
- )
- with gr.Row():
- enable_debug_output = gr.Checkbox(
- value=config_data["others"]["enable_debug_output"], label="是否开启调试输出"
- )
- with gr.Row():
- enable_friend_chat = gr.Checkbox(
- value=config_data["others"]["enable_friend_chat"], label="是否开启好友聊天"
- )
- elif PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- with gr.Row():
- enable_friend_chat = gr.Checkbox(
- value=config_data["experimental"]["enable_friend_chat"], label="是否开启好友聊天"
- )
- enable_advance_output = gr.Checkbox(value=False,visible=False,interactive=False)
- enable_kuuki_read = gr.Checkbox(value=False,visible=False,interactive=False)
- enable_debug_output = gr.Checkbox(value=False,visible=False,interactive=False)
- if PARSED_CONFIG_VERSION > HAVE_ONLINE_STATUS_VERSION:
- with gr.Row():
- gr.Markdown(
- """### 远程统计设置\n
- 测试功能,发送统计信息,主要是看全球有多少只麦麦
- """
- )
- with gr.Row():
- remote_status = gr.Checkbox(
- value=config_data["remote"]["enable"], label="是否开启麦麦在线全球统计"
- )
- if PARSED_CONFIG_VERSION >= version.parse("0.0.11"):
- with gr.Row():
- gr.Markdown("""### 回复分割器设置""")
- with gr.Row():
- enable_response_spliter = gr.Checkbox(
- value=config_data["response_spliter"]["enable_response_spliter"],
- label="是否启用回复分割器"
- )
- with gr.Row():
- response_max_length = gr.Number(
- value=config_data["response_spliter"]["response_max_length"],
- label="回复允许的最大长度"
- )
- with gr.Row():
- response_max_sentence_num = gr.Number(
- value=config_data["response_spliter"]["response_max_sentence_num"],
- label="回复允许的最大句子数"
- )
- else:
- enable_response_spliter = gr.Checkbox(value=False,visible=False,interactive=False)
- response_max_length = gr.Number(value=0,visible=False,interactive=False)
- response_max_sentence_num = gr.Number(value=0,visible=False,interactive=False)
- with gr.Row():
- gr.Markdown("""### 中文错别字设置""")
- with gr.Row():
- chinese_typo_enabled = gr.Checkbox(
- value=config_data["chinese_typo"]["enable"], label="是否开启中文错别字"
- )
- with gr.Row():
- error_rate = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.001,
- value=config_data["chinese_typo"]["error_rate"],
- label="单字替换概率",
- )
- with gr.Row():
- min_freq = gr.Number(value=config_data["chinese_typo"]["min_freq"], label="最小字频阈值")
- with gr.Row():
- tone_error_rate = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.01,
- value=config_data["chinese_typo"]["tone_error_rate"],
- label="声调错误概率",
- )
- with gr.Row():
- word_replace_rate = gr.Slider(
- minimum=0,
- maximum=1,
- step=0.001,
- value=config_data["chinese_typo"]["word_replace_rate"],
- label="整词替换概率",
- )
- with gr.Row():
- save_other_config_btn = gr.Button("保存其他配置", variant="primary")
- with gr.Row():
- save_other_config_message = gr.Textbox()
- with gr.Row():
- if PARSED_CONFIG_VERSION <= HAVE_ONLINE_STATUS_VERSION:
- remote_status = gr.Checkbox(value=False, visible=False)
- save_other_config_btn.click(
- save_other_config,
- inputs=[
- keywords_reaction_enabled,
- enable_advance_output,
- enable_kuuki_read,
- enable_debug_output,
- enable_friend_chat,
- chinese_typo_enabled,
- error_rate,
- min_freq,
- tone_error_rate,
- word_replace_rate,
- remote_status,
- enable_response_spliter,
- response_max_length,
- response_max_sentence_num
- ],
- outputs=[save_other_config_message],
- )
-# 检查端口是否可用
-def is_port_available(port, host='0.0.0.0'):
- """检查指定的端口是否可用"""
- try:
- # 创建一个socket对象
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- # 设置socket重用地址选项
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- # 尝试绑定端口
- sock.bind((host, port))
- # 如果成功绑定,则关闭socket并返回True
- sock.close()
- return True
- except socket.error:
- # 如果绑定失败,说明端口已被占用
- return False
-
-
- # 寻找可用端口
-def find_available_port(start_port=7000, max_port=8000):
- """
- 从start_port开始,寻找可用的端口
- 如果端口被占用,尝试下一个端口,直到找到可用端口或达到max_port
- """
- port = start_port
- while port <= max_port:
- if is_port_available(port):
- logger.info(f"找到可用端口: {port}")
- return port
- logger.warning(f"端口 {port} 已被占用,尝试下一个端口")
- port += 1
- # 如果所有端口都被占用,返回None
- logger.error(f"无法找到可用端口 (已尝试 {start_port}-{max_port})")
- return None
-
-# 寻找可用端口
-launch_port = find_available_port(7000, 8000) or 7000
-
-app.queue().launch( # concurrency_count=511, max_size=1022
- server_name="0.0.0.0",
- inbrowser=True,
- share=is_share,
- server_port=launch_port,
- debug=debug,
- quiet=True,
-)
-
diff --git a/webui_conda.bat b/webui_conda.bat
deleted file mode 100644
index 02a11327..00000000
--- a/webui_conda.bat
+++ /dev/null
@@ -1,28 +0,0 @@
-@echo on
-echo Starting script...
-echo Activating conda environment: maimbot
-call conda activate maimbot
-if errorlevel 1 (
- echo Failed to activate conda environment
- pause
- exit /b 1
-)
-echo Conda environment activated successfully
-echo Changing directory to C:\GitHub\MaiMBot
-cd /d C:\GitHub\MaiMBot
-if errorlevel 1 (
- echo Failed to change directory
- pause
- exit /b 1
-)
-echo Current directory is:
-cd
-
-python webui.py
-if errorlevel 1 (
- echo Command failed with error code %errorlevel%
- pause
- exit /b 1
-)
-echo Script completed successfully
-pause
\ No newline at end of file
diff --git a/如果你的配置文件版本太老就点我.bat b/如果你的配置文件版本太老就点我.bat
deleted file mode 100644
index fec1f4cd..00000000
--- a/如果你的配置文件版本太老就点我.bat
+++ /dev/null
@@ -1,45 +0,0 @@
-@echo off
-setlocal enabledelayedexpansion
-chcp 65001
-cd /d %~dp0
-
-echo =====================================
-echo 选择Python环境:
-echo 1 - venv (推荐)
-echo 2 - conda
-echo =====================================
-choice /c 12 /n /m "输入数字(1或2): "
-
-if errorlevel 2 (
- echo =====================================
- set "CONDA_ENV="
- set /p CONDA_ENV="请输入要激活的 conda 环境名称: "
-
- :: 检查输入是否为空
- if "!CONDA_ENV!"=="" (
- echo 错误:环境名称不能为空
- pause
- exit /b 1
- )
-
- call conda activate !CONDA_ENV!
- if errorlevel 1 (
- echo 激活 conda 环境失败
- pause
- exit /b 1
- )
-
- echo Conda 环境 "!CONDA_ENV!" 激活成功
- python config/auto_update.py
-) else (
- if exist "venv\Scripts\python.exe" (
- venv\Scripts\python config/auto_update.py
- ) else (
- echo =====================================
- echo 错误: venv环境不存在,请先创建虚拟环境
- pause
- exit /b 1
- )
-)
-endlocal
-pause
diff --git a/配置文件错误排查.py b/配置文件错误排查.py
deleted file mode 100644
index 50f5af1a..00000000
--- a/配置文件错误排查.py
+++ /dev/null
@@ -1,633 +0,0 @@
-import tomli
-import sys
-from pathlib import Path
-from typing import Dict, Any, List, Tuple
-
-def load_toml_file(file_path: str) -> Dict[str, Any]:
- """加载TOML文件"""
- try:
- with open(file_path, "rb") as f:
- return tomli.load(f)
- except Exception as e:
- print(f"错误: 无法加载配置文件 {file_path}: {str(e)} 请检查文件是否存在或者他妈的有没有东西没写值")
- sys.exit(1)
-
-def load_env_file(file_path: str) -> Dict[str, str]:
- """加载.env文件中的环境变量"""
- env_vars = {}
- try:
- with open(file_path, 'r', encoding='utf-8') as f:
- for line in f:
- line = line.strip()
- if not line or line.startswith('#'):
- continue
- if '=' in line:
- key, value = line.split('=', 1)
- key = key.strip()
- value = value.strip()
-
- # 处理注释
- if '#' in value:
- value = value.split('#', 1)[0].strip()
-
- # 处理引号
- if (value.startswith('"') and value.endswith('"')) or \
- (value.startswith("'") and value.endswith("'")):
- value = value[1:-1]
-
- env_vars[key] = value
- return env_vars
- except Exception as e:
- print(f"警告: 无法加载.env文件 {file_path}: {str(e)}")
- return {}
-
-def check_required_sections(config: Dict[str, Any]) -> List[str]:
- """检查必要的配置段是否存在"""
- required_sections = [
- "inner", "bot", "personality", "message", "emoji",
- "cq_code", "response", "willing", "memory", "mood",
- "groups", "model"
- ]
- missing_sections = []
-
- for section in required_sections:
- if section not in config:
- missing_sections.append(section)
-
- return missing_sections
-
-def check_probability_sum(config: Dict[str, Any]) -> List[Tuple[str, float]]:
- """检查概率总和是否为1"""
- errors = []
-
- # 检查人格概率
- if "personality" in config:
- personality = config["personality"]
- prob_sum = sum([
- personality.get("personality_1_probability", 0),
- personality.get("personality_2_probability", 0),
- personality.get("personality_3_probability", 0)
- ])
- if abs(prob_sum - 1.0) > 0.001: # 允许有小数点精度误差
- errors.append(("人格概率总和", prob_sum))
-
- # 检查响应模型概率
- if "response" in config:
- response = config["response"]
- model_prob_sum = sum([
- response.get("model_r1_probability", 0),
- response.get("model_v3_probability", 0),
- response.get("model_r1_distill_probability", 0)
- ])
- if abs(model_prob_sum - 1.0) > 0.001:
- errors.append(("响应模型概率总和", model_prob_sum))
-
- return errors
-
-def check_probability_range(config: Dict[str, Any]) -> List[Tuple[str, float]]:
- """检查概率值是否在0-1范围内"""
- errors = []
-
- # 收集所有概率值
- prob_fields = []
-
- # 人格概率
- if "personality" in config:
- personality = config["personality"]
- prob_fields.extend([
- ("personality.personality_1_probability", personality.get("personality_1_probability")),
- ("personality.personality_2_probability", personality.get("personality_2_probability")),
- ("personality.personality_3_probability", personality.get("personality_3_probability"))
- ])
-
- # 消息概率
- if "message" in config:
- message = config["message"]
- prob_fields.append(("message.emoji_chance", message.get("emoji_chance")))
-
- # 响应模型概率
- if "response" in config:
- response = config["response"]
- prob_fields.extend([
- ("response.model_r1_probability", response.get("model_r1_probability")),
- ("response.model_v3_probability", response.get("model_v3_probability")),
- ("response.model_r1_distill_probability", response.get("model_r1_distill_probability"))
- ])
-
- # 情绪衰减率
- if "mood" in config:
- mood = config["mood"]
- prob_fields.append(("mood.mood_decay_rate", mood.get("mood_decay_rate")))
-
- # 中文错别字概率
- if "chinese_typo" in config and config["chinese_typo"].get("enable", False):
- typo = config["chinese_typo"]
- prob_fields.extend([
- ("chinese_typo.error_rate", typo.get("error_rate")),
- ("chinese_typo.tone_error_rate", typo.get("tone_error_rate")),
- ("chinese_typo.word_replace_rate", typo.get("word_replace_rate"))
- ])
-
- # 检查所有概率值是否在0-1范围内
- for field_name, value in prob_fields:
- if value is not None and (value < 0 or value > 1):
- errors.append((field_name, value))
-
- return errors
-
-def check_model_configurations(config: Dict[str, Any], env_vars: Dict[str, str]) -> List[str]:
- """检查模型配置是否完整,并验证provider是否正确"""
- errors = []
-
- if "model" not in config:
- return ["缺少[model]部分"]
-
- required_models = [
- "llm_reasoning", "llm_reasoning_minor", "llm_normal",
- "llm_normal_minor", "llm_emotion_judge", "llm_topic_judge",
- "llm_summary_by_topic", "vlm", "embedding"
- ]
-
- # 从环境变量中提取有效的API提供商
- valid_providers = set()
- for key in env_vars:
- if key.endswith('_BASE_URL'):
- provider_name = key.replace('_BASE_URL', '')
- valid_providers.add(provider_name)
-
- # 将provider名称标准化以便比较
- provider_mapping = {
- "SILICONFLOW": ["SILICONFLOW", "SILICON_FLOW", "SILICON-FLOW"],
- "CHAT_ANY_WHERE": ["CHAT_ANY_WHERE", "CHAT-ANY-WHERE", "CHATANYWHERE"],
- "DEEP_SEEK": ["DEEP_SEEK", "DEEP-SEEK", "DEEPSEEK"]
- }
-
- # 创建反向映射表,用于检查错误拼写
- reverse_mapping = {}
- for standard, variants in provider_mapping.items():
- for variant in variants:
- reverse_mapping[variant.upper()] = standard
-
- for model_name in required_models:
- # 检查model下是否有对应子部分
- if model_name not in config["model"]:
- errors.append(f"缺少[model.{model_name}]配置")
- else:
- model_config = config["model"][model_name]
- if "name" not in model_config:
- errors.append(f"[model.{model_name}]缺少name属性")
-
- if "provider" not in model_config:
- errors.append(f"[model.{model_name}]缺少provider属性")
- else:
- provider = model_config["provider"].upper()
-
- # 检查拼写错误
- for known_provider, _correct_provider in reverse_mapping.items():
- # 使用模糊匹配检测拼写错误
- if (provider != known_provider and
- _similar_strings(provider, known_provider) and
- provider not in reverse_mapping):
- errors.append(
- f"[model.{model_name}]的provider '{model_config['provider']}' "
- f"可能拼写错误,应为 '{known_provider}'"
- )
- break
-
- return errors
-
-def _similar_strings(s1: str, s2: str) -> bool:
- """简单检查两个字符串是否相似(用于检测拼写错误)"""
- # 如果两个字符串长度相差过大,则认为不相似
- if abs(len(s1) - len(s2)) > 2:
- return False
-
- # 计算相同字符的数量
- common_chars = sum(1 for c1, c2 in zip(s1, s2) if c1 == c2)
- # 如果相同字符比例超过80%,则认为相似
- return common_chars / max(len(s1), len(s2)) > 0.8
-
-def check_api_providers(config: Dict[str, Any], env_vars: Dict[str, str]) -> List[str]:
- """检查配置文件中的API提供商是否与环境变量中的一致"""
- errors = []
-
- if "model" not in config:
- return ["缺少[model]部分"]
-
- # 从环境变量中提取有效的API提供商
- valid_providers = {}
- for key in env_vars:
- if key.endswith('_BASE_URL'):
- provider_name = key.replace('_BASE_URL', '')
- base_url = env_vars[key]
- valid_providers[provider_name] = {
- "base_url": base_url,
- "key": env_vars.get(f"{provider_name}_KEY", "")
- }
-
- # 检查配置文件中使用的所有提供商
- used_providers = set()
- for _model_category, model_config in config["model"].items():
- if "provider" in model_config:
- provider = model_config["provider"]
- used_providers.add(provider)
-
- # 检查此提供商是否在环境变量中定义
- normalized_provider = provider.replace(" ", "_").upper()
- found = False
- for env_provider in valid_providers:
- if normalized_provider == env_provider:
- found = True
- break
- # 尝试更宽松的匹配(例如SILICONFLOW可能匹配SILICON_FLOW)
- elif normalized_provider.replace("_", "") == env_provider.replace("_", ""):
- found = True
- errors.append(f"提供商 '{provider}' 在环境变量中的名称是 '{env_provider}', 建议统一命名")
- break
-
- if not found:
- errors.append(f"提供商 '{provider}' 在环境变量中未定义")
-
- # 特别检查常见的拼写错误
- for provider in used_providers:
- if provider.upper() == "SILICONFOLW":
- errors.append("提供商 'SILICONFOLW' 存在拼写错误,应为 'SILICONFLOW'")
-
- return errors
-
-def check_groups_configuration(config: Dict[str, Any]) -> List[str]:
- """检查群组配置"""
- errors = []
-
- if "groups" not in config:
- return ["缺少[groups]部分"]
-
- groups = config["groups"]
-
- # 检查talk_allowed是否为列表
- if "talk_allowed" not in groups:
- errors.append("缺少groups.talk_allowed配置")
- elif not isinstance(groups["talk_allowed"], list):
- errors.append("groups.talk_allowed应该是一个列表")
- else:
- # 检查talk_allowed是否包含默认示例值123
- if 123 in groups["talk_allowed"]:
- errors.append({
- "main": "groups.talk_allowed中存在默认示例值'123',请修改为真实的群号",
- "details": [
- f" 当前值: {groups['talk_allowed']}",
- " '123'为示例值,需要替换为真实群号"
- ]
- })
-
- # 检查是否存在重复的群号
- talk_allowed = groups["talk_allowed"]
- duplicates = []
- seen = set()
- for gid in talk_allowed:
- if gid in seen and gid not in duplicates:
- duplicates.append(gid)
- seen.add(gid)
-
- if duplicates:
- errors.append({
- "main": "groups.talk_allowed中存在重复的群号",
- "details": [f" 重复的群号: {duplicates}"]
- })
-
- # 检查其他群组配置
- if "talk_frequency_down" in groups and not isinstance(groups["talk_frequency_down"], list):
- errors.append("groups.talk_frequency_down应该是一个列表")
-
- if "ban_user_id" in groups and not isinstance(groups["ban_user_id"], list):
- errors.append("groups.ban_user_id应该是一个列表")
-
- return errors
-
-def check_keywords_reaction(config: Dict[str, Any]) -> List[str]:
- """检查关键词反应配置"""
- errors = []
-
- if "keywords_reaction" not in config:
- return ["缺少[keywords_reaction]部分"]
-
- kr = config["keywords_reaction"]
-
- # 检查enable字段
- if "enable" not in kr:
- errors.append("缺少keywords_reaction.enable配置")
-
- # 检查规则配置
- if "rules" not in kr:
- errors.append("缺少keywords_reaction.rules配置")
- elif not isinstance(kr["rules"], list):
- errors.append("keywords_reaction.rules应该是一个列表")
- else:
- for i, rule in enumerate(kr["rules"]):
- if "enable" not in rule:
- errors.append(f"关键词规则 #{i+1} 缺少enable字段")
- if "keywords" not in rule:
- errors.append(f"关键词规则 #{i+1} 缺少keywords字段")
- elif not isinstance(rule["keywords"], list):
- errors.append(f"关键词规则 #{i+1} 的keywords应该是一个列表")
- if "reaction" not in rule:
- errors.append(f"关键词规则 #{i+1} 缺少reaction字段")
-
- return errors
-
-def check_willing_mode(config: Dict[str, Any]) -> List[str]:
- """检查回复意愿模式配置"""
- errors = []
-
- if "willing" not in config:
- return ["缺少[willing]部分"]
-
- willing = config["willing"]
-
- if "willing_mode" not in willing:
- errors.append("缺少willing.willing_mode配置")
- elif willing["willing_mode"] not in ["classical", "dynamic", "custom"]:
- errors.append(f"willing.willing_mode值无效: {willing['willing_mode']}, 应为classical/dynamic/custom")
-
- return errors
-
-def check_memory_config(config: Dict[str, Any]) -> List[str]:
- """检查记忆系统配置"""
- errors = []
-
- if "memory" not in config:
- return ["缺少[memory]部分"]
-
- memory = config["memory"]
-
- # 检查必要的参数
- required_fields = [
- "build_memory_interval", "memory_compress_rate",
- "forget_memory_interval", "memory_forget_time",
- "memory_forget_percentage"
- ]
-
- for field in required_fields:
- if field not in memory:
- errors.append(f"缺少memory.{field}配置")
-
- # 检查参数值的有效性
- if "memory_compress_rate" in memory and (memory["memory_compress_rate"] <= 0 or memory["memory_compress_rate"] > 1):
- errors.append(f"memory.memory_compress_rate值无效: {memory['memory_compress_rate']}, 应在0-1之间")
-
- if ("memory_forget_percentage" in memory
- and (memory["memory_forget_percentage"] <= 0 or memory["memory_forget_percentage"] > 1)):
- errors.append(f"memory.memory_forget_percentage值无效: {memory['memory_forget_percentage']}, 应在0-1之间")
-
- return errors
-
-def check_personality_config(config: Dict[str, Any]) -> List[str]:
- """检查人格配置"""
- errors = []
-
- if "personality" not in config:
- return ["缺少[personality]部分"]
-
- personality = config["personality"]
-
- # 检查prompt_personality是否存在且为数组
- if "prompt_personality" not in personality:
- errors.append("缺少personality.prompt_personality配置")
- elif not isinstance(personality["prompt_personality"], list):
- errors.append("personality.prompt_personality应该是一个数组")
- else:
- # 检查数组长度
- if len(personality["prompt_personality"]) < 1:
- errors.append(
- f"personality.prompt_personality至少需要1项,"
- f"当前长度: {len(personality['prompt_personality'])}"
- )
- else:
- # 模板默认值
- template_values = [
- "用一句话或几句话描述性格特点和其他特征",
- "用一句话或几句话描述性格特点和其他特征",
- "例如,是一个热爱国家热爱党的新时代好青年"
- ]
-
- # 检查是否仍然使用默认模板值
- error_details = []
- for i, (current, template) in enumerate(zip(personality["prompt_personality"][:3], template_values)):
- if current == template:
- error_details.append({
- "main": f"personality.prompt_personality第{i+1}项仍使用默认模板值,请自定义",
- "details": [
- f" 当前值: '{current}'",
- f" 请不要使用模板值: '{template}'"
- ]
- })
-
- # 将错误添加到errors列表
- for error in error_details:
- errors.append(error)
-
- return errors
-
-def check_bot_config(config: Dict[str, Any]) -> List[str]:
- """检查机器人基础配置"""
- errors = []
- infos = []
-
- if "bot" not in config:
- return ["缺少[bot]部分"]
-
- bot = config["bot"]
-
- # 检查QQ号是否为默认值或测试值
- if "qq" not in bot:
- errors.append("缺少bot.qq配置")
- elif bot["qq"] == 1 or bot["qq"] == 123:
- errors.append(f"QQ号 '{bot['qq']}' 似乎是默认值或测试值,请设置为真实的QQ号")
- else:
- infos.append(f"当前QQ号: {bot['qq']}")
-
- # 检查昵称是否设置
- if "nickname" not in bot or not bot["nickname"]:
- errors.append("缺少bot.nickname配置或昵称为空")
- elif bot["nickname"]:
- infos.append(f"当前昵称: {bot['nickname']}")
-
- # 检查别名是否为列表
- if "alias_names" in bot and not isinstance(bot["alias_names"], list):
- errors.append("bot.alias_names应该是一个列表")
-
- return errors, infos
-
-def format_results(all_errors):
- """格式化检查结果"""
- sections_errors, prob_sum_errors, prob_range_errors, model_errors, api_errors, groups_errors, kr_errors, willing_errors, memory_errors, personality_errors, bot_results = all_errors # noqa: E501, F821
- bot_errors, bot_infos = bot_results
-
- if not any([
- sections_errors, prob_sum_errors,
- prob_range_errors, model_errors, api_errors, groups_errors,
- kr_errors, willing_errors, memory_errors, personality_errors, bot_errors]):
- result = "✅ 配置文件检查通过,未发现问题。"
-
- # 添加机器人信息
- if bot_infos:
- result += "\n\n【机器人信息】"
- for info in bot_infos:
- result += f"\n - {info}"
-
- return result
-
- output = []
- output.append("❌ 配置文件检查发现以下问题:")
-
- if sections_errors:
- output.append("\n【缺失的配置段】")
- for section in sections_errors:
- output.append(f" - {section}")
-
- if prob_sum_errors:
- output.append("\n【概率总和错误】(应为1.0)")
- for name, value in prob_sum_errors:
- output.append(f" - {name}: {value:.4f}")
-
- if prob_range_errors:
- output.append("\n【概率值范围错误】(应在0-1之间)")
- for name, value in prob_range_errors:
- output.append(f" - {name}: {value}")
-
- if model_errors:
- output.append("\n【模型配置错误】")
- for error in model_errors:
- output.append(f" - {error}")
-
- if api_errors:
- output.append("\n【API提供商错误】")
- for error in api_errors:
- output.append(f" - {error}")
-
- if groups_errors:
- output.append("\n【群组配置错误】")
- for error in groups_errors:
- if isinstance(error, dict):
- output.append(f" - {error['main']}")
- for detail in error['details']:
- output.append(f"{detail}")
- else:
- output.append(f" - {error}")
-
- if kr_errors:
- output.append("\n【关键词反应配置错误】")
- for error in kr_errors:
- output.append(f" - {error}")
-
- if willing_errors:
- output.append("\n【回复意愿配置错误】")
- for error in willing_errors:
- output.append(f" - {error}")
-
- if memory_errors:
- output.append("\n【记忆系统配置错误】")
- for error in memory_errors:
- output.append(f" - {error}")
-
- if personality_errors:
- output.append("\n【人格配置错误】")
- for error in personality_errors:
- if isinstance(error, dict):
- output.append(f" - {error['main']}")
- for detail in error['details']:
- output.append(f"{detail}")
- else:
- output.append(f" - {error}")
-
- if bot_errors:
- output.append("\n【机器人基础配置错误】")
- for error in bot_errors:
- output.append(f" - {error}")
-
- # 添加机器人信息,即使有错误
- if bot_infos:
- output.append("\n【机器人信息】")
- for info in bot_infos:
- output.append(f" - {info}")
-
- return "\n".join(output)
-
-def main():
- # 获取配置文件路径
- config_path = Path("config/bot_config.toml")
- env_path = Path(".env")
-
- if not config_path.exists():
- print(f"错误: 找不到配置文件 {config_path}")
- return
-
- if not env_path.exists():
- print(f"警告: 找不到环境变量文件 {env_path}, 将跳过API提供商检查")
- env_vars = {}
- else:
- env_vars = load_env_file(env_path)
-
- # 加载配置文件
- config = load_toml_file(config_path)
-
- # 运行各种检查
- sections_errors = check_required_sections(config)
- prob_sum_errors = check_probability_sum(config)
- prob_range_errors = check_probability_range(config)
- model_errors = check_model_configurations(config, env_vars)
- api_errors = check_api_providers(config, env_vars)
- groups_errors = check_groups_configuration(config)
- kr_errors = check_keywords_reaction(config)
- willing_errors = check_willing_mode(config)
- memory_errors = check_memory_config(config)
- personality_errors = check_personality_config(config)
- bot_results = check_bot_config(config)
-
- # 格式化并打印结果
- all_errors = (
- sections_errors, prob_sum_errors,
- prob_range_errors, model_errors, api_errors, groups_errors,
- kr_errors, willing_errors, memory_errors, personality_errors, bot_results)
- result = format_results(all_errors)
- print("📋 机器人配置检查结果:")
- print(result)
-
- # 综合评估
- total_errors = 0
-
- # 解包bot_results
- bot_errors, _ = bot_results
-
- # 计算普通错误列表的长度
- for errors in [
- sections_errors, model_errors, api_errors,
- groups_errors, kr_errors, willing_errors, memory_errors, bot_errors]:
- total_errors += len(errors)
-
- # 计算元组列表的长度(概率相关错误)
- total_errors += len(prob_sum_errors)
- total_errors += len(prob_range_errors)
-
- # 特殊处理personality_errors和groups_errors
- for errors_list in [personality_errors, groups_errors]:
- for error in errors_list:
- if isinstance(error, dict):
- # 每个字典表示一个错误,而不是每行都算一个
- total_errors += 1
- else:
- total_errors += 1
-
- if total_errors > 0:
- print(f"\n总计发现 {total_errors} 个配置问题。")
- print("\n建议:")
- print("1. 修复所有错误后再运行机器人")
- print("2. 特别注意拼写错误,例如不!要!写!错!别!字!!!!!")
- print("3. 确保所有API提供商名称与环境变量中一致")
- print("4. 检查概率值设置,确保总和为1")
- else:
- print("\n您的配置文件完全正确!机器人可以正常运行。")
-
-if __name__ == "__main__":
- main()
- input("\n按任意键退出...")
\ No newline at end of file
diff --git a/麦麦开始学习.bat b/麦麦开始学习.bat
deleted file mode 100644
index f96d7cfd..00000000
--- a/麦麦开始学习.bat
+++ /dev/null
@@ -1,56 +0,0 @@
-@echo off
-chcp 65001 > nul
-setlocal enabledelayedexpansion
-cd /d %~dp0
-
-title 麦麦学习系统
-
-cls
-echo ======================================
-echo 警告提示
-echo ======================================
-echo 1.这是一个demo系统,不完善不稳定,仅用于体验/不要塞入过长过大的文本,这会导致信息提取迟缓
-echo ======================================
-
-echo.
-echo ======================================
-echo 请选择Python环境:
-echo 1 - venv (推荐)
-echo 2 - conda
-echo ======================================
-choice /c 12 /n /m "请输入数字选择(1或2): "
-
-if errorlevel 2 (
- echo ======================================
- set "CONDA_ENV="
- set /p CONDA_ENV="请输入要激活的 conda 环境名称: "
-
- :: 检查输入是否为空
- if "!CONDA_ENV!"=="" (
- echo 错误:环境名称不能为空
- pause
- exit /b 1
- )
-
- call conda activate !CONDA_ENV!
- if errorlevel 1 (
- echo 激活 conda 环境失败
- pause
- exit /b 1
- )
-
- echo Conda 环境 "!CONDA_ENV!" 激活成功
- python src/plugins/zhishi/knowledge_library.py
-) else (
- if exist "venv\Scripts\python.exe" (
- venv\Scripts\python src/plugins/zhishi/knowledge_library.py
- ) else (
- echo ======================================
- echo 错误: venv环境不存在,请先创建虚拟环境
- pause
- exit /b 1
- )
-)
-
-endlocal
-pause