Commit Graph

897 Commits

Author SHA1 Message Date
Windpicker-owo
43483b934e feat: 更新机器人配置并添加数据库迁移脚本
- 将bot_config_template.toml中的版本升级至7.9.0
- 增强数据库配置选项以支持PostgreSQL
- 引入一个新脚本,用于在SQLite、MySQL和PostgreSQL之间迁移数据
- 实现一个方言适配器,用于处理特定于数据库的行为和配置
2025-11-27 18:45:01 +08:00
拾风
94b889f34e Merge branch 'dev' into mofox-bus 2025-11-26 22:52:06 +08:00
copilot-swe-agent[bot]
1ca3aa6a07 fix: 修复代码质量和隐形问题 - 移除未使用导入、修复asyncio任务引用、修复类型注解
Co-authored-by: Windpicker-owo <221029311+Windpicker-owo@users.noreply.github.com>
2025-11-26 14:43:44 +00:00
Windpicker-owo
9f82671972 Merge branch 'dev' into mofox-bus 2025-11-26 22:25:39 +08:00
Windpicker-owo
0dc41bc839 refactor(emoji_manager): 使用异步任务处理表情描述生成,优化错误处理逻辑
refactor(graph_store): 移除冗余日志信息,简化内存边同步逻辑
refactor(affinity_chatter): 将信息日志级别更改为调试级别
2025-11-26 21:38:46 +08:00
Windpicker-owo
0908fb50a0 优化日志 2025-11-26 21:16:16 +08:00
Windpicker-owo
e0157256b1 feat(napcat_adapter): 添加请求处理程序、发送处理程序、视频处理程序以及实用函数
- 实现了request_handler.py来处理对核心的请求。
- 创建了send_handler.py文件,用于处理并向Napcat发送消息。
- 添加了video_handler.py文件,用于从QQ消息中下载和处理视频文件。
- 开发了utils.py,用于缓存和实现与Napcat操作相关的实用函数。
- 为群组、成员和自身信息引入了带有生存时间(TTL)设置的缓存机制。
- 新模块中增强了错误处理和日志记录功能。
2025-11-26 20:09:41 +08:00
Windpicker-owo
46a98fefc4 重构:更新聊天流中打断计数的重置逻辑,简化元事件处理器的实现 2025-11-26 17:58:31 +08:00
Windpicker-owo
d28ba27f26 重构:统一平台字段命名,更新相关数据模型和消息处理逻辑 2025-11-26 17:34:25 +08:00
Windpicker-owo
8fc4cd4c3b 重构:移除过时的napcat_adapter_plugin组件
- 从napcat_adapter_plugin中删除了stream_router.py、utils.py、video_handler.py、websocket_manager.py和todo.md文件。
- 在napcat_cache.json中为组和成员信息引入了一种新的缓存结构。
- 通过移除未使用的模块和整合功能,简化了插件的架构。
2025-11-26 16:40:31 +08:00
Windpicker-owo
8a6b141017 重构代码以使用 mofox_wire 替代 mofox_bus,更新相关文档和示例 2025-11-25 22:45:57 +08:00
tt-P607
fd65d8c4eb feat(person_info): 实施基于稳健 ID 的用户信息同步。本次提交重构了用户识别和信息检索系统,使其基于稳定的平台和用户 ID,不再依赖脆弱的姓名解析机制。同时引入了自动后台进程,以保持用户信息的实时更新。主要变更包括:
- 在 `PersonInfoManager` 中新增 `sync_user_info` 方法,根据 `platform` 和 `user_id` 来创建和更新用户记录。
- `ChatManager` 现在会在处理消息时触发该同步作为非阻塞后台任务,确保用户数据(如昵称)保持最新。
- 提示生成逻辑,特别是关系和上下文信息的生成,已重构为使用稳定的 `user_id`,而非从回复消息内容中解析姓名。
- `PromptParameters` 已被扩展,以在整个回复生成流程中传递 `platform` 和 `user_id`。
- 弃用依赖名称到 ID 查找的脆弱方法。
2025-11-25 22:01:41 +08:00
Windpicker-owo
b6de9b5a9c 重构聊天系统中的消息发送与处理
- 更新了`uni_message_sender.py`,使用`MessageEnvelope`来发送消息,取代了之前的`MessageSending`结构。
- 引入了`send_envelope`函数,通过改进日志记录和错误处理来简化消息发送流程。
- 修改了`HeartFCSender`以直接处理`MessageEnvelope`,确保与新消息结构的兼容性。
- 重构了`default_generator.py`,以构建`MessageEnvelope`而不是`MessageSending`,从而增强了消息构建逻辑。
- 调整了`utils.py`中的效用函数,以使用`DatabaseUserInfo`来处理用户信息。
- 更新了`send_api.py`以构建和发送`MessageEnvelope`,从而改进了消息分发逻辑。
- 从插件系统中移除了已弃用的`MaiMessages`类,清理了未使用的代码。
- 增强了`napcat_adapter_plugin`以适应新的消息结构,确保消息的正确处理和发送。
- 对代码进行整体清理和整理,以提高可维护性和可读性。
2025-11-25 21:54:27 +08:00
Windpicker-owo
c268ea2fb2 修复ChatStream循环导入问题 2025-11-25 20:29:48 +08:00
Windpicker-owo
6b3b2a8245 重构并增强Napcat适配器的功能
- 更新了`BaseAdapter`以简化子进程处理。
- 对`AdapterManager`进行了重构,以便根据适配器的`run_in_subprocess`属性来管理适配器。
- 增强了`NapcatAdapter`,以利用新的`CoreSinkManager`实现更优的进程管理。
- 在`utils.py`中实现了针对群组和成员信息的缓存机制。
- 改进了`message_handler.py`中的消息处理,以支持各种消息类型和格式。
- 已将插件配置版本更新至7.8.3。
2025-11-25 19:55:36 +08:00
Windpicker-owo
1ebdc37b22 重构ChatStream和StreamContext:移除context_manager引用
- 在ChatStream及相关类中,将所有context_manager的实例替换为直接上下文访问。
- 更新方法,利用新的上下文结构来管理聊天状态和消息。
- 增强的StreamContext,增加了用于消息处理、统计和历史管理的方法。
- 在重构过程中改进了错误处理和日志记录。
2025-11-25 12:01:26 +08:00
Windpicker-owo
d30b0544b5 重构消息处理和信封转换
- 从代码库中移除了EnvelopeConverter类及其相关方法,因为它们已不再需要。
- 更新了主系统,使其能够直接处理MessageEnvelope对象,而无需将其转换为旧格式。
- 增强了MessageRuntime类,以支持多种消息类型并防止重复注册处理程序。
引入了一个新的MessageHandler类来管理消息处理,包括预处理和数据库存储。
- 改进了整个消息处理工作流程中的错误处理和日志记录。
- 更新了类型提示和数据模型,以确保消息结构的一致性和清晰度。
2025-11-24 22:36:33 +08:00
minecraft1024a
94b4123039 refactor(plugin_system): 废弃旧版Command系统并重构注册中心
本次提交完全移除了对旧版 `BaseCommand` 系统的支持,统一使用 `PlusCommand`。所有旧版命令现在通过一个兼容性适配器在加载时自动转换为 `PlusCommand`,简化了命令处理流程和代码库。

主要变更:
- **移除旧版命令处理**: 删除了 `ChatBot` 中专门处理旧版 `BaseCommand` 的方法 (`_process_commands_with_new_system`) 和相关逻辑,现在所有命令都通过 `PlusCommand` 的处理流程。
- **重构组件注册中心**: 对 `ComponentRegistry` 进行了大规模重构和清理:
    - 添加了大量文档字符串和类型提示,显著提升了代码的可读性和可维护性。
    - 废弃了特定于 `BaseCommand` 的注册表和查找方法 (`_command_registry`, `_command_patterns`, `find_command_by_text`)。
    - 实现了 `unregister_plugin` 和 `remove_component` 方法,支持插件和组件在运行时的动态卸载。
    - 统一并简化了各类组件的注册、查询和状态管理逻辑,使其更加一致和健壮。

BREAKING CHANGE: 废弃了 `BaseCommand` 类。所有自定义命令现在必须继承自 `PlusCommand`。虽然系统提供了向后兼容的适配器,但强烈建议将现有命令迁移到 `PlusCommand` 以获得全部功能和最佳性能。直接依赖旧版 `BaseCommand` 注册和查找机制的代码将无法工作。
2025-11-22 12:35:37 +08:00
minecraft1024a
30bf1f68b1 refactor(plugin_system): 重构 Prompt 注入逻辑以实现动态化
本次重构的核心目标是将 Prompt 注入规则的处理方式从系统启动时的一次性加载,转变为在每次需要注入时实时、动态地构建。这解决了之前静态加载机制下,运行时启用/禁用 Prompt 组件无法影响其注入行为的问题。

