refactor: 删除和项目无关的文件
244
CLAUDE.md
@@ -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] 部分
|
||||
650
MaiLauncher.bat
@@ -1,650 +0,0 @@
|
||||
@echo off
|
||||
@setlocal enabledelayedexpansion
|
||||
@chcp 936
|
||||
|
||||
@REM 设置版本号
|
||||
set "VERSION=1.0"
|
||||
|
||||
title 麦麦Bot控制台 v%VERSION%
|
||||
|
||||
@REM 设置Python和Git环境变量
|
||||
set "_root=%~dp0"
|
||||
set "_root=%_root:~0,-1%"
|
||||
cd "%_root%"
|
||||
|
||||
|
||||
:search_python
|
||||
cls
|
||||
if exist "%_root%\python" (
|
||||
set "PYTHON_HOME=%_root%\python"
|
||||
) else if exist "%_root%\venv" (
|
||||
call "%_root%\venv\Scripts\activate.bat"
|
||||
set "PYTHON_HOME=%_root%\venv\Scripts"
|
||||
) else (
|
||||
echo 正在自动查找Python解释器...
|
||||
|
||||
where python >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "delims=" %%i in ('where python') do (
|
||||
echo %%i | findstr /i /c:"!LocalAppData!\Microsoft\WindowsApps\python.exe" >nul
|
||||
if errorlevel 1 (
|
||||
echo 找到Python解释器:%%i
|
||||
set "py_path=%%i"
|
||||
goto :validate_python
|
||||
)
|
||||
)
|
||||
)
|
||||
set "search_paths=%ProgramFiles%\Git*;!LocalAppData!\Programs\Python\Python*"
|
||||
for /d %%d in (!search_paths!) do (
|
||||
if exist "%%d\python.exe" (
|
||||
set "py_path=%%d\python.exe"
|
||||
goto :validate_python
|
||||
)
|
||||
)
|
||||
echo 没有找到Python解释器,要安装吗?
|
||||
set /p pyinstall_confirm="继续?(Y/n): "
|
||||
if /i "!pyinstall_confirm!"=="Y" (
|
||||
cls
|
||||
echo 正在安装Python...
|
||||
winget install --id Python.Python.3.13 -e --accept-package-agreements --accept-source-agreements
|
||||
if %errorlevel% neq 0 (
|
||||
echo 安装失败,请手动安装Python
|
||||
start https://www.python.org/downloads/
|
||||
exit /b
|
||||
)
|
||||
echo 安装完成,正在验证Python...
|
||||
goto search_python
|
||||
|
||||
) else (
|
||||
echo 取消安装Python,按任意键退出...
|
||||
pause >nul
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo 错误:未找到可用的Python解释器!
|
||||
exit /b 1
|
||||
|
||||
:validate_python
|
||||
"!py_path!" --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo 无效的Python解释器:%py_path%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: 提取安装目录
|
||||
for %%i in ("%py_path%") do set "PYTHON_HOME=%%~dpi"
|
||||
set "PYTHON_HOME=%PYTHON_HOME:~0,-1%"
|
||||
)
|
||||
if not exist "%PYTHON_HOME%\python.exe" (
|
||||
echo Python路径验证失败:%PYTHON_HOME%
|
||||
echo 请检查Python安装路径中是否有python.exe文件
|
||||
exit /b 1
|
||||
)
|
||||
echo 成功设置Python路径:%PYTHON_HOME%
|
||||
|
||||
|
||||
|
||||
:search_git
|
||||
cls
|
||||
if exist "%_root%\tools\git\bin" (
|
||||
set "GIT_HOME=%_root%\tools\git\bin"
|
||||
) else (
|
||||
echo 正在自动查找Git...
|
||||
|
||||
where git >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "delims=" %%i in ('where git') do (
|
||||
set "git_path=%%i"
|
||||
goto :validate_git
|
||||
)
|
||||
)
|
||||
echo 正在扫描常见安装路径...
|
||||
set "search_paths=!ProgramFiles!\Git\cmd"
|
||||
for /f "tokens=*" %%d in ("!search_paths!") do (
|
||||
if exist "%%d\git.exe" (
|
||||
set "git_path=%%d\git.exe"
|
||||
goto :validate_git
|
||||
)
|
||||
)
|
||||
echo 没有找到Git,要安装吗?
|
||||
set /p confirm="继续?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
cls
|
||||
echo 正在安装Git...
|
||||
set "custom_url=https://ghfast.top/https://github.com/git-for-windows/git/releases/download/v2.48.1.windows.1/Git-2.48.1-64-bit.exe"
|
||||
|
||||
set "download_path=%TEMP%\Git-Installer.exe"
|
||||
|
||||
echo 正在下载Git安装包...
|
||||
curl -L -o "!download_path!" "!custom_url!"
|
||||
|
||||
if exist "!download_path!" (
|
||||
echo 下载成功,开始安装Git...
|
||||
start /wait "" "!download_path!" /SILENT /NORESTART
|
||||
) else (
|
||||
echo 下载失败,请手动安装Git
|
||||
start https://git-scm.com/download/win
|
||||
exit /b
|
||||
)
|
||||
|
||||
del "!download_path!"
|
||||
echo 临时文件已清理。
|
||||
|
||||
echo 安装完成,正在验证Git...
|
||||
where git >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "delims=" %%i in ('where git') do (
|
||||
set "git_path=%%i"
|
||||
goto :validate_git
|
||||
)
|
||||
goto :search_git
|
||||
|
||||
) else (
|
||||
echo 安装完成,但未找到Git,请手动安装Git
|
||||
start https://git-scm.com/download/win
|
||||
exit /b
|
||||
)
|
||||
|
||||
) else (
|
||||
echo 取消安装Git,按任意键退出...
|
||||
pause >nul
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo 错误:未找到可用的Git!
|
||||
exit /b 1
|
||||
|
||||
:validate_git
|
||||
"%git_path%" --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo 无效的Git:%git_path%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: 提取安装目录
|
||||
for %%i in ("%git_path%") do set "GIT_HOME=%%~dpi"
|
||||
set "GIT_HOME=%GIT_HOME:~0,-1%"
|
||||
)
|
||||
|
||||
:search_mongodb
|
||||
cls
|
||||
sc query | findstr /i "MongoDB" >nul
|
||||
if !errorlevel! neq 0 (
|
||||
echo MongoDB服务未运行,是否尝试运行服务?
|
||||
set /p confirm="是否启动?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo 正在尝试启动MongoDB服务...
|
||||
powershell -Command "Start-Process -Verb RunAs cmd -ArgumentList '/c net start MongoDB'"
|
||||
echo 正在等待MongoDB服务启动...
|
||||
echo 按下任意键跳过等待...
|
||||
timeout /t 30 >nul
|
||||
sc query | findstr /i "MongoDB" >nul
|
||||
if !errorlevel! neq 0 (
|
||||
echo MongoDB服务启动失败,可能是没有安装,要安装吗?
|
||||
set /p install_confirm="继续安装?(Y/N): "
|
||||
if /i "!install_confirm!"=="Y" (
|
||||
echo 正在安装MongoDB...
|
||||
winget install --id MongoDB.Server -e --accept-package-agreements --accept-source-agreements
|
||||
echo 安装完成,正在启动MongoDB服务...
|
||||
net start MongoDB
|
||||
if !errorlevel! neq 0 (
|
||||
echo 启动MongoDB服务失败,请手动启动
|
||||
exit /b
|
||||
) else (
|
||||
echo MongoDB服务已成功启动
|
||||
)
|
||||
) else (
|
||||
echo 取消安装MongoDB,按任意键退出...
|
||||
pause >nul
|
||||
exit /b
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo "警告:MongoDB服务未运行,将导致MaiMBot无法访问数据库!"
|
||||
)
|
||||
) else (
|
||||
echo MongoDB服务已运行
|
||||
)
|
||||
|
||||
@REM set "GIT_HOME=%_root%\tools\git\bin"
|
||||
set "PATH=%PYTHON_HOME%;%GIT_HOME%;%PATH%"
|
||||
|
||||
:install_maim
|
||||
if not exist "!_root!\bot.py" (
|
||||
cls
|
||||
echo 你似乎没有安装麦麦Bot,要安装在当前目录吗?
|
||||
set /p confirm="继续?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo 要使用Git代理下载吗?
|
||||
set /p proxy_confirm="继续?(Y/N): "
|
||||
if /i "!proxy_confirm!"=="Y" (
|
||||
echo 正在安装麦麦Bot...
|
||||
git clone https://ghfast.top/https://github.com/SengokuCola/MaiMBot
|
||||
) else (
|
||||
echo 正在安装麦麦Bot...
|
||||
git clone https://github.com/SengokuCola/MaiMBot
|
||||
)
|
||||
xcopy /E /H /I MaiMBot . >nul 2>&1
|
||||
rmdir /s /q MaiMBot
|
||||
git checkout main-fix
|
||||
|
||||
echo 安装完成,正在安装依赖...
|
||||
python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
python -m pip install virtualenv
|
||||
python -m virtualenv venv
|
||||
call venv\Scripts\activate.bat
|
||||
python -m pip install -r requirements.txt
|
||||
|
||||
echo 安装完成,要编辑配置文件吗?
|
||||
set /p edit_confirm="继续?(Y/N): "
|
||||
if /i "!edit_confirm!"=="Y" (
|
||||
goto config_menu
|
||||
) else (
|
||||
echo 取消编辑配置文件,按任意键返回主菜单...
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@REM git获取当前分支名并保存在变量里
|
||||
for /f "delims=" %%b in ('git symbolic-ref --short HEAD 2^>nul') do (
|
||||
set "BRANCH=%%b"
|
||||
)
|
||||
|
||||
@REM 根据不同分支名给分支名字符串使用不同颜色
|
||||
echo 分支名: %BRANCH%
|
||||
if "!BRANCH!"=="main" (
|
||||
set "BRANCH_COLOR=[92m"
|
||||
) else if "!BRANCH!"=="main-fix" (
|
||||
set "BRANCH_COLOR=[91m"
|
||||
@REM ) else if "%BRANCH%"=="stable-dev" (
|
||||
@REM set "BRANCH_COLOR=[96m"
|
||||
) else (
|
||||
set "BRANCH_COLOR=[93m"
|
||||
)
|
||||
|
||||
@REM endlocal & set "BRANCH_COLOR=%BRANCH_COLOR%"
|
||||
|
||||
:check_is_venv
|
||||
echo 正在检查虚拟环境状态...
|
||||
if exist "%_root%\config\no_venv" (
|
||||
echo 检测到no_venv,跳过虚拟环境检查
|
||||
goto menu
|
||||
)
|
||||
|
||||
:: 环境检测
|
||||
if defined VIRTUAL_ENV (
|
||||
goto menu
|
||||
)
|
||||
|
||||
if exist "%_root%\config\conda_env" (
|
||||
set /p CONDA_ENV=<"%_root%\config\conda_env"
|
||||
call conda activate !CONDA_ENV! || (
|
||||
echo 激活失败,可能原因:
|
||||
echo 1. 环境不存在
|
||||
echo 2. conda配置异常
|
||||
pause
|
||||
goto conda_menu
|
||||
)
|
||||
echo 成功激活conda环境:!CONDA_ENV!
|
||||
goto menu
|
||||
)
|
||||
|
||||
echo =====================================
|
||||
echo 虚拟环境检测警告:
|
||||
echo 当前使用系统Python路径:!PYTHON_HOME!
|
||||
echo 未检测到激活的虚拟环境!
|
||||
|
||||
:env_interaction
|
||||
echo =====================================
|
||||
echo 请选择操作:
|
||||
echo 1 - 创建并激活Venv虚拟环境
|
||||
echo 2 - 创建/激活Conda虚拟环境
|
||||
echo 3 - 临时跳过本次检查
|
||||
echo 4 - 永久跳过虚拟环境检查
|
||||
set /p choice="请输入选项(1-4): "
|
||||
|
||||
if "!choice!"=="4" (
|
||||
echo 要永久跳过虚拟环境检查吗?
|
||||
set /p no_venv_confirm="继续?(Y/N): ....."
|
||||
if /i "!no_venv_confirm!"=="Y" (
|
||||
echo 1 > "%_root%\config\no_venv"
|
||||
echo 已创建no_venv文件
|
||||
pause >nul
|
||||
goto menu
|
||||
) else (
|
||||
echo 取消跳过虚拟环境检查,按任意键返回...
|
||||
pause >nul
|
||||
goto env_interaction
|
||||
)
|
||||
)
|
||||
|
||||
if "!choice!"=="3" (
|
||||
echo 警告:使用系统环境可能导致依赖冲突!
|
||||
timeout /t 2 >nul
|
||||
goto menu
|
||||
)
|
||||
|
||||
if "!choice!"=="2" goto handle_conda
|
||||
if "!choice!"=="1" goto handle_venv
|
||||
|
||||
echo 无效的输入,请输入1-4之间的数字
|
||||
timeout /t 2 >nul
|
||||
goto env_interaction
|
||||
|
||||
:handle_venv
|
||||
python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
echo 正在初始化Venv环境...
|
||||
python -m pip install virtualenv || (
|
||||
echo 安装环境失败,错误码:!errorlevel!
|
||||
pause
|
||||
goto env_interaction
|
||||
)
|
||||
echo 创建虚拟环境到:venv
|
||||
python -m virtualenv venv || (
|
||||
echo 环境创建失败,错误码:!errorlevel!
|
||||
pause
|
||||
goto env_interaction
|
||||
)
|
||||
|
||||
call venv\Scripts\activate.bat
|
||||
echo 已激活Venv环境
|
||||
echo 要安装依赖吗?
|
||||
set /p install_confirm="继续?(Y/N): "
|
||||
if /i "!install_confirm!"=="Y" (
|
||||
goto update_dependencies
|
||||
)
|
||||
goto menu
|
||||
|
||||
:handle_conda
|
||||
where conda >nul 2>&1 || (
|
||||
echo 未检测到conda,可能原因:
|
||||
echo 1. 未安装Miniconda
|
||||
echo 2. conda配置异常
|
||||
timeout /t 10 >nul
|
||||
goto env_interaction
|
||||
)
|
||||
|
||||
:conda_menu
|
||||
echo 请选择Conda操作:
|
||||
echo 1 - 创建新环境
|
||||
echo 2 - 激活已有环境
|
||||
echo 3 - 返回上级菜单
|
||||
set /p choice="请输入选项(1-3): "
|
||||
|
||||
if "!choice!"=="3" goto env_interaction
|
||||
if "!choice!"=="2" goto activate_conda
|
||||
if "!choice!"=="1" goto create_conda
|
||||
|
||||
echo 无效的输入,请输入1-3之间的数字
|
||||
timeout /t 2 >nul
|
||||
goto conda_menu
|
||||
|
||||
:create_conda
|
||||
set /p "CONDA_ENV=请输入新环境名称:"
|
||||
if "!CONDA_ENV!"=="" (
|
||||
echo 环境名称不能为空!
|
||||
goto create_conda
|
||||
)
|
||||
conda create -n !CONDA_ENV! python=3.13 -y || (
|
||||
echo 环境创建失败,错误码:!errorlevel!
|
||||
timeout /t 10 >nul
|
||||
goto conda_menu
|
||||
)
|
||||
goto activate_conda
|
||||
|
||||
:activate_conda
|
||||
set /p "CONDA_ENV=请输入要激活的环境名称:"
|
||||
call conda activate !CONDA_ENV! || (
|
||||
echo 激活失败,可能原因:
|
||||
echo 1. 环境不存在
|
||||
echo 2. conda配置异常
|
||||
pause
|
||||
goto conda_menu
|
||||
)
|
||||
echo 成功激活conda环境:!CONDA_ENV!
|
||||
echo !CONDA_ENV! > "%_root%\config\conda_env"
|
||||
echo 要安装依赖吗?
|
||||
set /p install_confirm="继续?(Y/N): "
|
||||
if /i "!install_confirm!"=="Y" (
|
||||
goto update_dependencies
|
||||
)
|
||||
:menu
|
||||
@chcp 936
|
||||
cls
|
||||
echo 麦麦Bot控制台 v%VERSION% 当前分支: %BRANCH_COLOR%%BRANCH%[0m
|
||||
echo 当前Python环境: [96m!PYTHON_HOME![0m
|
||||
echo ======================
|
||||
echo 1. 更新并启动麦麦Bot (默认)
|
||||
echo 2. 直接启动麦麦Bot
|
||||
echo 3. 启动麦麦配置界面
|
||||
echo 4. 打开麦麦神奇工具箱
|
||||
echo 5. 退出
|
||||
echo ======================
|
||||
|
||||
set /p choice="请输入选项数字 (1-5)并按下回车以选择: "
|
||||
|
||||
if "!choice!"=="" set choice=1
|
||||
|
||||
if "!choice!"=="1" goto update_and_start
|
||||
if "!choice!"=="2" goto start_bot
|
||||
if "!choice!"=="3" goto config_menu
|
||||
if "!choice!"=="4" goto tools_menu
|
||||
if "!choice!"=="5" exit /b
|
||||
|
||||
echo 无效的输入,请输入1-5之间的数字
|
||||
timeout /t 2 >nul
|
||||
goto menu
|
||||
|
||||
:config_menu
|
||||
@chcp 936
|
||||
cls
|
||||
if not exist config/bot_config.toml (
|
||||
copy /Y "template\bot_config_template.toml" "config\bot_config.toml"
|
||||
|
||||
)
|
||||
if not exist .env.prod (
|
||||
copy /Y "template.env" ".env.prod"
|
||||
)
|
||||
|
||||
start python webui.py
|
||||
|
||||
goto menu
|
||||
|
||||
|
||||
:tools_menu
|
||||
@chcp 936
|
||||
cls
|
||||
echo 麦麦时尚工具箱 当前分支: %BRANCH_COLOR%%BRANCH%[0m
|
||||
echo ======================
|
||||
echo 1. 更新依赖
|
||||
echo 2. 切换分支
|
||||
echo 3. 重置当前分支
|
||||
echo 4. 更新配置文件
|
||||
echo 5. 学习新的知识库
|
||||
echo 6. 打开知识库文件夹
|
||||
echo 7. 返回主菜单
|
||||
echo ======================
|
||||
|
||||
set /p choice="请输入选项数字: "
|
||||
if "!choice!"=="1" goto update_dependencies
|
||||
if "!choice!"=="2" goto switch_branch
|
||||
if "!choice!"=="3" goto reset_branch
|
||||
if "!choice!"=="4" goto update_config
|
||||
if "!choice!"=="5" goto learn_new_knowledge
|
||||
if "!choice!"=="6" goto open_knowledge_folder
|
||||
if "!choice!"=="7" goto menu
|
||||
|
||||
echo 无效的输入,请输入1-6之间的数字
|
||||
timeout /t 2 >nul
|
||||
goto tools_menu
|
||||
|
||||
:update_dependencies
|
||||
cls
|
||||
echo 正在更新依赖...
|
||||
python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
python.exe -m pip install -r requirements.txt
|
||||
|
||||
echo 依赖更新完成,按任意键返回工具箱菜单...
|
||||
pause
|
||||
goto tools_menu
|
||||
|
||||
:switch_branch
|
||||
cls
|
||||
echo 正在切换分支...
|
||||
echo 当前分支: %BRANCH%
|
||||
@REM echo 可用分支: main, debug, stable-dev
|
||||
echo 1. 切换到[92mmain[0m
|
||||
echo 2. 切换到[91mmain-fix[0m
|
||||
echo 请输入要切换到的分支:
|
||||
set /p branch_name="分支名: "
|
||||
if "%branch_name%"=="" set branch_name=main
|
||||
if "%branch_name%"=="main" (
|
||||
set "BRANCH_COLOR=[92m"
|
||||
) else if "%branch_name%"=="main-fix" (
|
||||
set "BRANCH_COLOR=[91m"
|
||||
@REM ) else if "%branch_name%"=="stable-dev" (
|
||||
@REM set "BRANCH_COLOR=[96m"
|
||||
) else if "%branch_name%"=="1" (
|
||||
set "BRANCH_COLOR=[92m"
|
||||
set "branch_name=main"
|
||||
) else if "%branch_name%"=="2" (
|
||||
set "BRANCH_COLOR=[91m"
|
||||
set "branch_name=main-fix"
|
||||
) else (
|
||||
echo 无效的分支名, 请重新输入
|
||||
timeout /t 2 >nul
|
||||
goto switch_branch
|
||||
)
|
||||
|
||||
echo 正在切换到分支 %branch_name%...
|
||||
git checkout %branch_name%
|
||||
echo 分支切换完成,当前分支: %BRANCH_COLOR%%branch_name%[0m
|
||||
set "BRANCH=%branch_name%"
|
||||
echo 按任意键返回工具箱菜单...
|
||||
pause >nul
|
||||
goto tools_menu
|
||||
|
||||
|
||||
:reset_branch
|
||||
cls
|
||||
echo 正在重置当前分支...
|
||||
echo 当前分支: !BRANCH!
|
||||
echo 确认要重置当前分支吗?
|
||||
set /p confirm="继续?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo 正在重置当前分支...
|
||||
git reset --hard !BRANCH!
|
||||
echo 分支重置完成,按任意键返回工具箱菜单...
|
||||
) else (
|
||||
echo 取消重置当前分支,按任意键返回工具箱菜单...
|
||||
)
|
||||
pause >nul
|
||||
goto tools_menu
|
||||
|
||||
|
||||
:update_config
|
||||
cls
|
||||
echo 正在更新配置文件...
|
||||
echo 请确保已备份重要数据,继续将修改当前配置文件。
|
||||
echo 继续请按Y,取消请按任意键...
|
||||
set /p confirm="继续?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo 正在更新配置文件...
|
||||
python.exe config\auto_update.py
|
||||
echo 配置文件更新完成,按任意键返回工具箱菜单...
|
||||
) else (
|
||||
echo 取消更新配置文件,按任意键返回工具箱菜单...
|
||||
)
|
||||
pause >nul
|
||||
goto tools_menu
|
||||
|
||||
:learn_new_knowledge
|
||||
cls
|
||||
echo 正在学习新的知识库...
|
||||
echo 请确保已备份重要数据,继续将修改当前知识库。
|
||||
echo 继续请按Y,取消请按任意键...
|
||||
set /p confirm="继续?(Y/N): "
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo 正在学习新的知识库...
|
||||
python.exe src\plugins\zhishi\knowledge_library.py
|
||||
echo 学习完成,按任意键返回工具箱菜单...
|
||||
) else (
|
||||
echo 取消学习新的知识库,按任意键返回工具箱菜单...
|
||||
)
|
||||
pause >nul
|
||||
goto tools_menu
|
||||
|
||||
:open_knowledge_folder
|
||||
cls
|
||||
echo 正在打开知识库文件夹...
|
||||
if exist data\raw_info (
|
||||
start explorer data\raw_info
|
||||
) else (
|
||||
echo 知识库文件夹不存在!
|
||||
echo 正在创建文件夹...
|
||||
mkdir data\raw_info
|
||||
timeout /t 2 >nul
|
||||
)
|
||||
goto tools_menu
|
||||
|
||||
|
||||
:update_and_start
|
||||
cls
|
||||
:retry_git_pull
|
||||
git pull > temp.log 2>&1
|
||||
findstr /C:"detected dubious ownership" temp.log >nul
|
||||
if %errorlevel% equ 0 (
|
||||
echo 检测到仓库权限问题,正在自动修复...
|
||||
git config --global --add safe.directory "%cd%"
|
||||
echo 已添加例外,正在重试git pull...
|
||||
del temp.log
|
||||
goto retry_git_pull
|
||||
)
|
||||
del temp.log
|
||||
echo 正在更新依赖...
|
||||
python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
python -m pip install -r requirements.txt && cls
|
||||
|
||||
echo 当前代理设置:
|
||||
echo HTTP_PROXY=%HTTP_PROXY%
|
||||
echo HTTPS_PROXY=%HTTPS_PROXY%
|
||||
|
||||
echo Disable Proxy...
|
||||
set HTTP_PROXY=
|
||||
set HTTPS_PROXY=
|
||||
set no_proxy=0.0.0.0/32
|
||||
|
||||
REM chcp 65001
|
||||
python bot.py
|
||||
echo.
|
||||
echo Bot已停止运行,按任意键返回主菜单...
|
||||
pause >nul
|
||||
goto menu
|
||||
|
||||
:start_bot
|
||||
cls
|
||||
echo 正在更新依赖...
|
||||
python -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
python -m pip install -r requirements.txt && cls
|
||||
|
||||
echo 当前代理设置:
|
||||
echo HTTP_PROXY=%HTTP_PROXY%
|
||||
echo HTTPS_PROXY=%HTTPS_PROXY%
|
||||
|
||||
echo Disable Proxy...
|
||||
set HTTP_PROXY=
|
||||
set HTTPS_PROXY=
|
||||
set no_proxy=0.0.0.0/32
|
||||
|
||||
REM chcp 65001
|
||||
python bot.py
|
||||
echo.
|
||||
echo Bot已停止运行,按任意键返回主菜单...
|
||||
pause >nul
|
||||
goto menu
|
||||
|
||||
|
||||
:open_dir
|
||||
start explorer "%cd%"
|
||||
goto menu
|
||||
@@ -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()
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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 还强调时空关联性联想。如果两个事物在时间或空间上经常同时出现,它们也会在记忆中形成关联。比如,每次在公园里看到花的时候,都能听到鸟儿的叫声,那么花和鸟儿叫声的形态特征(花的视觉形态和鸟叫的听觉形态)就会在记忆中形成关联,以后听到鸟叫可能就会联想到公园里的花。
|
||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 36 KiB |
@@ -1 +0,0 @@
|
||||
gource gource.log --user-image-dir docs/avatars/ --default-user-image docs/avatars/default.png
|
||||
175
docs/doc1.md
@@ -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部署支持**:
|
||||
- 提供容器化部署方案,简化安装和运行。
|
||||
@@ -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密钥请妥善保管,不要泄露
|
||||
- 建议先在测试环境中运行,确认无误后再部署到生产环境
|
||||
289
docs/fast_q_a.md
@@ -1,289 +0,0 @@
|
||||
## 快速更新Q&A❓
|
||||
|
||||
- 这个文件用来记录一些常见的新手问题。
|
||||
|
||||
### 完整安装教程
|
||||
|
||||
[MaiMbot简易配置教程](https://www.bilibili.com/video/BV1zsQ5YCEE6)
|
||||
|
||||
### Api相关问题
|
||||
|
||||
- 为什么显示:"缺失必要的API KEY" ❓
|
||||
|
||||
<img src="./pic/API_KEY.png" width=650>
|
||||
|
||||
>你需要在 [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`中自行选择:
|
||||
><img src="./pic/compass_downloadguide.png" width=400>
|
||||
|
||||
>打开你的MongoDB Compass软件,你会在左上角看到这样的一个界面:
|
||||
>
|
||||
><img src="./pic/MONGO_DB_0.png" width=250>
|
||||
>
|
||||
><br>
|
||||
>
|
||||
>点击 "CONNECT" 之后,点击展开 MegBot 标签栏
|
||||
>
|
||||
><img src="./pic/MONGO_DB_1.png" width=250>
|
||||
>
|
||||
><br>
|
||||
>
|
||||
>点进 "emoji" 再点击 "DELETE" 删掉所有条目,如图所示
|
||||
>
|
||||
><img src="./pic/MONGO_DB_2.png" width=450>
|
||||
>
|
||||
><br>
|
||||
>
|
||||
>你可以用类似的方式手动清空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 本体**
|
||||
>
|
||||
><br>
|
||||
>
|
||||
> 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
|
||||
>```
|
||||
|
||||
<details>
|
||||
<summary>Linux(点击展开)</summary>
|
||||
|
||||
#### **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
|
||||
```
|
||||
|
||||
|
||||
##### **注意事项**
|
||||
- 终止进程前,务必确认该进程非系统关键服务(如未知进程占用,建议先排查来源),如果你不知道这个进程是否关键,请更改端口使用。
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>macOS(点击展开)</summary>
|
||||
|
||||
### **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
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -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服务的密钥,不然机器人就不能和你说话了呢
|
||||
- 修改完配置后要重启机器人才能生效喵~
|
||||
@@ -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. 其他说明:
|
||||
- 项目处于测试阶段,可能存在未知问题
|
||||
- 建议初次使用保持默认配置
|
||||
@@ -1,331 +0,0 @@
|
||||
# 面向纯新手的Linux服务器麦麦部署指南
|
||||
|
||||
|
||||
## 事前准备
|
||||
为了能使麦麦不间断的运行,你需要一台一直开着的服务器。
|
||||
|
||||
### 如果你想购买服务器
|
||||
华为云、阿里云、腾讯云等等都是在国内可以选择的选择。
|
||||
|
||||
租一台最低配置的就足敷需要了,按月租大概十几块钱就能租到了。
|
||||
|
||||
### 如果你不想购买服务器
|
||||
你可以准备一台可以一直开着的电脑/主机,只需要保证能够正常访问互联网即可
|
||||
|
||||
**下文将统称它们为`服务器`**
|
||||
|
||||
我们假设你已经有了一台Linux架构的服务器。举例使用的是Ubuntu24.04,其他的原理相似。
|
||||
|
||||
## 0.我们就从零开始吧
|
||||
|
||||
### 网络问题
|
||||
|
||||
为访问Github相关界面,推荐去下一款加速器,新手可以试试[Watt Toolkit](https://gitee.com/rmbgame/SteamTools/releases/latest)。
|
||||
|
||||
### 安装包下载
|
||||
|
||||
#### MongoDB
|
||||
进入[MongoDB下载页](https://www.mongodb.com/try/download/community-kubernetes-operator),并选择版本
|
||||
|
||||
以Ubuntu24.04 x86为例,保持如图所示选项,点击`Download`即可,如果是其他系统,请在`Platform`中自行选择:
|
||||
|
||||

|
||||
|
||||
|
||||
不想使用上述方式?你也可以参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/administration/install-on-linux/#std-label-install-mdb-community-edition-linux)进行安装,进入后选择自己的系统版本即可
|
||||
|
||||
#### QQ(可选)/Napcat
|
||||
*如果你使用Napcat的脚本安装,可以忽略此步*
|
||||
访问https://github.com/NapNeko/NapCatQQ/releases/latest
|
||||
在图中所示区域可以找到QQ的下载链接,选择对应版本下载即可
|
||||
从这里下载,可以保证你下载到的QQ版本兼容最新版Napcat
|
||||

|
||||
如果你不想使用Napcat的脚本安装,还需参考[Napcat-Linux手动安装](https://www.napcat.wiki/guide/boot/Shell-Linux-SemiAuto)
|
||||
|
||||
#### 麦麦
|
||||
|
||||
先打开https://github.com/MaiM-with-u/MaiBot/releases
|
||||
往下滑找到这个
|
||||

|
||||
下载箭头所指这个压缩包。
|
||||
|
||||
### 路径
|
||||
|
||||
我把麦麦相关文件放在了/moi/mai里面,你可以凭喜好更改,记得适当调整下面涉及到的部分即可。
|
||||
|
||||
文件结构:
|
||||
|
||||
```
|
||||
moi
|
||||
└─ mai
|
||||
├─ linuxqq_3.2.16-32793_amd64.deb # linuxqq安装包
|
||||
├─ mongodb-org-server_8.0.5_amd64.deb # MongoDB的安装包
|
||||
└─ bot
|
||||
└─ MaiMBot-0.5.8-alpha.zip # 麦麦的压缩包
|
||||
```
|
||||
|
||||
### 网络
|
||||
|
||||
你可以在你的服务器控制台网页更改防火墙规则,允许6099,8080,27017这几个端口的出入。
|
||||
|
||||
## 1.正式开始!
|
||||
|
||||
远程连接你的服务器,你会看到一个黑框框闪着白方格,这就是我们要进行设置的场所——终端了。以下的bash命令都是在这里输入。
|
||||
|
||||
## 2. Python的安装
|
||||
|
||||
- 导入 Python 的稳定版 PPA(Ubuntu需执行此步,Debian可忽略):
|
||||
|
||||
```bash
|
||||
sudo add-apt-repository ppa:deadsnakes/ppa
|
||||
```
|
||||
|
||||
- 导入 PPA 后,更新 APT 缓存:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
- 在「终端」中执行以下命令来安装 Python 3.12:
|
||||
|
||||
```bash
|
||||
sudo apt install python3.12
|
||||
```
|
||||
|
||||
- 验证安装是否成功:
|
||||
|
||||
```bash
|
||||
python3.12 --version
|
||||
```
|
||||
- (可选)更新替代方案,设置 python3.12 为默认的 python3 版本:
|
||||
```bash
|
||||
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1
|
||||
sudo update-alternatives --config python3
|
||||
```
|
||||
|
||||
- 在「终端」中,执行以下命令安装 pip:
|
||||
|
||||
```bash
|
||||
sudo apt install python3-pip
|
||||
```
|
||||
|
||||
- 检查Pip是否安装成功:
|
||||
|
||||
```bash
|
||||
pip --version
|
||||
```
|
||||
|
||||
- 安装必要组件
|
||||
|
||||
``` bash
|
||||
sudo apt install python-is-python3
|
||||
```
|
||||
|
||||
## 3.MongoDB的安装
|
||||
*如果你是参考[官方文档](https://www.mongodb.com/zh-cn/docs/manual/administration/install-on-linux/#std-label-install-mdb-community-edition-linux)进行安装的,可跳过此步*
|
||||
|
||||
``` bash
|
||||
cd /moi/mai
|
||||
```
|
||||
|
||||
``` bash
|
||||
dpkg -i mongodb-org-server_8.0.5_amd64.deb
|
||||
```
|
||||
|
||||
``` bash
|
||||
mkdir -p /root/data/mongodb/{data,log}
|
||||
```
|
||||
|
||||
## 4.MongoDB的运行
|
||||
|
||||
```bash
|
||||
service mongod start
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl status mongod #通过这条指令检查运行状态
|
||||
```
|
||||
|
||||
有需要的话可以把这个服务注册成开机自启
|
||||
|
||||
```bash
|
||||
sudo systemctl enable mongod
|
||||
```
|
||||
|
||||
## 5.Napcat的安装
|
||||
|
||||
``` bash
|
||||
# 该脚本适用于支持Ubuntu 20+/Debian 10+/Centos9
|
||||
curl -o napcat.sh https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh && sudo bash napcat.sh
|
||||
```
|
||||
执行后,脚本会自动帮你部署好QQ及Napcat
|
||||
*注:如果你已经手动安装了Napcat和QQ,可忽略此步*
|
||||
|
||||
成功的标志是输入``` napcat ```出来炫酷的彩虹色界面
|
||||
|
||||
## 6.Napcat的运行
|
||||
|
||||
此时你就可以根据提示在```napcat```里面登录你的QQ号了。
|
||||
|
||||
```bash
|
||||
napcat start <你的QQ号>
|
||||
napcat status #检查运行状态
|
||||
```
|
||||
|
||||
然后你就可以登录napcat的webui进行设置了:
|
||||
|
||||
```http://<你服务器的公网IP>:6099/webui?token=napcat```
|
||||
|
||||
如果你部署在自己的电脑上:
|
||||
```http://127.0.0.1:6099/webui?token=napcat```
|
||||
|
||||
> [!WARNING]
|
||||
> 如果你的麦麦部署在公网,请**务必**修改Napcat的默认密码
|
||||
|
||||
|
||||
第一次是这个,后续改了密码之后token就会对应修改。你也可以使用```napcat log <你的QQ号>```来查看webui地址。把里面的```127.0.0.1```改成<你服务器的公网IP>即可。
|
||||
|
||||
登录上之后在网络配置界面添加websocket客户端,名称随便输一个,url改成`ws://127.0.0.1:8080/onebot/v11/ws`保存之后点启用,就大功告成了。
|
||||
|
||||
## 7.麦麦的安装
|
||||
|
||||
### step 1 安装解压软件
|
||||
|
||||
```bash
|
||||
sudo apt-get install unzip
|
||||
```
|
||||
|
||||
### step 2 解压文件
|
||||
|
||||
```bash
|
||||
cd /moi/mai/bot # 注意:要切换到压缩包的目录中去
|
||||
unzip MaiMBot-0.5.8-alpha.zip
|
||||
```
|
||||
|
||||
### step 3 进入虚拟环境安装库
|
||||
|
||||
```bash
|
||||
cd /moi/mai/bot
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### step 4 试运行
|
||||
|
||||
```bash
|
||||
cd /moi/mai/bot
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
python bot.py
|
||||
```
|
||||
|
||||
肯定运行不成功,不过你会发现结束之后多了一些文件
|
||||
|
||||
```
|
||||
bot
|
||||
├─ .env
|
||||
└─ config
|
||||
└─ bot_config.toml
|
||||
```
|
||||
|
||||
你可以使用vim、nano等编辑器直接在终端里修改这些配置文件,但如果你不熟悉它们的操作,也可以使用带图形界面的编辑器。
|
||||
如果你的麦麦部署在远程服务器,也可以把它们下载到本地改好再传上去
|
||||
|
||||
### step 5 文件配置
|
||||
|
||||
本项目需要配置两个主要文件:
|
||||
|
||||
1. `.env` - 配置API服务和系统环境
|
||||
2. `bot_config.toml` - 配置机器人行为和模型
|
||||
|
||||
#### API
|
||||
|
||||
你可以注册一个硅基流动的账号,通过邀请码注册有14块钱的免费额度:https://cloud.siliconflow.cn/i/7Yld7cfg。
|
||||
|
||||
#### 修改配置文件
|
||||
请参考
|
||||
- [🎀 新手配置指南](./installation_cute.md) - 通俗易懂的配置教程,适合初次使用的猫娘
|
||||
- [⚙️ 标准配置指南](./installation_standard.md) - 简明专业的配置说明,适合有经验的用户
|
||||
|
||||
|
||||
### step 6 运行
|
||||
|
||||
现在再运行
|
||||
|
||||
```bash
|
||||
cd /moi/mai/bot
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
python bot.py
|
||||
```
|
||||
|
||||
应该就能运行成功了。
|
||||
|
||||
## 8.事后配置
|
||||
|
||||
可是现在还有个问题:只要你一关闭终端,bot.py就会停止运行。那该怎么办呢?我们可以把bot.py注册成服务。
|
||||
|
||||
重启服务器,打开MongoDB和napcat服务。
|
||||
|
||||
新建一个文件,名为`bot.service`,内容如下
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=maimai bot
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/moi/mai/bot
|
||||
ExecStart=/moi/mai/bot/venv/bin/python /moi/mai/bot/bot.py
|
||||
Restart=on-failure
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
里面的路径视自己的情况更改。
|
||||
|
||||
把它放到`/etc/systemd/system`里面。
|
||||
|
||||
重新加载 `systemd` 配置:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
启动服务:
|
||||
|
||||
```bash
|
||||
sudo systemctl start bot.service # 启动服务
|
||||
sudo systemctl restart bot.service # 或者重启服务
|
||||
```
|
||||
|
||||
检查服务状态:
|
||||
|
||||
```bash
|
||||
sudo systemctl status bot.service
|
||||
```
|
||||
|
||||
现在再关闭终端,检查麦麦能不能正常回复QQ信息。如果可以的话就大功告成了!
|
||||
|
||||
## 9.命令速查
|
||||
|
||||
```bash
|
||||
service mongod start # 启动mongod服务
|
||||
napcat start <你的QQ号> # 登录napcat
|
||||
cd /moi/mai/bot # 切换路径
|
||||
python -m venv venv # 创建虚拟环境
|
||||
source venv/bin/activate # 激活虚拟环境
|
||||
|
||||
sudo systemctl daemon-reload # 重新加载systemd配置
|
||||
sudo systemctl start bot.service # 启动bot服务
|
||||
sudo systemctl enable bot.service # 启动bot服务
|
||||
|
||||
sudo systemctl status bot.service # 检查bot服务状态
|
||||
```
|
||||
|
||||
```bash
|
||||
python bot.py # 运行麦麦
|
||||
```
|
||||
|
||||
@@ -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_directory>`:你的maimbot目录
|
||||
|
||||
`<venv_directory>`:你的venv环境(就是上文创建环境后,执行的代码`source maimbot/bin/activate`中source后面的路径的绝对路径)
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=MaiMbot 麦麦
|
||||
After=network.target mongod.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=<maimbot_directory>
|
||||
ExecStart=<venv_directory>/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
|
||||
```
|
||||
@@ -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
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.maimbot</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/path/to/maimbot-venv/bin/python</string>
|
||||
<string>/path/to/MaiMbot/bot.py</string>
|
||||
</array>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/path/to/MaiMbot</string>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/maimbot.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/maimbot.err</string>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
加载服务:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
---
|
||||
@@ -1,110 +0,0 @@
|
||||
# 📦 Windows系统如何手动部署MaiMbot麦麦?
|
||||
|
||||
## 你需要什么?
|
||||
|
||||
- 一台电脑,能够上网的那种
|
||||
|
||||
- 一个QQ小号(QQ框架的使用可能导致qq被风控,严重(小概率)可能会导致账号封禁,强烈不推荐使用大号)
|
||||
|
||||
- 可用的大模型API
|
||||
|
||||
- 一个AI助手,网上随便搜一家打开来用都行,可以帮你解决一些不懂的问题
|
||||
|
||||
## 你需要知道什么?
|
||||
|
||||
- 如何正确向AI助手提问,来学习新知识
|
||||
|
||||
- Python是什么
|
||||
|
||||
- Python的虚拟环境是什么?如何创建虚拟环境
|
||||
|
||||
- 命令行是什么
|
||||
|
||||
- 数据库是什么?如何安装并启动MongoDB
|
||||
|
||||
- 如何运行一个QQ机器人,以及NapCat框架是什么
|
||||
|
||||
## 如果准备好了,就可以开始部署了
|
||||
|
||||
### 1️⃣ **首先,我们需要安装正确版本的Python**
|
||||
|
||||
在创建虚拟环境之前,请确保你的电脑上安装了Python 3.9及以上版本。如果没有,可以按以下步骤安装:
|
||||
|
||||
1. 访问Python官网下载页面:<https://www.python.org/downloads/release/python-3913/>
|
||||
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生成知识库
|
||||
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 27 KiB |
@@ -1,68 +0,0 @@
|
||||
# 群晖 NAS 部署指南
|
||||
|
||||
**笔者使用的是 DSM 7.2.2,其他 DSM 版本的操作可能不完全一样**
|
||||
**需要使用 Container Manager,群晖的部分部分入门级 NAS 可能不支持**
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 创建配置文件目录
|
||||
|
||||
打开 `DSM ➡️ 控制面板 ➡️ 共享文件夹`,点击 `新增` ,创建一个共享文件夹
|
||||
只需要设置名称,其他设置均保持默认即可。如果你已经有 docker 专用的共享文件夹了,就跳过这一步
|
||||
|
||||
打开 `DSM ➡️ FileStation`, 在共享文件夹中创建一个 `MaiMBot` 文件夹
|
||||
|
||||
### 准备配置文件
|
||||
|
||||
docker-compose.yml: https://github.com/SengokuCola/MaiMBot/blob/main/docker-compose.yml
|
||||
下载后打开,将 `services-mongodb-image` 修改为 `mongo:4.4.24`。这是因为最新的 MongoDB 强制要求 AVX 指令集,而群晖似乎不支持这个指令集
|
||||

|
||||
|
||||
bot_config.toml: https://github.com/SengokuCola/MaiMBot/blob/main/template/bot_config_template.toml
|
||||
下载后,重命名为 `bot_config.toml`
|
||||
打开它,按自己的需求填写配置文件
|
||||
|
||||
.env: https://github.com/SengokuCola/MaiMBot/blob/main/template.env
|
||||
下载后,重命名为 `.env`
|
||||
将 `HOST` 修改为 `0.0.0.0`,确保 maimbot 能被 napcat 访问
|
||||
按下图修改 mongodb 设置,使用 `MONGODB_URI`
|
||||

|
||||
|
||||
把 `bot_config.toml` 和 `.env` 放入之前创建的 `MaiMBot`文件夹
|
||||
|
||||
#### 如何下载?
|
||||
|
||||
点这里!
|
||||
|
||||
### 创建项目
|
||||
|
||||
打开 `DSM ➡️ ContainerManager ➡️ 项目`,点击 `新增` 创建项目,填写以下内容:
|
||||
|
||||
- 项目名称: `maimbot`
|
||||
- 路径:之前创建的 `MaiMBot` 文件夹
|
||||
- 来源: `上传 docker-compose.yml`
|
||||
- 文件:之前下载的 `docker-compose.yml` 文件
|
||||
|
||||
图例:
|
||||
|
||||

|
||||
|
||||
一路点下一步,等待项目创建完成
|
||||
|
||||
### 设置 Napcat
|
||||
|
||||
1. 登陆 napcat
|
||||
打开 napcat: `http://<你的nas地址>:6099` ,输入token登陆
|
||||
token可以打开 `DSM ➡️ ContainerManager ➡️ 项目 ➡️ MaiMBot ➡️ 容器 ➡️ Napcat ➡️ 日志`,找到类似 `[WebUi] WebUi Local Panel Url: http://127.0.0.1:6099/webui?token=xxxx` 的日志
|
||||
这个 `token=` 后面的就是你的 napcat token
|
||||
|
||||
2. 按提示,登陆你给麦麦准备的QQ小号
|
||||
|
||||
3. 设置 websocket 客户端
|
||||
`网络配置 -> 新建 -> Websocket客户端`,名称自定,URL栏填入 `ws://maimbot:8080/onebot/v11/ws`,启用并保存即可。
|
||||
若修改过容器名称,则替换 `maimbot` 为你自定的名称
|
||||
|
||||
### 部署完成
|
||||
|
||||
找个群,发送 `麦麦,你在吗` 之类的
|
||||
如果一切正常,应该能正常回复了
|
||||
@@ -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"<span style='color: red;'>获取embeddings失败!{embedding}</span>",
|
||||
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"<span style='color: red;'>出现异常: {e}</span>",
|
||||
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,
|
||||
)
|
||||
BIN
requirements.txt
@@ -1,4 +0,0 @@
|
||||
CHCP 65001
|
||||
@echo off
|
||||
python webui.py
|
||||
pause
|
||||
10
run.bat
@@ -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
|
||||
137
run.py
@@ -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")
|
||||
571
run.sh
@@ -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 <<EOF
|
||||
[mongodb-org-8.0]
|
||||
name=MongoDB Repository
|
||||
baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/x86_64/
|
||||
gpgcheck=1
|
||||
enabled=1
|
||||
gpgkey=https://pgp.mongodb.com/server-8.0.asc
|
||||
EOF
|
||||
yum install -y mongodb-org
|
||||
systemctl enable --now mongod
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
if [[ $IS_INSTALL_NAPCAT == true ]]; then
|
||||
echo -e "${GREEN}安装 NapCat...${RESET}"
|
||||
curl -o napcat.sh https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh && bash napcat.sh --cli y --docker n
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}创建安装目录...${RESET}"
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
cd "$INSTALL_DIR" || exit 1
|
||||
|
||||
echo -e "${GREEN}设置Python虚拟环境...${RESET}"
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
echo -e "${GREEN}克隆仓库...${RESET}"
|
||||
git clone -b "$BRANCH" "$GITHUB_REPO" repo || {
|
||||
echo -e "${RED}克隆仓库失败!${RESET}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "${GREEN}安装Python依赖...${RESET}"
|
||||
pip install -r repo/requirements.txt
|
||||
|
||||
echo -e "${GREEN}同意协议...${RESET}"
|
||||
|
||||
# 首先计算当前EULA的MD5值
|
||||
current_md5=$(md5sum "repo/EULA.md" | awk '{print $1}')
|
||||
|
||||
# 首先计算当前隐私条款文件的哈希值
|
||||
current_md5_privacy=$(md5sum "repo/PRIVACY.md" | awk '{print $1}')
|
||||
|
||||
echo -n $current_md5 > repo/eula.confirmed
|
||||
echo -n $current_md5_privacy > repo/privacy.confirmed
|
||||
|
||||
echo -e "${GREEN}创建系统服务...${RESET}"
|
||||
cat > /etc/systemd/system/${SERVICE_NAME}.service <<EOF
|
||||
[Unit]
|
||||
Description=麦麦Bot 主进程
|
||||
After=network.target mongod.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${INSTALL_DIR}/repo
|
||||
ExecStart=$INSTALL_DIR/venv/bin/python3 bot.py
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat > /etc/systemd/system/${SERVICE_NAME_WEB}.service <<EOF
|
||||
[Unit]
|
||||
Description=麦麦Bot WebUI
|
||||
After=network.target mongod.service ${SERVICE_NAME}.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${INSTALL_DIR}/repo
|
||||
ExecStart=$INSTALL_DIR/venv/bin/python3 webui.py
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable ${SERVICE_NAME}
|
||||
|
||||
# 保存安装信息
|
||||
echo "INSTALLER_VERSION=${INSTALLER_VERSION}" > /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
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
mongod --dbpath="mongodb" --port 27017
|
||||
@@ -1,7 +0,0 @@
|
||||
chcp 65001
|
||||
call conda activate maimbot
|
||||
cd .
|
||||
|
||||
REM 执行nb run命令
|
||||
nb run
|
||||
pause
|
||||
@@ -1,5 +0,0 @@
|
||||
@REM call conda activate niuniu
|
||||
cd ../src\gui
|
||||
start /b ../../venv/scripts/python.exe reasoning_gui.py
|
||||
exit
|
||||
|
||||
@@ -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
|
||||
11
setup.py
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
633
配置文件错误排查.py
@@ -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按任意键退出...")
|
||||
56
麦麦开始学习.bat
@@ -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
|
||||