This commit is contained in:
Wbucket
2026-11-06 23:24:13 +08:00
parent 258d0c3337
commit 127772756d
3 changed files with 137 additions and 9 deletions
+34 -8
View File
@@ -1,25 +1,51 @@
from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult
from astrbot.api.star import Context, Star, register from astrbot.api.star import Context, Star, register
from astrbot.api import logger from astrbot.api import logger
from astrbot.api.provider import ProviderRequest from astrbot.api.provider import (ProviderRequest,LLMResponse )
from astrbot.core.agent.message import TextPart
from .service.timer import TimerService
@register("helloworld", "YourName", "一个简单的 Hello World 插件", "1.0.0")
@register("wait_msg", "Wbucket", "一个简单的 llm等待回复插件", "0.0.1")
class MyPlugin(Star): class MyPlugin(Star):
def __init__(self, context: Context): def __init__(self, context: Context):
super().__init__(context) super().__init__(context)
self.Timer = TimerService(self)
async def initialize(self): async def initialize(self):
"""可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。"""
# 注册指令的装饰器。指令名为 helloworld。注册成功后,发送 `/helloworld` 就会触发这个指令,并回复 `你好, {user_name}!` # 注册指令的装饰器
@filter.on_llm_request() @filter.on_llm_request()
async def helloworld(self, event: AstrMessageEvent,req : ProviderRequest): async def content_inject(self, event: AstrMessageEvent,req : ProviderRequest):
"""这是一个 hello world 指令""" # 这是 handler 的描述,将会被解析方便用户了解插件内容。建议填写。 """这是一个 hello world 指令""" # 这是 handler 的描述,将会被解析方便用户了解插件内容。建议填写。
logger.info("系统提示词:",req.system_prompt) # logger.info("系统提示词:"+req.system_prompt)
req.extra_user_content_parts.append(TextPart(
text=(
"-----wt使用----"
"在回复内容中加入<wt>n</wt>模板输入想要等待的时间,n=等待秒数\n"
"最短10s最长30min(1800s),不添加则正常回复(只有对方回复你才会被唤醒)\n"
"例如'<wt>15</wt>'-->等待15秒后再次唤醒.\n"
"使用场景:希望对方在多久之后能回你,或者希望这个话题能在短期内继续而不是因为对方的不回复就夭折\n"
"例如如下场景:\n"
"--\n"
"assistant:'你觉得咸粽子好吃还是甜粽子好吃?<wt>40</wt>'\n"
"(系统时间:四十秒后,系统定时唤醒)\n"
"user:'<wt>40s过去了,对方无回应</wt>'\n"
"assistant:'你怎么不理我<wt>40</wt>'\n"
"(系统时间:二十秒后,用户回复,定时任务取消)\n"
"user:'抱歉啊刚看到,我觉得咸的好吃awa'\n"
"每主动发出消息建议带上wt标签,标签必须闭合且只包裹你要等待的秒数。\n"
"如果话题完结了,不想再无意义被唤醒,或者回复完毕别人的问题还没被追问的时候则不必再加。自己看着决定即可。\n"
"-------"
)
))
@filter.event_message_type(filter.EventMessageType.PRIVATE_MESSAGE) @filter.on_decorating_result()
async def awa(self,event:AstrMessageEvent): async def pattern_extract(self,event:AstrMessageEvent):
yield event.plain_result(event.get_message_str()) self.Timer.parse(event)
async def terminate(self): async def terminate(self):
"""可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。"""
+46
View File
@@ -0,0 +1,46 @@
from astrbot.api.event import AstrMessageEvent
from astrbot.api.provider import LLMResponse
from astrbot.api import logger
from astrbot.core.message.message_event_result import MessageChain,Plain
from ..tool.pattern import Pattern
from astrbot.api.star import Star
import asyncio
class TimerService:
def __init__(self,star:Star) -> None:
self.star = star
pass
# 解析模板并进行定时
def parse(self,event:AstrMessageEvent):
res = event.get_result()
if not res:
logger.info("[wait_msg]:解析失败:没拿到消息链")
return
Second:int|None = None
logger.info("[wait_msg]:开始解析模板")
for index,i in enumerate(res.chain) :
logger.info(f"获得消息链类型:{i.type}内容:{i}")
if not isinstance(i,Plain) or not i.type == "Plain":
continue
dump = Pattern(i.text)
i.text = dump.string
Second = dump.count
# 改变信息
res.chain[index] = i
event.set_result(res)
if not Second is None:
self.timer(event,Second)
return
# 定时:
def timer(self,event:AstrMessageEvent,Sec:int):
asyncio.create_task(self.timer_task())
async def timer_task(self):
await asyncio.sleep(1)
logger.warning("awa现在过去一秒了哦")
+56
View File
@@ -0,0 +1,56 @@
import re
from astrbot.api import logger
# 输入内容,获取过滤后的字符串与定时秒数
class Pattern:
_pattern = r'<wt>((?!wt).)*</wt>'
_MAX_SEC = 1800
_MIN_SEC = 10
# 定义最大与最小的范围,固定输入的规范
def __init__(self,o_str:str) -> None:
logger.debug(f"模板消息:{o_str}")
res = self.extract(o_str)
self.count:int|None = res['second']
self.string:str = res["content"]
def sec_range(self,i)->int:
if i > Pattern._MAX_SEC:
return Pattern._MAX_SEC
if i < Pattern._MIN_SEC :
return Pattern._MIN_SEC
return i
def load(self,pattern_str:str)->int|None:
content = pattern_str.strip().removeprefix("<wt>").removesuffix("</wt>").strip()
try:
num = int(content)
return self.sec_range(num)
except:
logger.warning ("模板内容错误:{}".format(content))
return None
def extract(self,o_str:str):
# 多次匹配防止重复模板
timerSec :None|int = None
res=re.finditer(Pattern._pattern,o_str)
for i in res :
# 对结果和源字符串处理
o_str = o_str.replace(i.group(),"",1)
num = self.load(i.group())
logger.info("获得模板:{0}".format(i.group()))
if num and not timerSec:
timerSec = num
#消除不完整/非法模板
o_str= o_str.replace("<wt>","")
o_str=o_str.replace("</wt>","")
logger.info(f"过滤后消息:{o_str}")
return {
"content":o_str,
"second":timerSec
}