Files
mai-bot/src/config/official_configs.py
2026-04-12 16:34:43 +08:00

2052 lines
54 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Literal, Optional
import re
from .config_base import ConfigBase, Field
"""
须知:
1. 本文件中记录了所有的配置项
2. 所有新增的class都需要继承自ConfigBase
3. 所有新增的class都应在official_configs.py中的Config类中添加字段
4. 对于新增的字段若为可选项则应在其后添加Field()并设置default_factory或default
5. 所有的配置项都应该按照如下方法添加字段说明:
class ExampleConfig(ConfigBase):
example_field: str
\"""This is an example field\"""
- 注释前面增加_warp_标记可以实现配置文件中注释在配置项前面单独一行显示
"""
class BotConfig(ConfigBase):
"""机器人配置类"""
__ui_label__ = "基本信息"
__ui_icon__ = "bot"
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台"""
qq_account: int = Field(
default=0,
json_schema_extra={
"x-widget": "input",
"x-icon": "user",
},
)
"""QQ账号"""
platforms: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "layers",
},
)
"""其他平台"""
nickname: str = Field(
default="麦麦",
json_schema_extra={
"x-widget": "input",
"x-icon": "user-circle",
},
)
"""机器人昵称"""
alias_names: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "tags",
},
)
"""别名列表"""
class PersonalityConfig(ConfigBase):
"""人格配置类"""
__ui_label__ = "人格"
__ui_icon__ = "user-circle"
personality: str = Field(
default="是一个大二在读女大学生,现在正在上网和群友聊天,有时有点攻击性,有时比较温柔",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "user-circle",
},
)
"""人格建议100字以内描述人格特质和身份特征"""
reply_style: str = Field(
default="请不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "message-square",
},
)
"""默认表达风格描述麦麦说话的表达风格表达习惯如要修改可以酌情新增内容建议1-2行"""
multiple_reply_style: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""可选的多种表达风格列表,当配置不为空时可按概率随机替换 reply_style"""
multiple_probability: float = Field(
default=0.3,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""每次构建回复时,从 multiple_reply_style 中随机替换 reply_style 的概率0.0-1.0"""
states: list[str] = Field(
default_factory=lambda: [
"是一个女大学生,喜欢上网聊天,会刷小红书。",
"是一个大二心理学生,会刷贴吧和中国知网。",
"是一个赛博网友,最近很想吐槽人。",
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "shuffle",
},
)
"""_wrap_状态列表用于随机替换personality"""
state_probability: float = Field(
default=0.3,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""状态概率每次构建人格时替换personality的概率"""
class VisualConfig(ConfigBase):
"""视觉配置类"""
__ui_label__ = "视觉"
__ui_icon__ = "image"
planner_mode: Literal["text", "multimodal", "auto"] = Field(
default="auto",
json_schema_extra={
"x-widget": "select",
"x-icon": "git-branch",
},
)
"""规划器模式auto根据模型信息自动选择text为纯文本模式multimodal为多模态模式"""
replyer_mode: Literal["text", "multimodal", "auto"] = Field(
default="auto",
json_schema_extra={
"x-widget": "select",
"x-icon": "git-branch",
},
)
"""回复器模式auto根据模型信息自动选择text为纯文本模式multimodal为多模态模式"""
visual_style: str = Field(
default="请用中文描述这张图片的内容。如果有文字请把文字描述概括出来请留意其主题直观感受输出为一段平文本最多30字请注意不要分点就输出一段文本",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "image",
},
)
"""_wrap_识图提示词不建议修改"""
class TalkRulesItem(ConfigBase):
platform: str = ""
"""平台与ID一起留空表示全局"""
item_id: str = ""
"""用户ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = "group"
"""聊天流类型group群聊或private私聊"""
time: str = ""
"""时间段,格式为 "HH:MM-HH:MM",支持跨夜区间"""
value: float = 0.5
"""聊天频率值范围0-1"""
class ChatConfig(ConfigBase):
"""聊天配置类"""
__ui_label__ = "聊天"
__ui_icon__ = "message-square"
talk_value: float = Field(
default=1,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "message-circle",
"step": 0.1,
},
)
"""聊天频率越小越沉默范围0-1"""
mentioned_bot_reply: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "at-sign",
},
)
"""是否启用提及必回复"""
inevitable_at_reply: bool = Field(default=True)
"""是否启用at必回复"""
max_context_size: int = Field(
default=30,
json_schema_extra={
"x-widget": "input",
"x-icon": "layers",
},
)
"""上下文长度"""
planner_interrupt_max_consecutive_count: int = Field(
default=2,
ge=0,
json_schema_extra={
"x-widget": "input",
"x-icon": "pause-circle",
},
)
"""Planner 连续被新消息打断的最大次数0 表示不启用打断"""
group_chat_prompt: str = Field(
default="""
你正在qq群里聊天下面是群里正在聊的内容其中包含聊天记录和聊天中的图片。
回复尽量简短一些。最好一次对一个话题进行回复,免得啰嗦或者回复内容太乱。请注意把握聊天内容。
不要回复的太频繁!控制回复的频率,不要每个人的消息都回复,只回复你感兴趣的或者主动提及你的。
""",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "users",
},
)
"""_wrap_群聊通用注意事项"""
private_chat_prompts: str = Field(
default="""
你正在聊天,下面是正在聊的内容,其中包含聊天记录和聊天中的图片。
回复尽量简短一些。请注意把握聊天内容。
请考虑对方的发言频率,想法,思考自己何时回复以及回复内容。
""",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "user",
},
)
"""_wrap_私聊通用注意事项"""
chat_prompts: list["ExtraPromptItem"] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
enable_talk_value_rules: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "settings",
},
)
"""是否启用动态发言频率规则"""
talk_value_rules: list[TalkRulesItem] = Field(
default_factory=lambda: [
TalkRulesItem(platform="", item_id="", rule_type="group", time="00:00-08:59", value=0.8),
TalkRulesItem(platform="", item_id="", rule_type="group", time="09:00-18:59", value=1.0),
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""
_wrap_思考频率规则列表支持按聊天流/按日内时段配置。
"""
class MessageReceiveConfig(ConfigBase):
"""消息接收配置类"""
__ui_parent__ = "response_post_process"
image_parse_threshold: int = Field(
default=5,
json_schema_extra={
"x-widget": "input",
"x-icon": "image",
},
)
"""
当消息中图片数量不超过此阈值时,启用图片解析功能,将图片内容解析为文本后再进行处理。
当消息中图片数量超过此阈值时,为了避免过度解析导致的性能问题,将跳过图片解析,直接进行处理。
"""
ban_words: set[str] = Field(
default_factory=lambda: set(),
json_schema_extra={
"x-widget": "custom",
"x-icon": "ban",
},
)
"""过滤词列表"""
ban_msgs_regex: set[str] = Field(
default_factory=lambda: set(),
json_schema_extra={
"x-widget": "custom",
"x-icon": "regex",
},
)
"""过滤正则表达式列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
for pattern in self.ban_msgs_regex:
try:
re.compile(pattern)
except re.error as e:
raise ValueError(f"Invalid regex pattern in ban_msgs_regex: '{pattern}'") from e
return super().model_post_init(context)
class TargetItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台与ID一起留空表示全局"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户/群ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
},
)
"""聊天流类型group群聊或private私聊"""
class MemoryConfig(ConfigBase):
"""记忆配置类"""
__ui_parent__ = "emoji"
global_memory: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "globe",
},
)
"""是否允许记忆检索在聊天记录中进行全局查询忽略当前chat_id仅对 search_chat_history 等工具生效)"""
global_memory_blacklist: list[TargetItem] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "shield-off",
},
)
"""_wrap_全局记忆黑名单当启用全局记忆时不将特定聊天流纳入检索"""
enable_memory_query_tool: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否启用 Maisaka 内置长期记忆检索工具 query_memory"""
memory_query_default_limit: int = Field(
default=5,
ge=1,
le=20,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""Maisaka 内置长期记忆检索工具 query_memory 的默认返回条数"""
long_term_auto_summary_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "book-open",
},
)
"""是否自动启动聊天总结并导入长期记忆"""
person_fact_writeback_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "user-round-pen",
},
)
"""是否在发送回复后自动提取并写回人物事实到长期记忆"""
chat_history_topic_check_message_threshold: int = Field(
default=80,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""聊天历史话题检查的消息数量阈值,当累积消息数达到此值时触发话题检查"""
chat_history_topic_check_time_hours: float = Field(
default=8.0,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
},
)
"""聊天历史话题检查的时间阈值(小时),当距离上次检查超过此时间且消息数达到最小阈值时触发话题检查"""
chat_history_topic_check_min_messages: int = Field(
default=20,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""聊天历史话题检查的时间触发模式下的最小消息数阈值"""
chat_history_finalize_no_update_checks: int = Field(
default=3,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "check-circle",
},
)
"""聊天历史话题打包存储的连续无更新检查次数阈值当话题连续N次检查无新增内容时触发打包存储"""
chat_history_finalize_message_count: int = Field(
default=5,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "package",
},
)
"""聊天历史话题打包存储的消息条数阈值,当话题的消息条数超过此值时触发打包存储"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置值"""
if self.chat_history_topic_check_message_threshold < 1:
raise ValueError(
f"chat_history_topic_check_message_threshold 必须至少为1当前值: {self.chat_history_topic_check_message_threshold}"
)
if self.chat_history_topic_check_time_hours <= 0:
raise ValueError(
f"chat_history_topic_check_time_hours 必须大于0当前值: {self.chat_history_topic_check_time_hours}"
)
if self.chat_history_topic_check_min_messages < 1:
raise ValueError(
f"chat_history_topic_check_min_messages 必须至少为1当前值: {self.chat_history_topic_check_min_messages}"
)
if self.chat_history_finalize_no_update_checks < 1:
raise ValueError(
f"chat_history_finalize_no_update_checks 必须至少为1当前值: {self.chat_history_finalize_no_update_checks}"
)
if self.chat_history_finalize_message_count < 1:
raise ValueError(
f"chat_history_finalize_message_count 必须至少为1当前值: {self.chat_history_finalize_message_count}"
)
return super().model_post_init(context)
class LearningItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台与ID一起留空表示全局"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
},
)
"""聊天流类型group群聊或private私聊"""
use_expression: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "message-square",
},
)
"""是否启用表达学习"""
enable_learning: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "graduation-cap",
},
)
"""是否启用表达优化学习"""
enable_jargon_learning: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "book",
},
)
"""是否启用jargon学习"""
advanced_chosen: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "sparkles",
},
)
"""是否启用基于子代理的二次表达方式选择"""
class ExpressionGroup(ConfigBase):
"""表达互通组配置类,若列表为空代表全局共享"""
expression_groups: list[TargetItem] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "users",
},
)
"""_wrap_表达学习互通组"""
class ExpressionConfig(ConfigBase):
"""表达配置类"""
__ui_label__ = "表达"
__ui_icon__ = "pen-tool"
learning_list: list[LearningItem] = Field(
default_factory=lambda: [
LearningItem(
platform="",
item_id="",
rule_type="group",
use_expression=True,
enable_learning=True,
enable_jargon_learning=True,
advanced_chosen=False,
)
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""_wrap_表达学习配置列表支持按聊天流配置"""
expression_groups: list[ExpressionGroup] = Field(
default_factory=list,
json_schema_extra={
"x-widget": "custom",
"x-icon": "users",
},
)
"""_wrap_表达学习互通组"""
expression_checked_only: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "check",
},
)
"""是否仅选择已检查且未拒绝的表达方式"""
expression_self_reflect: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "refresh-cw",
},
)
"""是否启用自动表达优化"""
expression_auto_check_interval: int = Field(
default=600,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
},
)
"""表达方式自动检查的间隔时间(秒)"""
expression_auto_check_count: int = Field(
default=20,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""每次自动检查时随机选取的表达方式数量"""
expression_auto_check_custom_criteria: list[str] = Field(
default_factory=list,
json_schema_extra={
"x-widget": "custom",
"x-icon": "file-text",
},
)
"""表达方式自动检查的额外自定义评估标准"""
all_global_jargon: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "globe",
},
)
"""是否开启全局黑话模式,注意,此功能关闭后,已经记录的全局黑话不会改变,需要手动删除"""
class VoiceConfig(ConfigBase):
"""语音识别配置类"""
__ui_parent__ = "emoji"
enable_asr: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "mic",
},
)
"""是否启用语音识别,启用后麦麦可以识别语音消息"""
class EmojiConfig(ConfigBase):
"""表情包配置类"""
__ui_label__ = "功能"
__ui_icon__ = "puzzle"
emoji_send_num: int = Field(
default=25,
ge=1,
le=64,
json_schema_extra={
"x-widget": "input",
"x-icon": "grid",
},
)
"""一次从多少个表情包中选择发送,最大为 64"""
max_reg_num: int = Field(
default=64,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""表情包最大注册数量"""
do_replace: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "refresh-cw",
},
)
"""达到最大注册数量时替换旧表情包,关闭则达到最大数量时不会继续收集表情包"""
check_interval: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
},
)
"""表情包检查间隔(分钟)"""
steal_emoji: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "copy",
},
)
"""是否偷取表情包,让麦麦可以将一些表情包据为己有"""
content_filtration: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "filter",
},
)
"""是否启用表情包过滤,只有符合该要求的表情包才会被保存"""
filtration_prompt: str = Field(
default="符合公序良俗",
json_schema_extra={
"x-widget": "input",
"x-icon": "shield",
},
)
"""表情包过滤要求,只有符合该要求的表情包才会被保存"""
class KeywordRuleConfig(ConfigBase):
"""关键词规则配置类"""
keywords: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "tag",
},
)
"""关键词列表"""
regex: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "regex",
},
)
"""正则表达式列表"""
reaction: str = Field(
default="",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "message-circle",
},
)
"""关键词触发的反应"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置"""
if not self.keywords and not self.regex:
raise ValueError("关键词规则必须至少包含keywords或regex中的一个")
if not self.reaction:
raise ValueError("关键词规则必须包含reaction")
for pattern in self.regex:
try:
re.compile(pattern)
except re.error as e:
raise ValueError(f"无效的正则表达式 '{pattern}': {str(e)}") from e
return super().model_post_init(context)
class KeywordReactionConfig(ConfigBase):
"""关键词配置类"""
__ui_parent__ = "response_post_process"
keyword_rules: list[KeywordRuleConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""关键词规则列表"""
regex_rules: list[KeywordRuleConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""正则表达式规则列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置"""
for rule in self.keyword_rules + self.regex_rules:
if not isinstance(rule, KeywordRuleConfig):
raise ValueError(f"规则必须是KeywordRuleConfig类型而不是{type(rule).__name__}")
return super().model_post_init(context)
class ResponsePostProcessConfig(ConfigBase):
"""回复后处理配置类"""
__ui_label__ = "处理"
__ui_icon__ = "settings"
enable_response_post_process: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "settings",
},
)
"""是否启用回复后处理,包括错别字生成器,回复分割器"""
class ChineseTypoConfig(ConfigBase):
"""中文错别字配置类"""
__ui_parent__ = "response_post_process"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "type",
},
)
"""是否启用中文错别字生成器"""
error_rate: float = Field(
default=0.01,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.01,
},
)
"""单字替换概率"""
min_freq: int = Field(
default=9,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""最小字频阈值"""
tone_error_rate: float = Field(
default=0.1,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""声调错误概率"""
word_replace_rate: float = Field(
default=0.006,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.001,
},
)
"""整词替换概率"""
class ResponseSplitterConfig(ConfigBase):
"""回复分割器配置类"""
__ui_parent__ = "response_post_process"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "scissors",
},
)
"""是否启用回复分割器"""
max_length: int = Field(
default=512,
json_schema_extra={
"x-widget": "input",
"x-icon": "ruler",
},
)
"""回复允许的最大长度"""
max_sentence_num: int = Field(
default=8,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""回复允许的最大句子数"""
enable_kaomoji_protection: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "smile",
},
)
"""是否启用颜文字保护"""
enable_overflow_return_all: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "maximize",
},
)
"""是否在句子数量超出回复允许的最大句子数时一次性返回全部内容"""
class TelemetryConfig(ConfigBase):
"""遥测配置类"""
__ui_parent__ = "debug"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "activity",
},
)
"""是否启用遥测"""
class DebugConfig(ConfigBase):
"""调试配置类"""
__ui_label__ = "其他"
__ui_icon__ = "more-horizontal"
show_prompt: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "eye",
},
)
"""是否显示prompt"""
show_maisaka_thinking: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "brain",
},
)
"""是否显示回复器推理"""
fold_maisaka_thinking: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "minimize-2",
},
)
"""是否折叠 Maisaka 的 prompt 展示入口"""
show_jargon_prompt: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "book",
},
)
"""是否显示jargon相关提示词"""
show_memory_prompt: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否显示记忆检索相关prompt"""
class ExtraPromptItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台,留空无效"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户ID留空无效"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
},
)
"""聊天流类型group群聊或private私聊"""
prompt: str = Field(
default="",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "file-text",
},
)
"""额外的prompt内容"""
def model_post_init(self, context: Optional[dict] = None) -> None:
if not self.platform and not self.item_id and not self.prompt:
return super().model_post_init(context)
if not self.platform or not self.item_id or not self.prompt:
raise ValueError("ExtraPromptItem 中 platform, id 和 prompt 不能为空")
return super().model_post_init(context)
class MaimMessageConfig(ConfigBase):
"""maim_message配置类"""
__ui_parent__ = "debug"
ws_server_host: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "server",
},
)
"""旧版基于WS的服务器主机地址"""
ws_server_port: int = Field(
default=8080,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""旧版基于WS的服务器端口号"""
auth_token: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "key",
},
)
"""认证令牌用于旧版API验证为空则不启用验证"""
enable_api_server: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "server",
},
)
"""是否启用额外的新版API Server"""
api_server_host: str = Field(
default="0.0.0.0",
json_schema_extra={
"x-widget": "input",
"x-icon": "globe",
},
)
"""新版API Server主机地址"""
api_server_port: int = Field(
default=8090,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""新版API Server端口号"""
api_server_use_wss: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "lock",
},
)
"""新版API Server是否启用WSS"""
api_server_cert_file: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "file",
},
)
"""新版API Server SSL证书文件路径"""
api_server_key_file: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "key",
},
)
"""新版API Server SSL密钥文件路径"""
api_server_allowed_api_keys: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "shield",
},
)
"""新版API Server允许的API Key列表为空则允许所有连接"""
class LPMMKnowledgeConfig(ConfigBase):
"""LPMM知识库配置类"""
__ui_label__ = "知识库"
__ui_icon__ = "book-open"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否启用LPMM知识库"""
lpmm_mode: Literal["classic", "agent"] = Field(
default="classic",
json_schema_extra={
"x-widget": "select",
"x-icon": "brain",
},
)
"""LPMM知识库模式可选classic经典模式agent 模式"""
rag_synonym_search_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""同义检索TopK"""
rag_synonym_threshold: float = Field(
default=0.8,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""同义阈值,相似度高于该值的关系会被当作同义词"""
info_extraction_workers: int = Field(
default=3,
json_schema_extra={
"x-widget": "input",
"x-icon": "cpu",
},
)
"""实体抽取同时执行线程数非Pro模型不要设置超过5"""
qa_relation_search_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""关系检索TopK"""
qa_relation_threshold: float = Field(
default=0.75,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.05,
},
)
"""关系阈值,相似度高于该值的关系会被认为是相关关系"""
qa_paragraph_search_top_k: int = Field(
default=1000,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""段落检索TopK不能过小可能影响搜索结果"""
qa_paragraph_node_weight: float = Field(
default=0.05,
json_schema_extra={
"x-widget": "slider",
"x-icon": "weight",
"step": 0.01,
},
)
"""段落节点权重(在图搜索&PPR计算中的权重当搜索仅使用DPR时此参数不起作用"""
qa_ent_filter_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""实体过滤TopK"""
qa_ppr_damping: float = Field(
default=0.8,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""PPR阻尼系数"""
qa_res_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""最终提供段落TopK"""
embedding_dimension: int = Field(
default=1024,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""嵌入向量维度,输出维度"""
max_embedding_workers: int = Field(
default=3,
json_schema_extra={
"x-widget": "input",
"x-icon": "cpu",
},
)
"""嵌入/抽取并发线程数"""
embedding_chunk_size: int = Field(
default=4,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""每批嵌入的条数"""
max_synonym_entities: int = Field(
default=2000,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""同义边参与的实体数上限,超限则跳过"""
enable_ppr: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "zap",
},
)
"""是否启用PPR低配机器可关闭"""
class WebUIConfig(ConfigBase):
"""WebUI配置类"""
__ui_label__ = "WebUI"
__ui_icon__ = "layout"
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "monitor",
},
)
"""是否启用WebUI"""
host: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "globe",
},
)
"""WebUI 绑定主机地址"""
port: int = Field(
default=8001,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""WebUI 绑定端口"""
mode: Literal["development", "production"] = Field(
default="production",
json_schema_extra={
"x-widget": "select",
"x-icon": "settings",
},
)
"""运行模式development(开发) 或 production(生产)"""
anti_crawler_mode: Literal["false", "strict", "loose", "basic"] = Field(
default="basic",
json_schema_extra={
"x-widget": "select",
"x-icon": "shield",
},
)
"""防爬虫模式false(禁用) / strict(严格) / loose(宽松) / basic(基础-只记录不阻止)"""
allowed_ips: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "network",
},
)
"""IP白名单逗号分隔支持精确IP、CIDR格式和通配符"""
trusted_proxies: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "server",
},
)
"""信任的代理IP列表逗号分隔只有来自这些IP的X-Forwarded-For才被信任"""
trust_xff: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "shield-check",
},
)
"""是否启用X-Forwarded-For代理解析默认false"""
secure_cookie: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "cookie",
},
)
"""是否启用安全Cookie仅通过HTTPS传输默认false"""
enable_paragraph_content: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "file-text",
},
)
"""是否在知识图谱中加载段落完整内容需要加载embedding store会占用额外内存"""
class DatabaseConfig(ConfigBase):
"""数据库配置类"""
__ui_parent__ = "debug"
save_binary_data: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "save",
},
)
"""
是否将消息中的二进制数据保存为独立文件
若启用,消息中的语音等二进制数据将会保存为独立文件,并在消息中以特殊标记替代。启用会导致数据文件夹体积增大,但可以实现二次识别等功能。
若禁用,则消息中的二进制将会在识别后删除,并在消息中使用识别结果替代,无法二次识别
该配置项仅影响新存储的消息,已有消息不会受到影响
"""
class MaiSakaConfig(ConfigBase):
"""MaiSaka 对话系统配置类"""
__ui_label__ = "MaiSaka"
__ui_icon__ = "message-circle"
cli_user_name: str = Field(
default="用户",
json_schema_extra={
"x-widget": "input",
"x-icon": "user",
},
)
"""MaiSaka 使用的用户名称"""
show_image_path: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "image",
},
)
"""是否显示图片本地路径"""
class MCPAuthorizationConfig(ConfigBase):
"""MCP HTTP 认证配置。"""
mode: Literal["none", "bearer"] = Field(
default="none",
json_schema_extra={
"x-widget": "select",
"x-icon": "shield",
},
)
"""认证模式,当前支持无认证和静态 Bearer Token"""
bearer_token: str = Field(
default="",
json_schema_extra={
"x-widget": "password",
"x-icon": "key",
},
)
"""静态 Bearer Token仅在 `mode=\"bearer\"` 时使用"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 认证配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.mode == "bearer" and not self.bearer_token.strip():
raise ValueError("MCP 使用 bearer 认证时必须填写 bearer_token")
return super().model_post_init(context)
class MCPRootItemConfig(ConfigBase):
"""单个 MCP Root 配置。"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""是否启用当前 Root"""
uri: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "folder",
},
)
"""Root URI通常为 `file://` 路径 URI"""
name: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "tag",
},
)
"""Root 的显示名称"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证单个 Root 配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.enabled and not self.uri.strip():
raise ValueError("启用的 MCP Root 必须填写 uri")
return super().model_post_init(context)
class MCPRootsConfig(ConfigBase):
"""MCP Roots 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "folder-tree",
},
)
"""是否向 MCP 服务器暴露 Roots 能力"""
items: list[MCPRootItemConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "folder",
},
)
"""Roots 列表"""
class MCPSamplingConfig(ConfigBase):
"""MCP Sampling 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "brain",
},
)
"""是否启用 Sampling 能力声明"""
task_name: str = Field(
default="planner",
json_schema_extra={
"x-widget": "input",
"x-icon": "sparkles",
},
)
"""执行 Sampling 请求时使用的主程序模型任务名"""
include_context_support: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "layers",
},
)
"""是否声明支持 `includeContext` 非 `none` 语义"""
tool_support: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "wrench",
},
)
"""是否声明支持在 Sampling 中继续使用工具"""
class MCPElicitationConfig(ConfigBase):
"""MCP Elicitation 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "message-circle-question",
},
)
"""是否启用 Elicitation 能力声明"""
allow_form: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "form-input",
},
)
"""是否允许表单模式 Elicitation"""
allow_url: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "link",
},
)
"""是否允许 URL 模式 Elicitation"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 Elicitation 配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.enable and not (self.allow_form or self.allow_url):
raise ValueError("启用 MCP Elicitation 时至少需要允许一种模式")
return super().model_post_init(context)
class MCPClientConfig(ConfigBase):
"""MCP 客户端宿主能力配置。"""
client_name: str = Field(
default="MaiBot",
json_schema_extra={
"x-widget": "input",
"x-icon": "bot",
},
)
"""MCP 客户端实现名称"""
client_version: str = Field(
default="1.0.0",
json_schema_extra={
"x-widget": "input",
"x-icon": "info",
},
)
"""MCP 客户端实现版本"""
roots: MCPRootsConfig = Field(default_factory=MCPRootsConfig)
"""Roots 能力配置"""
sampling: MCPSamplingConfig = Field(default_factory=MCPSamplingConfig)
"""Sampling 能力配置"""
elicitation: MCPElicitationConfig = Field(default_factory=MCPElicitationConfig)
"""Elicitation 能力配置"""
class MCPServerItemConfig(ConfigBase):
"""单个 MCP 服务器配置。"""
name: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "tag",
},
)
"""服务器名称,必须唯一"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""是否启用当前 MCP 服务器"""
transport: Literal["stdio", "streamable_http"] = Field(
default="stdio",
json_schema_extra={
"x-widget": "select",
"x-icon": "shuffle",
},
)
"""传输方式,可选 `stdio` 或 `streamable_http`"""
command: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "terminal",
},
)
"""stdio 模式下启动服务器的命令"""
args: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""stdio 模式下的命令参数列表"""
env: dict[str, str] = Field(
default_factory=lambda: {},
json_schema_extra={
"x-widget": "custom",
"x-icon": "variable",
},
)
"""stdio 模式下附加的环境变量"""
url: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""`streamable_http` 模式下的 MCP 端点地址"""
headers: dict[str, str] = Field(
default_factory=lambda: {},
json_schema_extra={
"x-widget": "custom",
"x-icon": "file-json",
},
)
"""HTTP 模式下附加的请求头"""
http_timeout_seconds: float = Field(
default=30.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock-3",
},
)
"""HTTP 请求超时时间,单位秒"""
read_timeout_seconds: float = Field(
default=300.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""会话读取超时时间,单位秒"""
authorization: MCPAuthorizationConfig = Field(default_factory=MCPAuthorizationConfig)
"""HTTP 认证配置"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 服务器配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if not self.name.strip():
raise ValueError("MCPServerItemConfig.name 不能为空")
if self.transport == "stdio" and not self.command.strip():
raise ValueError(f"MCP 服务器 {self.name} 使用 stdio 时必须填写 command")
if self.transport == "streamable_http" and not self.url.strip():
raise ValueError(f"MCP 服务器 {self.name} 使用 streamable_http 时必须填写 url")
return super().model_post_init(context)
class MCPConfig(ConfigBase):
"""MCP 总配置。"""
__ui_parent__ = "maisaka"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "zap",
},
)
"""是否启用 MCPModel Context Protocol"""
client: MCPClientConfig = Field(default_factory=MCPClientConfig)
"""MCP 客户端宿主能力配置"""
servers: list[MCPServerItemConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "server",
},
)
"""_wrap_MCP 服务器配置列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 总配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
server_names = [server.name.strip() for server in self.servers if server.name.strip()]
if len(server_names) != len(set(server_names)):
raise ValueError("MCP 配置中的服务器名称不能重复")
return super().model_post_init(context)
class PluginRuntimeRenderConfig(ConfigBase):
"""插件运行时浏览器渲染配置。"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "image",
},
)
"""是否启用插件运行时浏览器渲染能力"""
browser_ws_endpoint: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""优先复用的现有 Chromium CDP 地址,可填写 ws/http 端点"""
executable_path: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "folder",
},
)
"""浏览器可执行文件路径,留空时自动探测本机 Chrome/Chromium"""
browser_install_root: str = Field(
default="data/playwright-browsers",
json_schema_extra={
"x-widget": "input",
"x-icon": "hard-drive",
},
)
"""Playwright 托管浏览器目录,自动下载 Chromium 时会复用该目录"""
headless: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "monitor",
},
)
"""是否以无头模式启动浏览器"""
launch_args: list[str] = Field(
default_factory=lambda: [
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-setuid-sandbox",
"--no-sandbox",
"--no-zygote",
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "terminal",
},
)
"""浏览器启动参数列表"""
concurrency_limit: int = Field(
default=2,
ge=1,
json_schema_extra={
"x-widget": "number",
"x-icon": "layers",
},
)
"""同时允许进行的最大渲染任务数"""
startup_timeout_sec: float = Field(
default=20.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock",
},
)
"""浏览器连接或启动超时时间(秒)"""
render_timeout_sec: float = Field(
default=15.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""单次渲染默认超时时间(秒)"""
auto_download_chromium: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "download",
},
)
"""未检测到可用浏览器时,是否自动下载 Playwright Chromium"""
download_connection_timeout_sec: float = Field(
default=120.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "cloud-lightning",
},
)
"""自动下载 Chromium 时的连接超时时间(秒)"""
restart_after_render_count: int = Field(
default=200,
ge=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "refresh-cw",
},
)
"""累计渲染指定次数后自动重建本地浏览器0 表示关闭该策略"""
class PluginRuntimeConfig(ConfigBase):
"""插件运行时配置类"""
__ui_label__ = "插件运行时"
__ui_icon__ = "puzzle"
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""启用插件系统"""
health_check_interval_sec: float = Field(
default=30.0,
json_schema_extra={
"x-widget": "number",
"x-icon": "activity",
},
)
"""健康检查间隔(秒)"""
max_restart_attempts: int = Field(
default=3,
json_schema_extra={
"x-widget": "number",
"x-icon": "refresh-cw",
},
)
"""Runner 崩溃后最大自动重启次数"""
runner_spawn_timeout_sec: float = Field(
default=30.0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock",
},
)
"""等待 Runner 子进程启动并注册的超时时间(秒)"""
hook_blocking_timeout_sec: float = Field(
default=30,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""Hook 阻塞步骤的全局超时上限(秒)"""
ipc_socket_path: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""
自定义 IPC Socket 路径(仅 Linux/macOS 生效)
留空则自动生成临时路径
"""
render: PluginRuntimeRenderConfig = Field(default_factory=PluginRuntimeRenderConfig)
"""浏览器渲染能力配置"""