mirror of
https://github.com/FuQuan233/nonebot-plugin-llmchat.git
synced 2025-09-04 10:20:45 +00:00
🐛 ♻️ use defaultdict and remove think matched content
This commit is contained in:
parent
bb9ae962e6
commit
812545f99d
1 changed files with 26 additions and 47 deletions
|
@ -1,5 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import deque
|
from collections import defaultdict, deque
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
@ -48,7 +48,7 @@ __plugin_meta__ = PluginMetadata(
|
||||||
supported_adapters={"~onebot.v11"},
|
supported_adapters={"~onebot.v11"},
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginConfig = get_plugin_config(Config).llmchat
|
plugin_config = get_plugin_config(Config).llmchat
|
||||||
driver = get_driver()
|
driver = get_driver()
|
||||||
tasks: set["asyncio.Task"] = set()
|
tasks: set["asyncio.Task"] = set()
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ def pop_reasoning_content(
|
||||||
think_content: Optional[str] = None
|
think_content: Optional[str] = None
|
||||||
# 匹配 <think> 标签和其中的内容
|
# 匹配 <think> 标签和其中的内容
|
||||||
if matched := re.match(r"<think>(.*?)</think>", content, flags=re.DOTALL):
|
if matched := re.match(r"<think>(.*?)</think>", content, flags=re.DOTALL):
|
||||||
think_content = matched.group(0)
|
think_content = matched.group(1)
|
||||||
|
|
||||||
# 如果找到了 <think> 标签内容,返回过滤后的文本和标签内的内容,否则只返回过滤后的文本和None
|
# 如果找到了 <think> 标签内容,返回过滤后的文本和标签内的内容,否则只返回过滤后的文本和None
|
||||||
if think_content:
|
if think_content:
|
||||||
|
@ -75,26 +75,26 @@ def pop_reasoning_content(
|
||||||
# 初始化群组状态
|
# 初始化群组状态
|
||||||
class GroupState:
|
class GroupState:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.preset_name = pluginConfig.default_preset
|
self.preset_name = plugin_config.default_preset
|
||||||
self.history = deque(maxlen=pluginConfig.history_size)
|
self.history = deque(maxlen=plugin_config.history_size)
|
||||||
self.queue = asyncio.Queue()
|
self.queue = asyncio.Queue()
|
||||||
self.processing = False
|
self.processing = False
|
||||||
self.last_active = time.time()
|
self.last_active = time.time()
|
||||||
self.past_events = deque(maxlen=pluginConfig.past_events_size)
|
self.past_events = deque(maxlen=plugin_config.past_events_size)
|
||||||
self.group_prompt: Optional[str] = None
|
self.group_prompt: Optional[str] = None
|
||||||
self.output_reasoning_content = False
|
self.output_reasoning_content = False
|
||||||
|
|
||||||
|
|
||||||
group_states: dict[int, GroupState] = {}
|
group_states: dict[int, GroupState] = defaultdict(GroupState)
|
||||||
|
|
||||||
|
|
||||||
# 获取当前预设配置
|
# 获取当前预设配置
|
||||||
def get_preset(group_id: int) -> PresetConfig:
|
def get_preset(group_id: int) -> PresetConfig:
|
||||||
state = group_states[group_id]
|
state = group_states[group_id]
|
||||||
for preset in pluginConfig.api_presets:
|
for preset in plugin_config.api_presets:
|
||||||
if preset.name == state.preset_name:
|
if preset.name == state.preset_name:
|
||||||
return preset
|
return preset
|
||||||
return pluginConfig.api_presets[0] # 默认返回第一个预设
|
return plugin_config.api_presets[0] # 默认返回第一个预设
|
||||||
|
|
||||||
|
|
||||||
# 消息格式转换
|
# 消息格式转换
|
||||||
|
@ -127,16 +127,10 @@ def format_message(event: GroupMessageEvent) -> str:
|
||||||
return json.dumps(message, ensure_ascii=False)
|
return json.dumps(message, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
async def isTriggered(event: GroupMessageEvent) -> bool:
|
async def is_triggered(event: GroupMessageEvent) -> bool:
|
||||||
"""扩展后的消息处理规则"""
|
"""扩展后的消息处理规则"""
|
||||||
|
|
||||||
group_id = event.group_id
|
state = group_states[event.group_id]
|
||||||
|
|
||||||
if group_id not in group_states:
|
|
||||||
logger.info(f"初始化群组状态,群号:{group_id}")
|
|
||||||
group_states[group_id] = GroupState()
|
|
||||||
|
|
||||||
state = group_states[group_id]
|
|
||||||
|
|
||||||
if state.preset_name == "off":
|
if state.preset_name == "off":
|
||||||
return False
|
return False
|
||||||
|
@ -148,7 +142,7 @@ async def isTriggered(event: GroupMessageEvent) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 随机触发条件
|
# 随机触发条件
|
||||||
if random.random() < pluginConfig.random_trigger_prob:
|
if random.random() < plugin_config.random_trigger_prob:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -156,7 +150,7 @@ async def isTriggered(event: GroupMessageEvent) -> bool:
|
||||||
|
|
||||||
# 消息处理器
|
# 消息处理器
|
||||||
handler = on_message(
|
handler = on_message(
|
||||||
rule=Rule(isTriggered),
|
rule=Rule(is_triggered),
|
||||||
priority=10,
|
priority=10,
|
||||||
block=False,
|
block=False,
|
||||||
)
|
)
|
||||||
|
@ -169,9 +163,6 @@ async def handle_message(event: GroupMessageEvent):
|
||||||
f"收到群聊消息 群号:{group_id} 用户:{event.user_id} 内容:{event.get_plaintext()}"
|
f"收到群聊消息 群号:{group_id} 用户:{event.user_id} 内容:{event.get_plaintext()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if group_id not in group_states:
|
|
||||||
group_states[group_id] = GroupState()
|
|
||||||
|
|
||||||
state = group_states[group_id]
|
state = group_states[group_id]
|
||||||
|
|
||||||
await state.queue.put(event)
|
await state.queue.put(event)
|
||||||
|
@ -190,7 +181,7 @@ async def process_messages(group_id: int):
|
||||||
client = AsyncOpenAI(
|
client = AsyncOpenAI(
|
||||||
base_url=preset.api_base,
|
base_url=preset.api_base,
|
||||||
api_key=preset.api_key,
|
api_key=preset.api_key,
|
||||||
timeout=pluginConfig.request_timeout,
|
timeout=plugin_config.request_timeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -213,14 +204,14 @@ async def process_messages(group_id: int):
|
||||||
- 如果有多条消息,你应该优先回复提到你的,一段时间之前的就不要回复了,也可以直接选择不回复。
|
- 如果有多条消息,你应该优先回复提到你的,一段时间之前的就不要回复了,也可以直接选择不回复。
|
||||||
- 如果你需要思考的话,你应该思考尽量少,以节省时间。
|
- 如果你需要思考的话,你应该思考尽量少,以节省时间。
|
||||||
下面是关于你性格的设定,如果设定中提到让你扮演某个人,或者设定中有提到名字,则优先使用设定中的名字。
|
下面是关于你性格的设定,如果设定中提到让你扮演某个人,或者设定中有提到名字,则优先使用设定中的名字。
|
||||||
{state.group_prompt or pluginConfig.default_prompt}
|
{state.group_prompt or plugin_config.default_prompt}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
messages: Iterable[ChatCompletionMessageParam] = [
|
messages: Iterable[ChatCompletionMessageParam] = [
|
||||||
{"role": "system", "content": systemPrompt}
|
{"role": "system", "content": systemPrompt}
|
||||||
]
|
]
|
||||||
|
|
||||||
messages += list(state.history)[-pluginConfig.history_size :]
|
messages += list(state.history)[-plugin_config.history_size :]
|
||||||
|
|
||||||
# 没有未处理的消息说明已经被处理了,跳过
|
# 没有未处理的消息说明已经被处理了,跳过
|
||||||
if state.past_events.__len__() < 1:
|
if state.past_events.__len__() < 1:
|
||||||
|
@ -283,7 +274,7 @@ async def process_messages(group_id: int):
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"API请求失败 群号:{group_id} 错误:{e!s}", exc_info=True)
|
logger.opt(exception=e).error(f"API请求失败 群号:{group_id}")
|
||||||
await handler.send(Message(f"服务暂时不可用,请稍后再试\n{e!s}"))
|
await handler.send(Message(f"服务暂时不可用,请稍后再试\n{e!s}"))
|
||||||
finally:
|
finally:
|
||||||
state.queue.task_done()
|
state.queue.task_done()
|
||||||
|
@ -300,14 +291,11 @@ async def handle_preset(event: GroupMessageEvent, args: Message = CommandArg()):
|
||||||
group_id = event.group_id
|
group_id = event.group_id
|
||||||
preset_name = args.extract_plain_text().strip()
|
preset_name = args.extract_plain_text().strip()
|
||||||
|
|
||||||
if group_id not in group_states:
|
|
||||||
group_states[group_id] = GroupState()
|
|
||||||
|
|
||||||
if preset_name == "off":
|
if preset_name == "off":
|
||||||
group_states[group_id].preset_name = preset_name
|
group_states[group_id].preset_name = preset_name
|
||||||
await preset_handler.finish("已关闭llmchat")
|
await preset_handler.finish("已关闭llmchat")
|
||||||
|
|
||||||
available_presets = {p.name for p in pluginConfig.api_presets}
|
available_presets = {p.name for p in plugin_config.api_presets}
|
||||||
if preset_name not in available_presets:
|
if preset_name not in available_presets:
|
||||||
available_presets_str = "\n- ".join(available_presets)
|
available_presets_str = "\n- ".join(available_presets)
|
||||||
await preset_handler.finish(
|
await preset_handler.finish(
|
||||||
|
@ -331,9 +319,6 @@ async def handle_edit_preset(event: GroupMessageEvent, args: Message = CommandAr
|
||||||
group_id = event.group_id
|
group_id = event.group_id
|
||||||
group_prompt = args.extract_plain_text().strip()
|
group_prompt = args.extract_plain_text().strip()
|
||||||
|
|
||||||
if group_id not in group_states:
|
|
||||||
group_states[group_id] = GroupState()
|
|
||||||
|
|
||||||
group_states[group_id].group_prompt = group_prompt
|
group_states[group_id].group_prompt = group_prompt
|
||||||
await edit_preset_handler.finish("修改成功")
|
await edit_preset_handler.finish("修改成功")
|
||||||
|
|
||||||
|
@ -350,9 +335,6 @@ reset_handler = on_command(
|
||||||
async def handle_reset(event: GroupMessageEvent, args: Message = CommandArg()):
|
async def handle_reset(event: GroupMessageEvent, args: Message = CommandArg()):
|
||||||
group_id = event.group_id
|
group_id = event.group_id
|
||||||
|
|
||||||
if group_id not in group_states:
|
|
||||||
group_states[group_id] = GroupState()
|
|
||||||
|
|
||||||
group_states[group_id].past_events.clear()
|
group_states[group_id].past_events.clear()
|
||||||
group_states[group_id].history.clear()
|
group_states[group_id].history.clear()
|
||||||
await reset_handler.finish("记忆已清空")
|
await reset_handler.finish("记忆已清空")
|
||||||
|
@ -369,17 +351,14 @@ think_handler = on_command(
|
||||||
|
|
||||||
@think_handler.handle()
|
@think_handler.handle()
|
||||||
async def handle_think(event: GroupMessageEvent, args: Message = CommandArg()):
|
async def handle_think(event: GroupMessageEvent, args: Message = CommandArg()):
|
||||||
group_id = event.group_id
|
state = group_states[event.group_id]
|
||||||
|
state.output_reasoning_content = not state.output_reasoning_content
|
||||||
|
|
||||||
if group_id not in group_states:
|
await think_handler.finish(
|
||||||
group_states[group_id] = GroupState()
|
f"已{
|
||||||
|
(state.output_reasoning_content and '开启') or '关闭'
|
||||||
if group_states[group_id].output_reasoning_content:
|
}思维输出"
|
||||||
group_states[group_id].output_reasoning_content = False
|
)
|
||||||
await think_handler.finish("已关闭思维输出")
|
|
||||||
else:
|
|
||||||
group_states[group_id].output_reasoning_content = True
|
|
||||||
await think_handler.finish("已开启思维输出")
|
|
||||||
|
|
||||||
|
|
||||||
# region 持久化与定时任务
|
# region 持久化与定时任务
|
||||||
|
@ -421,7 +400,7 @@ async def load_state():
|
||||||
state = GroupState()
|
state = GroupState()
|
||||||
state.preset_name = state_data["preset"]
|
state.preset_name = state_data["preset"]
|
||||||
state.history = deque(
|
state.history = deque(
|
||||||
state_data["history"], maxlen=pluginConfig.history_size
|
state_data["history"], maxlen=plugin_config.history_size
|
||||||
)
|
)
|
||||||
state.last_active = state_data["last_active"]
|
state.last_active = state_data["last_active"]
|
||||||
state.group_prompt = state_data["group_prompt"]
|
state.group_prompt = state_data["group_prompt"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue