Compare commits

..
25 Commits
Author SHA1 Message Date
Wbucket d1a011f206 dev: log 2026-11-08 01:06:50 +08:00
Wbucket bc18689f71 dev:调用和发送 2026-11-08 00:51:30 +08:00
Wbucket 1d2412bafd dev 2026-11-08 00:19:04 +08:00
Wbucket 839ba8cd0c dev 2026-11-08 00:05:19 +08:00
Wbucket 03031ca7e3 dev 2026-11-07 23:22:11 +08:00
Wbucket fae39bbb01 dev 2026-11-07 23:11:43 +08:00
Wbucket c49635faba dev:fxxking 'not' decide 2026-11-06 23:06:42 +08:00
Wbucket 5e3643a237 dev 2026-11-06 23:04:10 +08:00
Wbucket 8ce5aa8847 fix: pointer 2026-11-06 22:41:33 +08:00
Wbucket a7c4925106 fix: no async 2026-11-06 22:10:46 +08:00
Wbucket 7610960cb6 fix: no yield 2026-11-06 22:08:54 +08:00
Wbucket 3823b83d9e dev 2026-11-06 22:06:00 +08:00
Wbucket 498761ba03 dev 2026-11-06 22:00:27 +08:00
Wbucket 140dc6244e dev 2026-11-06 21:57:51 +08:00
Wbucket c6fff5a539 dev:fix 2026-11-06 21:54:24 +08:00
Wbucket fe7864853b fix 2026-11-06 21:10:18 +08:00
Wbucket 33dc032d82 fix: 不正确的事件 2026-11-06 21:06:51 +08:00
Wbucket dc8753b87c style: context 2026-11-06 15:30:23 +08:00
Wbucket 6f79cae3a3 dev:style 项目结构和分类 2026-11-05 22:54:18 +08:00
Wbucket 101d276d9a dev-log and 判别式 2026-11-05 22:10:10 +08:00
Wbucket f08a36f833 dev 2026-11-05 22:05:46 +08:00
Wbucket 0a17dc8a43 dev logger 2026-11-05 21:51:44 +08:00
Wbucket 4512c4a4cc dev 相对导入 2026-11-05 21:46:22 +08:00
Wbucket d4fd53ed4b dev 2026-11-05 21:40:00 +08:00
Wbucket a892390300 stlyle:context 2026-11-05 16:11:21 +08:00
3 changed files with 179 additions and 14 deletions
+24 -14
View File
@@ -1,39 +1,49 @@
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 astrbot.core.agent.message import TextPart
@register("helloworld", "YourName", "一个简单的 Hello World 插件", "1.0.0") from .service.timer import TimerService
@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 的描述,将会被解析方便用户了解插件内容。建议填写。
# logger.info("系统提示词:"+req.system_prompt)
req.extra_user_content_parts.append(TextPart( req.extra_user_content_parts.append(TextPart(
text=( text=(
"-----wt使用----"
"在回复内容中加入<wt>n</wt>模板输入想要等待的时间,n=等待秒数\n" "在回复内容中加入<wt>n</wt>模板输入想要等待的时间,n=等待秒数\n"
"最短2s最长30min(1800s),不添加则正常回复(只有对方回复你才会被唤醒)\n" "最短10s最长30min(1800s),不添加则正常回复(只有对方回复你才会被唤醒)\n"
"例如'<wt>5</wt>'-->等待5秒后再次唤醒.\n" "例如'<wt>15</wt>'-->等待15秒后再次唤醒.\n"
"使用场景:希望对方在多久之后能回你,或者希望这个话题能在短期内继续而不是因为对方的不回复就夭折\n" "使用场景:希望对方在多久之后能回你,或者希望这个话题能在短期内继续而不是因为对方的不回复就夭折\n"
"例如如下场景:\n" "例如如下场景:\n"
"assistant:'你觉得咸粽子好吃韩式甜粽子好吃?<wt>40</wt>'\n" "--\n"
"assistant:'你觉得咸粽子好吃还是甜粽子好吃?<wt>40</wt>'\n"
"(系统时间:四十秒后,系统定时唤醒)\n" "(系统时间:四十秒后,系统定时唤醒)\n"
"user:'<wt>无回应</wt>'\n" "user:'<wt>40s过去了,对方无回应</wt>'\n"
"assistant:'你怎么不理我<wt>40</wt>'\n" "assistant:'你怎么不理我<wt>40</wt>'\n"
"(系统时间:二十秒后,用户回复,定时任务取消)\n" "(系统时间:二十秒后,用户回复,定时任务取消)\n"
"user:'抱歉啊刚看到,我觉得咸的好吃awa'" "user:'抱歉啊刚看到,我觉得咸的好吃awa'\n"
"每主动发出消息建议带上wt标签,标签必须闭合且只包裹你要等待的秒数。\n"
"如果话题完结了,不想再无意义被唤醒,或者回复完毕别人的问题还没被追问的时候则不必再加。自己看着决定即可。\n"
"-------"
) )
)) ))
# @filter.event_message_type(filter.EventMessageType.PRIVATE_MESSAGE)
# async def awa(self,event:AstrMessageEvent):
# yield event.plain_result(event.get_message_str())
@filter.on_decorating_result()
async def pattern_extract(self,event:AstrMessageEvent):
self.Timer.parse(event)
async def terminate(self): async def terminate(self):
"""可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。"""
+99
View File
@@ -0,0 +1,99 @@
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
import json
class TimerService:
def __init__(self,star:Star) -> None:
self.star = star
self.tasks:list[TimerTask] = []
pass
# 解析模板并进行定时
def parse(self,event:AstrMessageEvent):
res = event.get_result()
if not res:
logger.warning("[wait_msg]:解析失败:没拿到消息链")
return
Second:int|None = None
logger.info("[wait_msg]:开始解析模板")
for index,i in enumerate(res.chain) :
logger.info(f"获得消息链类型:{i.type}")
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):
logger.info(f"进行一个{Sec}秒的对{event.get_sender_id()}({event.get_sender_name()})的等")
task = asyncio.create_task(self.timer_task(event,Sec))
self.tasks.append(TimerTask(event=event,task=task))
# 等待,唤醒任务本体
async def timer_task(self,event:AstrMessageEvent,second:int):
await asyncio.sleep(second)
await self.response_time(event)
# 调用llm
async def response_time(self,event:AstrMessageEvent):
try:
umo = event.unified_msg_origin
conv_mnger = self.star.context.conversation_manager
provider =await self.star.context.get_current_chat_provider_id(umo)
conv_id = await conv_mnger.get_curr_conversation_id(umo)
if conv_id is None:
logger.error(f"conversation_id获取失败!!umo:{umo}")
return False
conversation = await conv_mnger.get_conversation(umo,conv_id)
if conversation is None :
conversation = []
try:
history_list = json.loads(conversation.history)
except:
logger.warning("上下文获取失败,使用空上下文喵")
history_list = []
except:
logger.error("消息管理失败!")
return False
# logger.debug(f"获取上下文:{conversation}")
try:
req = await self.star.context.llm_generate(
chat_provider_id=provider,
prompt="<你等待的时间内对方没有回复>",
contexts=history_list,
tools=None
)
except:
logger.error("llm返回失败了喵...QAQ")
return
logger.debug(f"llm结果:{req.completion_text }")
# 保存至历史消息
#发送至平台
await event.send(MessageChain().message(req.completion_text))
class TimerTask:
def __init__(self,event:AstrMessageEvent,task:asyncio.Task) -> None:
self.event = event
self.task = task
pass
+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.debug(f"过滤后消息:{o_str}")
return {
"content":o_str,
"second":timerSec
}