主要变更包括:

- **PromptComponentManager 动态化**:
    - 移除了 `load_static_rules` 和 `_initialized` 标志,规则不再在启动时预加载到 `_dynamic_rules` 中。
    - `_dynamic_rules` 现在只存储通过 API 动态添加的纯运行时规则。
    - 新增 `_build_rules_for_target` 方法,该方法在 `apply_injections` 时被调用,实时从 `component_registry` 获取所有已启用的静态组件规则,并与 `_dynamic_rules` 中的运行时规则合并,确保规则集始终反映当前系统状态。

- **依赖 ComponentRegistry**:
    - `PromptComponentManager` 现在直接依赖 `component_registry` 来获取组件的最新启用状态和信息,而不是依赖自己预加载的缓存。
    - `get_registered_prompt_component_info`, `get_injection_info`, `get_injection_rules` 等多个 API 方法被修改为 `async`,并重写了内部逻辑,以动态查询和构建信息,确保返回的数据准确反映了当前所有可用组件(包括静态和纯动态)的注入配置。

- **ComponentRegistry 增强**:
    - 增加了对 Prompt 组件在禁用时从内部启用的注册表中移除的逻辑。
    - 扩展了 `is_component_available` 的逻辑,使其能正确处理不支持局部(stream-specific)状态的组件类型。
2025-11-22 11:15:45 +08:00
minecraft1024a
affd70b165 refactor(chat): 简化Action和PlusCommand的调用预处理
移除 `ChatBot` 和 `ActionModifier` 中用于过滤禁用组件的模板代码。

这两个模块现在直接从 `ComponentRegistry` 获取为当前聊天会话(`stream_id`)定制的可用组件列表。所有关于组件是否启用的判断逻辑都已下沉到 `plugin_system` 核心中,使得上层调用代码更清晰,且不再需要依赖 `global_announcement_manager` 来进行手动过滤。
2025-11-22 09:51:31 +08:00
minecraft1024a
a0618fb3c4 feat(plugin_system): 引入组件局部状态管理并重构插件API
引入了基于 `stream_id` 的组件局部状态管理机制。这允许在不修改全局配置的情况下,为特定会话临时启用或禁用组件,提供了更高的灵活性。

全面重构了 `plugin_manage_api`,提供了更强大和稳定的插件管理功能:
- 新增 `reload_all_plugins` 和 `get_system_report` API,方便进行批量重载和系统状态诊断。
- 增强了组件卸载逻辑,确保在插件移除时能更彻底地清理资源,特别是对 `EventHandler` 的订阅。
- 重写了内置的 `/system plugin` 命令,以利用新的API,并为相关操作添加了权限控制。

组件注册中心(ComponentRegistry)中的多个 `get_enabled_*` 方法现在可以接受 `stream_id`,以正确反映局部状态。

