fix(slack): transfer message attachments through file APIs

This commit is contained in:
Hyu
2026-10-11 00:17:19 +08:00
parent 49d2af9379
commit 7d4e13509b
7 changed files with 365 additions and 36 deletions
@@ -8,6 +8,7 @@ import pydantic
from langbot.libs.slack_api.api import SlackClient
from langbot.libs.slack_api.slackevent import SlackEvent
from langbot.libs.slack_api.media import send_chain
from langbot.pkg.platform.adapters.slack.api_impl import SlackAPIMixin
from langbot.pkg.platform.adapters.slack.errors import NotSupportedError
from langbot.pkg.platform.adapters.slack.event_converter import SlackEventConverter
@@ -96,8 +97,7 @@ class SlackAdapter(SlackAPIMixin, abstract_platform_adapter.AbstractPlatformAdap
target_id: str,
message: platform_message.MessageChain,
) -> platform_events.MessageResult:
content = await SlackMessageConverter.yiri2target(message)
raw = await self._send_text(str(target_type), str(target_id), content)
raw = await send_chain(self.bot, self._normalize_target_type(str(target_type)), str(target_id), message)
return platform_events.MessageResult(raw=raw)
async def reply_message(
@@ -111,7 +111,7 @@ class SlackAdapter(SlackAPIMixin, abstract_platform_adapter.AbstractPlatformAdap
raise ValueError('Slack reply_message requires a SlackEvent source object')
target_type = 'channel' if source.type == 'channel' else 'person'
target_id = source.channel_id if source.type == 'channel' else source.user_id
raw = await self._send_text(target_type, target_id, await SlackMessageConverter.yiri2target(message))
raw = await send_chain(self.bot, target_type, target_id, message)
return platform_events.MessageResult(message_id=source.message_id, raw=raw)
async def call_platform_api(self, action: str, params: dict = {}) -> dict:
@@ -4,6 +4,7 @@ import datetime
from langbot.libs.slack_api.slackevent import SlackEvent
from langbot.pkg.utils import image
from langbot.libs.slack_api.media import download_media
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
from langbot_plugin.api.entities.builtin.platform import message as platform_message
@@ -55,15 +56,24 @@ class SlackMessageConverter(abstract_platform_adapter.AbstractMessageConverter):
if event.type == 'channel':
components.append(platform_message.At(target='SlackBot'))
if event.pic_url:
try:
for file in event.get('event', {}).get('files', []):
url = file.get('url_private_download') or file.get('url_private')
if not url:
raise ValueError('Slack attachment is missing its download URL')
data, mime = await download_media(url, bot_token)
mime = file.get('mimetype') or mime
encoded = await image.encode_base64(data)
if mime.startswith('image/') and mime != 'image/svg+xml':
components.append(platform_message.Image(base64=f'data:{mime};base64,{encoded}'))
else:
components.append(
platform_message.Image(
url=event.pic_url, base64=await image.get_slack_image_to_base64(event.pic_url, bot_token)
platform_message.File(
id=file.get('id', ''),
name=file.get('name') or file.get('title') or 'attachment',
size=len(data),
base64=encoded,
)
)
except Exception:
components.append(platform_message.Image(url=event.pic_url))
if event.text:
components.append(platform_message.Plain(text=event.text))
+8 -23
View File
@@ -6,6 +6,8 @@ import traceback
import datetime
from langbot.libs.slack_api.api import SlackClient
from langbot.libs.slack_api.media import send_chain
from langbot.pkg.platform.adapters.slack.message_converter import SlackMessageConverter as OmniMessageConverter
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
from langbot.libs.slack_api.slackevent import SlackEvent
import langbot_plugin.api.entities.builtin.platform.events as platform_events
@@ -61,12 +63,9 @@ class SlackEventConverter(abstract_platform_adapter.AbstractEventConverter):
@staticmethod
async def target2yiri(event: SlackEvent, bot: SlackClient):
yiri_chain = await SlackMessageConverter.target2yiri(
message=event.text, message_id=event.message_id, pic_url=event.pic_url, bot=bot
)
yiri_chain = await OmniMessageConverter.target2yiri(event, bot.bot_token)
if event.type == 'channel':
yiri_chain.insert(0, platform_message.At(target='SlackBot'))
sender = platform_entities.GroupMember(
id=event.user_id,
@@ -127,27 +126,13 @@ class SlackAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
):
slack_event = await SlackEventConverter.yiri2target(message_source)
content_list = await SlackMessageConverter.yiri2target(message)
for content in content_list:
# Both text and image (URL) are sent as text messages
# Slack will auto-unfurl image URLs
message_content = content['content']
if slack_event.type == 'channel':
await self.bot.send_message_to_channel(message_content, slack_event.channel_id)
if slack_event.type == 'im':
await self.bot.send_message_to_one(message_content, slack_event.user_id)
target_type = 'channel' if slack_event.type == 'channel' else 'person'
target_id = slack_event.channel_id if target_type == 'channel' else slack_event.user_id
return await send_chain(self.bot, target_type, target_id, message)
async def send_message(self, target_type: str, target_id: str, message: platform_message.MessageChain):
content_list = await SlackMessageConverter.yiri2target(message)
for content in content_list:
# Both text and image (URL) are sent as text messages
# Slack will auto-unfurl image URLs
message_content = content['content']
if target_type == 'person':
await self.bot.send_message_to_one(message_content, target_id)
if target_type == 'group':
await self.bot.send_message_to_channel(message_content, target_id)
target_type = 'channel' if target_type in {'group', 'channel'} else target_type
return await send_chain(self.bot, target_type, target_id, message)
def register_listener(
self,