From 463b1209235ceef8d47978340fcf51e3459df68e Mon Sep 17 00:00:00 2001 From: douxt Date: Tue, 28 Jul 2026 23:57:00 +0800 Subject: [PATCH] feat(platform): pass original image URL to Image component in 6 adapters (#2362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve the platform CDN URL in Image.url alongside base64 data, enabling plugins to use ContentElement.from_image_url() for direct vision API access without redundant local download. - aiocqhttp: use msg_data["data"]["url"] and msg.data["url"] - discord: use attachment.url - telegram: use file.file_path - slack: use pic_url - wecom: use picurl - qqofficial: use pic_url Satori adapter already follows this pattern (satori.py:168). The change is purely additive — base64 is preserved for backward compatibility, and get_bytes() priority (url → base64 → path) ensures plugins can choose the optimal path. Closes #2355 Co-authored-by: douxt <8429023+douxt@users.noreply.github.com> Co-authored-by: Claude --- src/langbot/pkg/platform/sources/aiocqhttp.py | 10 ++++++++-- src/langbot/pkg/platform/sources/discord.py | 4 +++- src/langbot/pkg/platform/sources/qqofficial.py | 2 +- src/langbot/pkg/platform/sources/slack.py | 2 +- src/langbot/pkg/platform/sources/telegram.py | 3 ++- src/langbot/pkg/platform/sources/wecom.py | 4 +++- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/langbot/pkg/platform/sources/aiocqhttp.py b/src/langbot/pkg/platform/sources/aiocqhttp.py index 4b994c2be..d3b5fc589 100644 --- a/src/langbot/pkg/platform/sources/aiocqhttp.py +++ b/src/langbot/pkg/platform/sources/aiocqhttp.py @@ -240,7 +240,11 @@ class AiocqhttpMessageConverter(abstract_platform_adapter.AbstractMessageConvert async def process_message_data(msg_data, reply_list): if msg_data['type'] == 'image': image_base64, image_format = await image.qq_image_url_to_base64(msg_data['data']['url']) - reply_list.append(platform_message.Image(base64=f'data:image/{image_format};base64,{image_base64}')) + reply_list.append( + platform_message.Image( + url=msg_data['data']['url'], base64=f'data:image/{image_format};base64,{image_base64}' + ) + ) elif msg_data['type'] == 'text': reply_list.append(platform_message.Plain(text=msg_data['data']['text'])) @@ -285,7 +289,9 @@ class AiocqhttpMessageConverter(abstract_platform_adapter.AbstractMessageConvert image_msg = platform_message.Face(face_id=face_id, face_name=face_name) else: image_base64, image_format = await image.qq_image_url_to_base64(msg.data['url']) - image_msg = platform_message.Image(base64=f'data:image/{image_format};base64,{image_base64}') + image_msg = platform_message.Image( + url=msg.data['url'], base64=f'data:image/{image_format};base64,{image_base64}' + ) yiri_msg_list.append(image_msg) elif msg.type == 'forward': # 暂时不太合理 diff --git a/src/langbot/pkg/platform/sources/discord.py b/src/langbot/pkg/platform/sources/discord.py index fae65f6a0..edffc6e2a 100644 --- a/src/langbot/pkg/platform/sources/discord.py +++ b/src/langbot/pkg/platform/sources/discord.py @@ -783,7 +783,9 @@ class DiscordMessageConverter(abstract_platform_adapter.AbstractMessageConverter image_data = await response.read() image_base64 = base64.b64encode(image_data).decode('utf-8') image_format = response.headers['Content-Type'] - element_list.append(platform_message.Image(base64=f'data:{image_format};base64,{image_base64}')) + element_list.append( + platform_message.Image(url=attachment.url, base64=f'data:{image_format};base64,{image_base64}') + ) return platform_message.MessageChain(element_list) diff --git a/src/langbot/pkg/platform/sources/qqofficial.py b/src/langbot/pkg/platform/sources/qqofficial.py index 35fd81f76..a9fbb4000 100644 --- a/src/langbot/pkg/platform/sources/qqofficial.py +++ b/src/langbot/pkg/platform/sources/qqofficial.py @@ -102,7 +102,7 @@ class QQOfficialMessageConverter(abstract_platform_adapter.AbstractMessageConver yiri_msg_list.append(platform_message.Source(id=message_id, time=datetime.datetime.now())) if pic_url is not None: base64_url = await image.get_qq_official_image_base64(pic_url=pic_url, content_type=content_type) - yiri_msg_list.append(platform_message.Image(base64=base64_url)) + yiri_msg_list.append(platform_message.Image(url=pic_url, base64=base64_url)) yiri_msg_list.append(platform_message.Plain(text=message)) chain = platform_message.MessageChain(yiri_msg_list) diff --git a/src/langbot/pkg/platform/sources/slack.py b/src/langbot/pkg/platform/sources/slack.py index e577e3bdd..df18a0765 100644 --- a/src/langbot/pkg/platform/sources/slack.py +++ b/src/langbot/pkg/platform/sources/slack.py @@ -47,7 +47,7 @@ class SlackMessageConverter(abstract_platform_adapter.AbstractMessageConverter): yiri_msg_list.append(platform_message.Source(id=message_id, time=datetime.datetime.now())) if pic_url is not None: base64_url = await image.get_slack_image_to_base64(pic_url=pic_url, bot_token=bot.bot_token) - yiri_msg_list.append(platform_message.Image(base64=base64_url)) + yiri_msg_list.append(platform_message.Image(url=pic_url, base64=base64_url)) yiri_msg_list.append(platform_message.Plain(text=message)) chain = platform_message.MessageChain(yiri_msg_list) diff --git a/src/langbot/pkg/platform/sources/telegram.py b/src/langbot/pkg/platform/sources/telegram.py index e7ad626bb..49157a9d1 100644 --- a/src/langbot/pkg/platform/sources/telegram.py +++ b/src/langbot/pkg/platform/sources/telegram.py @@ -157,7 +157,8 @@ class TelegramMessageConverter(abstract_platform_adapter.AbstractMessageConverte message_components.append( platform_message.Image( - base64=f'data:{file_format};base64,{base64.b64encode(file_bytes).decode("utf-8")}' + url=file.file_path, + base64=f'data:{file_format};base64,{base64.b64encode(file_bytes).decode("utf-8")}', ) ) diff --git a/src/langbot/pkg/platform/sources/wecom.py b/src/langbot/pkg/platform/sources/wecom.py index 27c77ad37..5df4d2d49 100644 --- a/src/langbot/pkg/platform/sources/wecom.py +++ b/src/langbot/pkg/platform/sources/wecom.py @@ -133,7 +133,9 @@ class WecomMessageConverter(abstract_platform_adapter.AbstractMessageConverter): yiri_msg_list = [] yiri_msg_list.append(platform_message.Source(id=message_id, time=datetime.datetime.now())) image_base64, image_format = await image.get_wecom_image_base64(pic_url=picurl) - yiri_msg_list.append(platform_message.Image(base64=f'data:image/{image_format};base64,{image_base64}')) + yiri_msg_list.append( + platform_message.Image(url=picurl, base64=f'data:image/{image_format};base64,{image_base64}') + ) chain = platform_message.MessageChain(yiri_msg_list) return chain