插件定时能力扩展:接入天气/群总结/百科问答/成员画像并补齐周月触发器编辑

- 将 weather、message_summary、game_task、member_context 从硬编码 async_job 注册迁移为插件调度能力(get_schedule_actions/run_scheduled_action)\n- 保持原有默认时间与默认启用行为,新增执行统计结果用于后台日志展示\n- 为群总结与天气推送增加目标群范围适配,支持按后台配置选择 all/白名单/单群执行\n- 成员交互摘要支持日/周/月三类动作接入调度中心,兼容指定群与全量群刷新\n- 后台插件调度页面新增 every_week_time 与 every_month_last_day_time 的编辑支持
This commit is contained in:
liuwei
2026-04-16 15:49:02 +08:00
parent 184999b175
commit 1166323ab5
5 changed files with 333 additions and 66 deletions

View File

@@ -12,7 +12,6 @@ from base.plugin_common.message_plugin_interface import MessagePluginInterface
from base.plugin_common.plugin_interface import PluginStatus
from db.message_summary_db import MessageSummaryDBOperator
from utils.compress_chat_data import compress_chat_data
from utils.decorator.async_job import async_job
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.decorator.points_decorator import plugin_points_cost
from utils.decorator.rate_limit_decorator import group_feature_rate_limit
@@ -73,8 +72,6 @@ class MessageSummaryPlugin(MessagePluginInterface):
self._auto_revoke = None
# 注册功能权限
self.feature = self.register_feature()
# 注册定时任务每天早上9点总结昨天的聊天信息
async_job.at_times(["09:00"])(self.daily_summary_job)
def initialize(self, context: Dict[str, Any]) -> bool:
"""初始化插件"""
@@ -203,6 +200,49 @@ class MessageSummaryPlugin(MessagePluginInterface):
self.LOG.error(f"处理消息总结命令失败: {e}")
return False, None
def get_schedule_actions(self) -> List[Dict[str, Any]]:
"""声明群总结插件支持的后台可配置定时动作。"""
return [
{
"action_key": "daily_summary",
"name": "昨日群聊总结推送",
"description": "每天自动总结昨天群聊内容并发送到目标群",
"trigger_type": "at_times",
"trigger_config": {"time_list": ["09:00"]},
"target_scope": "all_enabled_groups",
"target_config": {},
"payload": {"min_messages": 100},
# 保持与原先硬编码任务一致:默认启用。
"default_enabled": True,
}
]
async def run_scheduled_action(self, action_key: str, context: Dict[str, Any]) -> Dict[str, Any]:
"""执行群总结定时动作,返回结构化执行结果。"""
if action_key != "daily_summary":
return {
"success": False,
"summary": f"不支持的动作: {action_key}",
"detail": {"action_key": action_key},
}
payload = context.get("payload") or {}
# 使用后台可配置参数控制最低消息阈值,避免写死在代码里。
min_messages = int(payload.get("min_messages", 100))
target_groups = context.get("target_groups") or []
result = await self.daily_summary_job(
target_groups=[str(g).strip() for g in target_groups if str(g).strip()],
min_message_count=min_messages,
)
return {
"success": bool(result.get("failed_groups", 0) == 0),
"summary": (
f"群总结完成: 目标{result.get('total_groups', 0)}群,"
f"发送成功{result.get('sent_groups', 0)}群,失败{result.get('failed_groups', 0)}"
),
"detail": result,
}
async def _async_generate_and_send_summary(
self,
chat_content: str,
@@ -545,12 +585,24 @@ class MessageSummaryPlugin(MessagePluginInterface):
section = "\n".join(section_lines)
return f"{section}\n\n{summary.strip()}"
async def daily_summary_job(self):
"""定时任务每天早上9点总结昨天的聊天信息"""
async def daily_summary_job(
self,
target_groups: Optional[List[str]] = None,
min_message_count: int = 100,
) -> Dict[str, Any]:
"""定时任务:总结指定群在昨日的聊天信息并推送。
Args:
target_groups: 目标群列表;为空时自动取所有已开启权限的群。
min_message_count: 触发总结的最低消息条数阈值。
Returns:
dict: 执行统计信息,便于后台调度日志展示。
"""
try:
if not self.bot:
self.LOG.warning("每日聊天总结任务跳过bot 尚未注入")
return
return {"total_groups": 0, "sent_groups": 0, "failed_groups": 0, "skipped_groups": 0}
self.LOG.info("开始执行每日聊天总结任务")
# 计算昨天的时间范围
@@ -561,24 +613,32 @@ class MessageSummaryPlugin(MessagePluginInterface):
self.LOG.info(
f"总结时间范围: {yesterday_start.strftime('%Y-%m-%d %H:%M:%S')}{yesterday_end.strftime('%Y-%m-%d %H:%M:%S')}")
# 获取所有启用了群机器人的群聊
all_groups = GroupBotManager.get_group_list()
# 调度动作支持“全部启用群”与“指定群”两种模式;指定群也会再做权限校验,防止误推送。
if target_groups:
enabled_groups = []
for group_id in target_groups:
if GroupBotManager.get_group_permission(group_id, self.feature) == PermissionStatus.ENABLED:
enabled_groups.append(group_id)
self.LOG.info(f"按指定目标群执行总结,输入={len(target_groups)},权限通过={len(enabled_groups)}")
else:
all_groups = GroupBotManager.get_group_list()
if not all_groups:
self.LOG.info("没有群聊启用群机器人,跳过定时总结")
return {"total_groups": 0, "sent_groups": 0, "failed_groups": 0, "skipped_groups": 0}
if not all_groups:
self.LOG.info("没有群聊启用群机器人,跳过定时总结")
return
# 筛选出开启了总结功能的群聊
enabled_groups = []
for group_id in all_groups:
if GroupBotManager.get_group_permission(group_id, self.feature) == PermissionStatus.ENABLED:
enabled_groups.append(group_id)
enabled_groups = []
for group_id in all_groups:
if GroupBotManager.get_group_permission(group_id, self.feature) == PermissionStatus.ENABLED:
enabled_groups.append(group_id)
if not enabled_groups:
self.LOG.info("没有群聊开启定时总结功能,跳过")
return
return {"total_groups": 0, "sent_groups": 0, "failed_groups": 0, "skipped_groups": 0}
self.LOG.info(f"找到 {len(enabled_groups)} 个开启定时总结的群聊")
sent_groups = 0
failed_groups = 0
skipped_groups = 0
# 为每个群生成总结
for group_id in enabled_groups:
@@ -590,9 +650,10 @@ class MessageSummaryPlugin(MessagePluginInterface):
yesterday_end
)
# 消息少于50条跳过总结
if message_count < 100:
self.LOG.info(f"{group_id} 昨天只有 {message_count} 条消息,不足50条,跳过总结")
# 消息低于阈值时跳过,阈值可由后台 payload 配置。
if message_count < min_message_count:
self.LOG.info(f"{group_id} 昨天只有 {message_count} 条消息,不足{min_message_count}条,跳过总结")
skipped_groups += 1
continue
self.LOG.info(f"{group_id} 昨天有 {message_count} 条消息,开始获取内容")
@@ -651,6 +712,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
str(image_path),
)
self.LOG.info(f"成功发送群 {group_name} 的昨日总结图片")
sent_groups += 1
else:
# 图片生成失败,发送文本消息
if summary and len(summary.strip()) > 0:
@@ -661,6 +723,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
if summary.strip() == "生成总结时出错":
await self._send_text_with_revoke(group_id, f"❌ [{yesterday.strftime('%Y-%m-%d')}] 聊天总结生成失败,请稍后再试", 5)
self.LOG.warning(f"{group_name} 的昨日总结生成失败,已发送可撤回失败提醒")
failed_groups += 1
else:
await self.bot.send_text_message(group_id, summary)
self._save_daily_summary_record(
@@ -673,18 +736,29 @@ class MessageSummaryPlugin(MessagePluginInterface):
None,
)
self.LOG.info(f"成功发送群 {group_name} 的昨日总结文本")
sent_groups += 1
else:
await self._send_text_with_revoke(group_id, f"❌ [{yesterday.strftime('%Y-%m-%d')}] 聊天总结生成失败,请稍后再试", 5)
self.LOG.warning(f"{group_name} 的昨日总结无有效内容,已发送可撤回失败提醒")
failed_groups += 1
# 避免请求过快
await asyncio.sleep(2)
except Exception as e:
self.LOG.error(f"为群 {group_id} 生成昨日总结失败: {e}", exc_info=True)
failed_groups += 1
continue
self.LOG.info("每日聊天总结任务执行完成")
return {
"total_groups": len(enabled_groups),
"sent_groups": sent_groups,
"failed_groups": failed_groups,
"skipped_groups": skipped_groups,
"min_message_count": min_message_count,
}
except Exception as e:
self.LOG.error(f"每日聊天总结任务执行失败: {e}", exc_info=True)
return {"total_groups": 0, "sent_groups": 0, "failed_groups": 1, "skipped_groups": 0}