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=" -) else if "!BRANCH!"=="main-fix" ( - set "BRANCH_COLOR=" -@REM ) else if "%BRANCH%"=="stable-dev" ( -@REM set "BRANCH_COLOR=" -) else ( - set "BRANCH_COLOR=" -) - -@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% -echo 当前Python环境: !PYTHON_HOME! -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% -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. 切换到main -echo 2. 切换到main-fix -echo 请输入要切换到的分支: -set /p branch_name="分支名: " -if "%branch_name%"=="" set branch_name=main -if "%branch_name%"=="main" ( - set "BRANCH_COLOR=" -) else if "%branch_name%"=="main-fix" ( - set "BRANCH_COLOR=" -@REM ) else if "%branch_name%"=="stable-dev" ( -@REM set "BRANCH_COLOR=" -) else if "%branch_name%"=="1" ( - set "BRANCH_COLOR=" - set "branch_name=main" -) else if "%branch_name%"=="2" ( - set "BRANCH_COLOR=" - 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% -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`中自行选择: - -![](./pic/MongoDB_Ubuntu_guide.png) - - -不想使用上述方式?你也可以参考[官方文档](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 -![](./pic/QQ_Download_guide_Linux.png) -如果你不想使用Napcat的脚本安装,还需参考[Napcat-Linux手动安装](https://www.napcat.wiki/guide/boot/Shell-Linux-SemiAuto) - -#### 麦麦 - -先打开https://github.com/MaiM-with-u/MaiBot/releases -往下滑找到这个 -![下载指引](./pic/linux_beginner_downloadguide.png "") -下载箭头所指这个压缩包。 - -### 路径 - -我把麦麦相关文件放在了/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 指令集,而群晖似乎不支持这个指令集 -![](./pic/synology_docker-compose.png) - -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` -![](./pic/synology_.env.png) - -把 `bot_config.toml` 和 `.env` 放入之前创建的 `MaiMBot`文件夹 - -#### 如何下载? - -点这里!![](./pic/synology_how_to_download.png) - -### 创建项目 - -打开 `DSM ➡️ ContainerManager ➡️ 项目`,点击 `新增` 创建项目,填写以下内容: - -- 项目名称: `maimbot` -- 路径:之前创建的 `MaiMBot` 文件夹 -- 来源: `上传 docker-compose.yml` -- 文件:之前下载的 `docker-compose.yml` 文件 - -图例: - -![](./pic/synology_create_project.png) - -一路点下一步,等待项目创建完成 - -### 设置 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