-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
feat(pipeline): 预回应表情功能 - 外层包装 + 自动撤回 #7009
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
Open
Sclock
wants to merge
15
commits into
AstrBotDevs:master
Choose a base branch
from
Sclock:fix/pre-ack-emoji
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
39c7d99
feat(platform): add base remove_react method to AstrMessageEvent
5c40ca6
feat(config): add discord defaults and auto_remove to pre_ack_emoji c…
463b94c
feat(lark): implement remove_react for reaction removal
9ca8ded
feat(discord): implement remove_react for reaction removal
59a222f
feat(telegram): implement remove_react for reaction removal
629ae02
feat(pipeline): add PreAckEmojiManager with full test coverage
439700c
feat(pipeline): integrate PreAckEmojiManager and remove old PreProces…
1c6ecb5
feat(i18n): add auto_remove config descriptions for pre_ack_emoji
5f70bec
test(pipeline): add execution count tests for onion model correctness
7ceacbd
fix: decouple Lark reaction_id from event, use EmojiRef dataclass
16d545c
fix: update react() return type annotation to str | None
5dfb64d
fix: remove is_at_or_wake_command guard from pre-ack emoji
9e56476
fix(pipeline): prevent duplicate stage execution after onion yield
828891f
Revert "fix(pipeline): prevent duplicate stage execution after onion …
805b75f
Revert "Revert "fix(pipeline): prevent duplicate stage execution afte…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import random | ||
| from dataclasses import dataclass | ||
|
|
||
| from astrbot.core import logger | ||
| from astrbot.core.platform import AstrMessageEvent | ||
|
|
||
|
|
||
| @dataclass | ||
| class EmojiRef: | ||
| """贴出的表情引用,包含撤回所需的全部信息。""" | ||
|
|
||
| emoji: str | ||
| reaction_id: str | None = None # 飞书需要 reaction_id 来撤回 | ||
|
|
||
|
|
||
| class PreAckEmojiManager: | ||
| """预回应表情管理器。 | ||
|
|
||
| 在 pipeline 执行前贴表情,执行后根据配置撤回。 | ||
| 运行在洋葱模型外层,不参与 stage 调度。 | ||
| """ | ||
|
|
||
| SUPPORTED_PLATFORMS = ("telegram", "lark", "discord") | ||
|
|
||
| def __init__(self, config: dict) -> None: | ||
| self.config = config | ||
|
|
||
| def _get_cfg(self, platform: str) -> dict: | ||
| return ( | ||
| self.config.get("platform_specific", {}) | ||
| .get(platform, {}) | ||
| .get("pre_ack_emoji", {}) | ||
| ) or {} | ||
|
|
||
| async def add_emoji(self, event: AstrMessageEvent) -> EmojiRef | None: | ||
| """贴表情。返回 EmojiRef,或 None(未贴)。""" | ||
| platform = event.get_platform_name() | ||
| if platform not in self.SUPPORTED_PLATFORMS: | ||
| return None | ||
|
|
||
| cfg = self._get_cfg(platform) | ||
| emojis = cfg.get("emojis") or [] | ||
|
|
||
| if not cfg.get("enable", False) or not emojis: | ||
| return None | ||
|
|
||
| emoji = random.choice(emojis) | ||
| try: | ||
| reaction_id = await event.react(emoji) | ||
| return EmojiRef(emoji=emoji, reaction_id=reaction_id) | ||
| except Exception as e: | ||
| logger.warning(f"{platform} 预回应表情发送失败: {e}") | ||
| return None | ||
|
|
||
| async def remove_emoji(self, event: AstrMessageEvent, ref: EmojiRef | None) -> None: | ||
| """根据配置撤回表情。""" | ||
| if ref is None: | ||
| return | ||
|
|
||
| platform = event.get_platform_name() | ||
| cfg = self._get_cfg(platform) | ||
|
|
||
| if not cfg.get("auto_remove", True): | ||
| return | ||
|
|
||
| try: | ||
| await event.remove_react(ref.emoji, reaction_id=ref.reaction_id) | ||
| except Exception as e: | ||
| logger.warning(f"{platform} 预回应表情撤回失败: {e}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR 描述中提到修复了洋葱模型重复执行后续阶段的 bug,并且添加了对应的单元测试 (
test_pipeline_execution.py)。但我在_process_stages方法中没有看到对应的修复。目前的实现中,当一个 generator stage (
i) 执行完毕后(async for循环结束),外层for循环会继续执行i+1,导致i+1以及之后的所有阶段被再次执行。这会导致test_pipeline_execution.py中的测试失败。为了修复这个问题,需要在
async for循环之后判断是否真的发生了yield。如果发生了,就应该break外层循环,因为后续阶段已经在递归调用_process_stages(event, i + 1)中处理过了。建议将
_process_stages方法修改如下:这个修改引入了
did_yield标志位,确保只有在 generator stage 真正yield并进入内层逻辑后,才会中断外层循环,从而避免了重复执行的问题。对于没有yield的 generator stage,其行为保持不变,会继续执行后续 stage.