diff --git a/nonebot_plugin_marshoai/azure.py b/nonebot_plugin_marshoai/azure.py index f7ebc33..b9ad409 100644 --- a/nonebot_plugin_marshoai/azure.py +++ b/nonebot_plugin_marshoai/azure.py @@ -234,15 +234,28 @@ async def send_markdown(msg: str): 人工智能给出的回答一般不会包含 HTML 嵌入其中,但是包含图片或者 LaTeX 公式、代码块,都很正常。 这个函数会把这些都以图片形式嵌入消息体。 """ + + if not IMG_TAG_PATTERN.search(msg): # 没有图片标签 + await UniMessage(msg).send(reply_to=True) + return + result_msg = UniMessage() code_blank_uuid_map = [ (uuid.uuid4().hex, cbp.group()) for cbp in CODE_BLOCK_PATTERN.finditer(msg) ] + last_tag_index = 0 + # 代码块渲染麻烦,先不处理 for rep, torep in code_blank_uuid_map: msg = msg.replace(torep, rep) + # for to_rep in CODE_SINGLE_PATTERN.finditer(msg): + # code_blank_uuid_map.append((rep := uuid.uuid4().hex, to_rep.group())) + # msg = msg.replace(to_rep.group(), rep) + + print("#####################\n", msg, "\n\n") + # 插入图片 for each_img_tag in IMG_TAG_PATTERN.finditer(msg): img_tag = await get_back_uuidcodeblock( @@ -254,14 +267,28 @@ async def send_markdown(msg: str): result_msg.append( TextMsg( await get_back_uuidcodeblock( - msg[: msg.find(img_tag)], code_blank_uuid_map + msg[last_tag_index : msg.find(img_tag)], code_blank_uuid_map ) ) ) - result_msg.append(ImageMsg(url=image_url, name=image_description + ".png")) + last_tag_index = msg.find(img_tag) + len(img_tag) - result_msg.append(TextMsg("({})".format(image_description))) + if image_ := await get_image_raw_and_type(image_url): + + result_msg.append( + ImageMsg( + raw=image_[0], mimetype=image_[1], name=image_description + ".png" + ) + ) + result_msg.append(TextMsg("({})".format(image_description))) + + else: + result_msg.append(TextMsg(img_tag)) + + result_msg.append( + TextMsg(await get_back_uuidcodeblock(msg[last_tag_index:], code_blank_uuid_map)) + ) await result_msg.send(reply_to=True) diff --git a/nonebot_plugin_marshoai/constants.py b/nonebot_plugin_marshoai/constants.py index 9dac1a5..c401ebc 100644 --- a/nonebot_plugin_marshoai/constants.py +++ b/nonebot_plugin_marshoai/constants.py @@ -37,7 +37,7 @@ https://github.com/LiteyukiStudio/marshoai-melo""" # 正则匹配代码块 CODE_BLOCK_PATTERN = re.compile( - r"```(.*?)```|`(.*?)`", + r"```(.*?)```|`(.*?)`", re.DOTALL ) # 正则匹配完整图片标签字段 IMG_TAG_PATTERN = re.compile(r"!\[[^\]]*\]\([^()]*\)") @@ -47,5 +47,5 @@ IMG_TAG_PATTERN = re.compile(r"!\[[^\]]*\]\([^()]*\)") # INTAG_TEXT_PATTERN = re.compile(r'!\[([^\]]*)\]') # 正则匹配 LaTeX 公式内容 LATEX_PATTERN = re.compile( - r"\\begin\{equation\}(.*?)\\\end\{equation\}|(? Optional[tuple[bytes, str]]: + """ + 获取图片的二进制数据 + + 参数: + url: str 图片链接 + timeout: int 超时时间 秒 + + return: + tuple[bytes, str]: 图片二进制数据, 图片MIME格式 + + """ async with httpx.AsyncClient() as client: - response = await client.get(url, headers=headers) + response = await client.get(url, headers=chromium_headers, timeout=timeout) if response.status_code == 200: # 获取图片数据 - image_data = response.content content_type = response.headers.get("Content-Type") if not content_type: content_type = mimetypes.guess_type(url)[0] # image_format = content_type.split("/")[1] if content_type else "jpeg" - base64_image = base64.b64encode(image_data).decode("utf-8") - data_url = f"data:{content_type};base64,{base64_image}" - return data_url + return response.content, str(content_type) else: return None +async def get_image_b64(url: str, timeout: int = 10) -> Optional[str]: + """ + 获取图片的base64编码 + + 参数: + url: 图片链接 + timeout: 超时时间 秒 + + return: 图片base64编码 + """ + + if data_type := await get_image_raw_and_type(url, timeout): + # image_format = content_type.split("/")[1] if content_type else "jpeg" + base64_image = base64.b64encode(data_type[0]).decode("utf-8") + data_url = "data:{};base64,{}".format(data_type[1], base64_image) + return data_url + else: + return None + + async def make_chat( - client: ChatCompletionsClient, msg: list, model_name: str, tools: list = None + client: ChatCompletionsClient, + msg: list, + model_name: str, + tools: Optional[list] = None, ): """调用ai获取回复