添加提取思维链,处理消息对象的函数,改善兼容性

This commit is contained in:
Asankilp 2025-01-31 18:23:41 +08:00
parent 887bf808a7
commit 42bed6aeca
2 changed files with 58 additions and 20 deletions

View File

@ -6,7 +6,6 @@ import openai
from arclet.alconna import Alconna, AllParam, Args from arclet.alconna import Alconna, AllParam, Args
from azure.ai.inference.models import ( from azure.ai.inference.models import (
AssistantMessage, AssistantMessage,
ChatCompletionsToolCall,
CompletionsFinishReason, CompletionsFinishReason,
ImageContentItem, ImageContentItem,
ImageUrl, ImageUrl,
@ -22,7 +21,6 @@ from nonebot.permission import SUPERUSER
from nonebot.rule import Rule, to_me from nonebot.rule import Rule, to_me
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot_plugin_alconna import MsgTarget, UniMessage, UniMsg, on_alconna from nonebot_plugin_alconna import MsgTarget, UniMessage, UniMsg, on_alconna
from openai import AsyncOpenAI
from .hooks import * from .hooks import *
from .instances import * from .instances import *
@ -287,7 +285,7 @@ async def marsho(
tools_lists = tools.tools_list + list( tools_lists = tools.tools_list + list(
map(lambda v: v.data(), get_function_calls().values()) map(lambda v: v.data(), get_function_calls().values())
) )
logger.debug(f"正在获取回答,模型:{model_name}") logger.info(f"正在获取回答,模型:{model_name}")
response = await make_chat_openai( response = await make_chat_openai(
client=client, client=client,
model_name=model_name, model_name=model_name,
@ -306,25 +304,26 @@ async def marsho(
context.append( context.append(
UserMessage(content=usermsg).as_dict(), target.id, target.private # type: ignore UserMessage(content=usermsg).as_dict(), target.id, target.private # type: ignore
) )
choice_msg_dict = choice.message.to_dict()
if "reasoning_content" in choice_msg_dict:
if config.marshoai_send_thinking:
await UniMessage(
"思维链:\n" + choice_msg_dict["reasoning_content"]
).send()
del choice_msg_dict["reasoning_content"]
context.append(choice_msg_dict, target.id, target.private)
##### DeepSeek-R1 兼容部分 #####
choice_msg_content, choice_msg_thinking, choice_msg_after = (
extract_content_and_think(choice.message)
)
if choice_msg_thinking and config.marshoai_send_thinking:
await UniMessage("思维链:\n" + choice_msg_thinking).send()
##### 兼容部分结束 #####
context.append(choice_msg_after.to_dict(), target.id, target.private)
if [target.id, target.private] not in target_list: if [target.id, target.private] not in target_list:
target_list.append([target.id, target.private]) target_list.append([target.id, target.private])
# 对话成功发送消息 # 对话成功发送消息
if config.marshoai_enable_richtext_parse: if config.marshoai_enable_richtext_parse:
await (await parse_richtext(str(choice.message.content))).send( await (await parse_richtext(str(choice_msg_content))).send(
reply_to=True reply_to=True
) )
else: else:
await UniMessage(str(choice.message.content)).send(reply_to=True) await UniMessage(str(choice_msg_content)).send(reply_to=True)
elif choice.finish_reason == CompletionsFinishReason.CONTENT_FILTERED: elif choice.finish_reason == CompletionsFinishReason.CONTENT_FILTERED:
# 对话失败,消息过滤 # 对话失败,消息过滤
@ -467,9 +466,8 @@ with contextlib.suppress(ImportError): # 优化先不做()
) )
choice = response.choices[0] choice = response.choices[0]
if choice.finish_reason == CompletionsFinishReason.STOPPED: if choice.finish_reason == CompletionsFinishReason.STOPPED:
await UniMessage(" " + str(choice.message.content)).send( content = extract_content_and_think(choice.message)[0]
at_sender=True await UniMessage(" " + str(content)).send(at_sender=True)
)
except Exception as e: except Exception as e:
await UniMessage(str(e) + suggest_solution(str(e))).send() await UniMessage(str(e) + suggest_solution(str(e))).send()
traceback.print_exc() traceback.print_exc()

View File

@ -1,6 +1,7 @@
import base64 import base64
import json import json
import mimetypes import mimetypes
import re
import uuid import uuid
from typing import Any, Optional from typing import Any, Optional
@ -15,6 +16,7 @@ from nonebot_plugin_alconna import Image as ImageMsg
from nonebot_plugin_alconna import Text as TextMsg from nonebot_plugin_alconna import Text as TextMsg
from nonebot_plugin_alconna import UniMessage from nonebot_plugin_alconna import UniMessage
from openai import AsyncOpenAI, NotGiven from openai import AsyncOpenAI, NotGiven
from openai.types.chat import ChatCompletionMessage
from zhDateTime import DateTime from zhDateTime import DateTime
from .config import config from .config import config
@ -34,7 +36,7 @@ if config.marshoai_enable_time_prompt:
# noinspection LongLine # noinspection LongLine
_chromium_headers = { _browser_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
} }
""" """
@ -47,7 +49,7 @@ _praises_init_data = {
"like": [ "like": [
{ {
"name": "Asankilp", "name": "Asankilp",
"advantages": "赋予了Marsho猫娘人格使用手机,在vim与vscode的加持下为Marsho写了许多代码使Marsho更加可爱", "advantages": "赋予了Marsho猫娘人格在vim与vscode的加持下为Marsho写了许多代码使Marsho更加可爱",
} }
] ]
} }
@ -71,7 +73,7 @@ async def get_image_raw_and_type(
""" """
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get(url, headers=_chromium_headers, timeout=timeout) response = await client.get(url, headers=_browser_headers, timeout=timeout)
if response.status_code == 200: if response.status_code == 200:
# 获取图片数据 # 获取图片数据
content_type = response.headers.get("Content-Type") content_type = response.headers.get("Content-Type")
@ -180,7 +182,7 @@ async def refresh_praises_json():
praises_json = data praises_json = data
def build_praises(): def build_praises() -> str:
praises = get_praises() praises = get_praises()
result = ["你喜欢以下几个人物,他们有各自的优点:"] result = ["你喜欢以下几个人物,他们有各自的优点:"]
for item in praises["like"]: for item in praises["like"]:
@ -461,3 +463,41 @@ if config.marshoai_enable_richtext_parse:
""" """
Mulan PSL v2 协议授权部分结束 Mulan PSL v2 协议授权部分结束
""" """
def extract_content_and_think(
message: ChatCompletionMessage,
) -> tuple[str, str | None, ChatCompletionMessage]:
"""
处理 API 返回的消息对象提取其中的内容和思维链并返回处理后的消息思维链消息对象
Args:
message (ChatCompletionMessage): API 返回的消息对象
Returns:
- content (str): 提取出的消息内容
- thinking (str | None): 提取出的思维链如果没有则为 None
- message (ChatCompletionMessage): 移除了思维链的消息对象
本函数参考自 [nonebot-plugin-deepseek](https://github.com/KomoriDev/nonebot-plugin-deepseek)
"""
try:
thinking = message.reasoning_content # type: ignore
except AttributeError:
thinking = None
if thinking:
delattr(message, "reasoning_content")
else:
think_blocks = re.findall(
r"<think>(.*?)</think>", message.content or "", flags=re.DOTALL
)
thinking = "\n".join([block.strip() for block in think_blocks if block.strip()])
content = re.sub(
r"<think>.*?</think>", "", message.content or "", flags=re.DOTALL
).strip()
message.content = content
return content, thinking, message