BREAKING CHANGE: `plugin_manage_api` 中的多个函数已被移除或替换。例如 `list_loaded_plugins` 和 `remove_plugin` 已被移除,加载插件的逻辑已整合到 `register_plugin_from_file` 中。内置的 `/system plugin` 命令的子命令也已更改。
2025-11-21 21:05:02 +08:00
Windpicker-owo
fee7611e99 feat: 实现消息编解码器和消息处理模型
- 添加编解码器,用于序列化和反序列化MessageEnvelope对象。
- 创建消息模型,包括分段(Seg)、群组信息(GroupInfo)、用户信息(UserInfo)、格式信息(FormatInfo)、模板信息(TemplateInfo)、基础消息信息(BaseMessageInfo)和消息基础(MessageBase)。
引入路由器以管理消息路由和连接。
- 实现运行时机制,通过钩子和路由来处理消息处理。
- 使用HTTP和WebSocket客户端和服务器开发传输层,以进行消息传输。
- 为消息内容和信封定义类型,以标准化消息结构。
2025-11-21 18:40:51 +08:00
Windpicker-owo
bd4e36b1cf feat(replyer): 添加最近消息支持以构建记忆块和查询文本 2025-11-20 18:06:23 +08:00
Windpicker-owo
6ecf5a36f2 增强聊天管理器和数据库API,添加自动注册和异步清理功能,优化模型转换为字典的逻辑 2025-11-20 16:48:18 +08:00
Windpicker-owo
80c1464ba7 Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox_Bot into dev 2025-11-19 20:19:10 +08:00
Windpicker-owo
2c346c3580 feat: 强制注册长期记忆目标ID,支持中文描述作为ID映射 2025-11-19 20:19:06 +08:00
Windpicker-owo
cf48d02ed3 feat: 重构记忆系统配置,移除三层记忆相关配置,优化全局记忆管理逻辑,支持批量生成文本向量 2025-11-19 19:16:27 +08:00
Windpicker-owo
14133410e6 feat: 批量生成文本embedding,优化兴趣匹配计算逻辑,支持消息兴趣值的批量更新 2025-11-19 16:30:44 +08:00
Windpicker-owo
75b806cd41 feat: 添加历史消息长度限制,优化上下文管理和消息处理逻辑 2025-11-19 13:59:40 +08:00
Windpicker-owo
d227e37a98 feat: 优化事件管理,添加事件处理超时和并发限制功能 2025-11-19 01:26:23 +08:00
Windpicker-owo
999d7b285f feat: 重构统一记忆管理器,整合聊天历史上下文并优化记忆块转移逻辑 2025-11-18 20:39:05 +08:00
Windpicker-owo
dc3ad19809 feat: 采用三层内存系统实现统一内存管理器
- 添加了UnifiedMemoryManager,以整合感知层、短期记忆层和长期记忆层。
- 实现了初始化、消息添加和内存搜索功能。
- 引入了记忆从短期存储到长期存储的自动转移机制。
- 开发了用于结构化内存表示的内存格式化工具。
- 增强日志记录功能,以便在内存操作过程中更好地进行追踪。
2025-11-18 16:17:25 +08:00
Windpicker-owo
b5cfa41d36 feat:实现短期内存管理器和统一内存管理器
- 添加了ShortTermMemoryManager来管理短期记忆,包括提取、决策和记忆操作。
- 集成大型语言模型(LLM),用于结构化记忆提取和决策过程。
- 基于重要性阈值,实现了从短期到长期的内存转移逻辑。
- 创建了UnifiedMemoryManager,通过统一接口整合感知记忆、短期记忆和长期记忆的管理。
- 通过法官模型评估来增强记忆提取过程的充分性。
- 增加了自动和手动内存传输功能。
- 包含内存管理操作和决策的全面日志记录。
2025-11-18 11:12:05 +08:00
tt-P607
8952a7392d feat(prompt): 指示模型使用更自然的用户昵称
在核心聊天提示中添加了一条新规则,以改善对用户的称呼方式。

这条规则指示模型避免直接重复复杂或含有符号的用户名。相反,它鼓励使用更自然的昵称或缩写,使对话感觉更像人与人之间的交流。
2025-11-17 09:38:45 +08:00
minecraft1024a
7a2c08c18e feat(prompt): 为提示词注入添加占位符保护机制
为防止注入规则(特别是使用宽泛正则表达式的 REMOVE 或 REPLACE 类型)意外修改或删除核心的 "{...}" 占位符,引入了一套新的占位符保护机制。

该机制通过以下步骤确保注入过程的安全性:
1.  **保护**:在应用任何规则之前,模板中的所有占位符都会被替换为唯一的临时标记。
2.  **预检与警告**:系统会检查所有危险规则(REMOVE/REPLACE),如果其目标内容可能匹配到被保护的占位符,则会记录一条警告日志。
3.  **安全应用**:所有注入规则在已保护的模板上按优先级顺序执行。
4.  **恢复**:完成所有注入后,临时标记被恢复为原始的占位符。

此项更改显著提升了提示词系统的鲁棒性,确保了核心模板的完整性不会被插件或动态规则无意中破坏。
2025-11-15 18:47:21 +08:00
minecraft1024a
6f62073630 chore: perform widespread code cleanup and formatting
Perform a comprehensive code cleanup across multiple modules to improve code quality, consistency, and maintainability.

