Skip to content

feat:发送消息前的At和Reply改用概率添加,同时过滤掉不支持的组件 #1818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions astrbot/core/config/astrbot_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ def check_config_integrity(self, refer_conf: Dict, conf: Dict, path=""):
# 创建一个新的有序字典以保持参考配置的顺序
new_conf = {}

# 向后兼容性处理
if path == "platform_settings":
for key in ["reply_with_mention", "reply_with_quote"]:
if key in conf and isinstance(conf[key], bool):
# 将布尔值转换为概率值
conf[key] = 1.0 if conf[key] else 0.0
has_new = True
logger.info(f"配置项 {key} 已从布尔值转换为概率值: {conf[key]}")

# 先按照参考配置的顺序添加配置项
for key, value in refer_conf.items():
if key not in conf:
Expand Down
12 changes: 6 additions & 6 deletions astrbot/core/config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"id_whitelist_log": True,
"wl_ignore_admin_on_group": True,
"wl_ignore_admin_on_friend": True,
"reply_with_mention": False,
"reply_with_quote": False,
"reply_with_mention": 0.0,
"reply_with_quote": 0.0,
Comment on lines +28 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: 为浮点概率添加 JSON 模式范围约束

请将 minimum: 0.0maximum: 1.0 添加到这些模式字段,以强制执行有效的概率值。

建议的实施方案:

                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
Original comment in English

suggestion: Add JSON schema range constraints for float probabilities

Please add minimum: 0.0 and maximum: 1.0 to these schema fields to enforce valid probability values.

Suggested implementation:

                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },

"path_mapping": [],
"segmented_reply": {
"enable": False,
Expand Down Expand Up @@ -466,13 +466,13 @@
},
"reply_with_mention": {
"description": "回复时 @ 发送者",
"type": "bool",
"hint": "启用后,机器人回复消息时会 @ 发送者。实际效果以具体的平台适配器为准。",
"type": "float",
"hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
},
"reply_with_quote": {
"description": "回复时引用消息",
"type": "bool",
"hint": "启用后,机器人回复消息时会引用原消息。实际效果以具体的平台适配器为准。",
"type": "float",
"hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
},
"path_mapping": {
"description": "路径映射",
Expand Down
16 changes: 10 additions & 6 deletions astrbot/core/pipeline/result_decorate/stage.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import random
import re
import time
import traceback
from typing import AsyncGenerator, Union

from astrbot.core import html_renderer, logger, file_token_service
from astrbot.core.message.components import At, File, Image, Node, Plain, Record, Reply
from astrbot.core.message.components import At, Face, File, Image, Node, Plain, Record, Reply
from astrbot.core.message.message_event_result import ResultContentType
from astrbot.core.platform.astr_message_event import AstrMessageEvent
from astrbot.core.platform.message_type import MessageType
Expand Down Expand Up @@ -263,7 +264,6 @@ async def process(
result.chain = [Image.fromFileSystem(url)]

# 触发转发消息
has_forwarded = False
if event.get_platform_name() == "aiocqhttp":
word_cnt = 0
for comp in result.chain:
Expand All @@ -274,13 +274,17 @@ async def process(
uin=event.get_self_id(), name="AstrBot", content=[*result.chain]
)
result.chain = [node]
has_forwarded = True

if not has_forwarded:

if any(isinstance(comp, (Plain, Face, Image, At)) for comp in result.chain):
# at 回复
if (
self.reply_with_mention
random.random() < self.reply_with_mention
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): 考虑强制执行有效的概率范围

这些概率的无效浮点数值可能会导致意外行为。在加载时限制它们,或者验证配置以确保它们保持在 0.0-1.0 之间。

建议的实施方案:

    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

如果在其他地方设置了 self.reply_with_mention(例如,通过配置加载器或 setter),则应在每次赋值时应用相同的限制逻辑。如果想在任何地方都强制执行此操作,请考虑将其设为具有 setter 的属性,该 setter 会限制该值。

Original comment in English

suggestion (bug_risk): Consider enforcing valid probability range

Invalid float values for these probabilities could cause unintended behavior. Clamp them at load time or validate the config to ensure they stay within 0.0–1.0.

Suggested implementation:

    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

If self.reply_with_mention is set elsewhere (e.g., via a config loader or setter), you should apply the same clamping logic at every assignment. If you want to enforce this everywhere, consider making it a property with a setter that clamps the value.

and event.get_message_type() != MessageType.FRIEND_MESSAGE
and not (
isinstance(result.chain[0], At)
and result.chain[0].qq == event.get_sender_id()
)
):
result.chain.insert(
0, At(qq=event.get_sender_id(), name=event.get_sender_name())
Expand All @@ -289,6 +293,6 @@ async def process(
result.chain[1].text = "\n" + result.chain[1].text

# 引用回复
if self.reply_with_quote:
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): 合并嵌套的 if 条件 (merge-nested-ifs)

Suggested change
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
if random.random() < self.reply_with_quote and not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))


Explanation过多的嵌套会使代码难以理解,这在 Python 中尤其如此,因为没有括号来帮助区分不同的嵌套级别。

阅读深度嵌套的代码令人困惑,因为您必须跟踪哪些条件与哪些级别相关。因此,我们努力尽可能减少嵌套,并且可以使用 and 组合两个 if 条件的情况很容易实现。

Original comment in English

suggestion (code-quality): Merge nested if conditions (merge-nested-ifs)

Suggested change
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
if random.random() < self.reply_with_quote and not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))


ExplanationToo much nesting can make code difficult to understand, and this is especially
true in Python, where there are no brackets to help out with the delineation of
different nesting levels.

Reading deeply nested code is confusing, since you have to keep track of which
conditions relate to which levels. We therefore strive to reduce nesting where
possible, and the situation where two if conditions can be combined using
and is an easy win.