Key changes include:
- Removing numerous unused imports.
- Standardizing import order.
- Eliminating trailing whitespace and inconsistent newlines.
- Updating legacy type hints to modern syntax (e.g., `List` -> `list`).
- Making minor improvements for code robustness and style.
2025-11-15 17:12:46 +08:00
minecraft1024a
f980a6f9f4 refactor(prompt): 将注意力和内容混淆统一为提示词扰动
本次提交重构了提示词修改逻辑,将之前独立的“注意力优化”和“内容混淆”功能合并为一个统一的概念:“提示词扰动”(Prompt Perturbation)。

主要变更包括:
- 在模型配置中引入新的统一选项:`enable_prompt_perturbation`, `perturbation_strength` 和 `enable_semantic_variants`。
- 将原 `AttentionOptimizer` 中的噪声注入和语义变体逻辑迁移到 `llm_models` 模块中,作为扰动策略的一部分。
- 简化 `attention_optimizer.py`,使其专注于提示词块重排 (`BlockShuffler`)。
- 更新 `_PromptProcessor` 以根据新的统一配置来协调不同的扰动技术。

此项更改为用户简化了配置,并通过集中化相关逻辑,提供了一个更清晰、更易于维护的实现。

BREAKING CHANGE: 内容混淆的相关配置已被替换。`enable_content_obfuscation` 和 `obfuscation_intensity` 配置项已移除。用户需更新配置以使用新的 `enable_prompt_perturbation` 和 `perturbation_strength`。
2025-11-14 20:14:19 +08:00
minecraft1024a
36b1b72e25 refactor(prompt): 移除注意力优化功能
注意力优化功能(通过添加随机空白字符或语义变体)被证明效果不佳且可能引入不稳定性。

为了简化代码库、减少用户配置的复杂性并提高系统的稳定性,决定移除此实验性功能。这使得提示词构建过程更加直接和可预测。

BREAKING CHANGE: 移除了注意力优化功能及其所有相关配置。用户需要从配置文件中移除 `[attention_optimization]` 部分。
2025-11-14 16:15:42 +08:00
minecraft1024a
d12c6d9b3a feat(prompt): 支持为组件添加新的注入规则
新增 `add_rule_for_component` 方法,允许为一个已存在的提示词组件添加一条新的注入规则。

该方法会自动查找并复用该组件已有的内容提供者 (content_provider) 和来源 (source),从而简化了为同一组件动态添加多个注入目标的操作。
2025-11-14 13:49:18 +08:00
minecraft1024a
ecf1714baa feat(prompt): 支持按组件名称批量移除注入规则
新增 `remove_all_rules_by_component_name` 方法,用于一次性移除指定提示词组件在所有目标上的注入规则。

此功能简化了组件的停用和清理流程,特别是在动态管理和热插拔组件的场景下,无需再手动遍历所有可能的目标提示词来逐一移除规则。
2025-11-14 13:34:36 +08:00
minecraft1024a
0d2234ca02 feat(prompt): 增强提示词组件信息获取,使其包含动态注入的组件
重构 `get_registered_prompt_component_info` 方法,以准确反映系统完整的提示词组件状态,包括静态注册和动态注入的组件。

此前的实现仅能返回静态注册的组件,无法展示通过动态规则注入的纯动态组件,导致信息不完整。

新的实现:
- 合并静态注册的组件和因动态注入规则而存在的组件。
- 为纯动态组件即时创建 `PromptInfo` 实例。
- 实时重建每个组件的 `injection_rules` 列表,以反映当前的注入配置。

这确保了前端或API调用方能够获取到所有可用提示词的最新、最准确的信息。
2025-11-14 13:10:25 +08:00
minecraft1024a
80210cfb58 feat(prompt): 增强 get_core_prompt_contents 方法以支持获取单个提示词
为 `get_core_prompt_contents` 方法添加了可选的 `prompt_name` 参数。
当指定 `prompt_name` 时,该方法现在只返回对应提示词模板的内容。如果未指定,则返回所有核心提示词。

BREAKING CHANGE: `get_core_prompt_contents` 方法的返回类型从 `dict[str, str]` 更改为 `list[list[str]]`,以统一处理单个和多个提示词的返回结果,确保接口行为的一致性。
2025-11-14 13:01:05 +08:00
minecraft1024a
ec1ce9db8e feat(statistic): 为供应商统计增加平均耗时和标准差指标
- 为按供应商分类的统计数据新增了平均请求耗时和耗时标准差的计算与展示。
- 重构了统计数据计算逻辑,统一使用 `defaultdict` 的直接索引访问替代 `.get()` 方法,使代码更简洁并提高了健壮性。
- 标准化了与耗时相关的统计键名,以提高代码的一致性和可读性。
2025-11-14 12:23:38 +08:00
tt-P607
a7e188f67c Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox_Bot into dev 2025-11-13 20:39:14 +08:00
tt-P607
dcc8f6477e refactor(chat): 简化括号内容过滤
将用于过滤 `[表情包:...]` 和 `[图片:...]` 等内容的多个特定正则表达式模式替换为一个更通用的 `[.*?]` 模式。

此更改简化了代码,并通过处理方括号内的任何内容(包括未处理的格式如 `[at=...]`)提高了过滤的稳健性。
2025-11-13 20:38:59 +08:00
minecraft1024a
718584a7da fix(statistic): 增强统计数据处理的健壮性
此前的统计处理逻辑在某些统计项(如模型调用、消息数)在特定周期内未产生数据时,会因为直接访问字典键而引发 `KeyError`,导致统计任务失败。

本次提交通过以下方式解决了该问题:
- 在访问统计字典时,全面使用 `dict.get()` 并提供默认值,避免因键不存在而崩溃。
- 使用 `setdefault` 来确保在计算平均耗时等指标前,相关的数据结构已被初始化。
- 简化并重构了历史总览数据的合并逻辑,使其在处理不完整数据时更加稳健。
2025-11-13 19:47:44 +08:00
minecraft1024a
2f46794a64 feat(statistic): 支持按 provider 统计请求 2025-11-13 18:38:47 +08:00
minecraft1024a
69f132a12e feat(prompt): 为提示词组件提供注入目标上下文
为了让单个提示词组件在注入到不同目标时能够有不同的行为,现在向组件的执行上下文中传递当前注入的目标提示词名称 (`target_prompt_name`)。

这使得组件可以根据注入点动态调整其生成的内容。例如,一个工具列表组件在注入到 planner prompt 和 reflection prompt 时可以提供不同详尽程度的列表。

主要变更:
- `BasePrompt` 初始化时接收 `target_prompt_name`。
- `PromptComponentManager` 在应用注入规则时会传递此参数。
- `add_injection_rule` 方法现在支持批量添加规则,以简化注册流程。

BREAKING CHANGE: `PromptComponentManager.add_injection_rule` 中 `content_provider` 的函数签名已更改,现在需要接受第二个参数 `target_prompt_name: str`。

旧签名: `async def provider(params: PromptParameters) -> str`
新签名: `async def provider(params: PromptParameters, target_prompt_name: str) -> str
2025-11-13 18:18:15 +08:00
minecraft1024a
ce2d1acc7c refactor(prompt): 简化和统一提示词注入查询方法
将多个功能重叠的查询方法整合为两个核心方法,以提供更清晰、更灵活的 API,方便获取注入信息和规则。

- `get_injection_info` 方法取代了原有的 `get_full_injection_map` 和 `get_injections_for_prompt`。它现在支持按目标提示词进行筛选,并能通过 `detailed` 参数控制返回信息的详细程度。
- `get_injection_rules` 方法整合了 `get_all_dynamic_rules`、`get_rules_for_target` 和 `get_rules_by_component` 的功能。现在可以通过一个方法,灵活地按目标、按组件或按两者的组合来筛选注入规则。
- 已更新 `system_management` 插件中的相关命令以适配新的 API。

BREAKING CHANGE: `PromptComponentManager` 的公共 API 已更改。
移除了 `get_full_injection_map`, `get_injections_for_prompt`, `get_all_dynamic_rules`, `get_rules_for_target`, `get_rules_by_component` 方法。
请分别使用新的 `get_injection_info` 和 `get_injection_rules` 方法进行替代。
2025-11-13 17:17:48 +08:00
tt-P607
30a1dd9242 Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox_Bot into dev 2025-11-13 16:28:51 +08:00