Files
LangBot/src/langbot/pkg/platform/adapters/officialaccount/message_converter.py
T
Hyu e631da0073 fix(runner): align SDK pin and complete real runtime verification (#2525)
* fix(runner): align SDK pin and workspace-aware integration fixtures

* fix(ci): format sources and resolve current migration head

* test(persistence): align standalone migration fixtures with current models

* test(web): align smoke fixtures with current processor UI

---------

Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
2026-09-11 12:57:29 +08:00

77 lines
3.7 KiB
Python

from __future__ import annotations
import datetime
from langbot.libs.official_account_api.oaevent import OAEvent
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
from langbot_plugin.api.entities.builtin.platform import message as platform_message
class OfficialAccountMessageConverter(abstract_platform_adapter.AbstractMessageConverter):
@staticmethod
async def yiri2target(message_chain: platform_message.MessageChain) -> str:
content_parts: list[str] = []
for component in message_chain:
if isinstance(component, platform_message.Source):
continue
if isinstance(component, platform_message.Plain):
content_parts.append(component.text)
elif isinstance(component, platform_message.At):
content_parts.append(f'@{component.display or component.target}')
elif isinstance(component, platform_message.AtAll):
content_parts.append('@all')
elif isinstance(component, platform_message.Image):
content_parts.append('[Image]')
elif isinstance(component, platform_message.Voice):
content_parts.append('[Voice]')
elif isinstance(component, platform_message.File):
content_parts.append(f'[File: {component.name or component.id or component.url or "file"}]')
elif isinstance(component, platform_message.Quote):
if component.id is not None:
content_parts.append(f'[Quote {component.id}]')
if component.origin:
content_parts.append(await OfficialAccountMessageConverter.yiri2target(component.origin))
elif isinstance(component, platform_message.Forward):
for node in component.node_list:
if node.message_chain:
content_parts.append(await OfficialAccountMessageConverter.yiri2target(node.message_chain))
else:
content_parts.append(str(component))
return '\n'.join(part for part in content_parts if part)
@staticmethod
async def target2yiri(event: OAEvent) -> platform_message.MessageChain:
timestamp = event.timestamp or int(datetime.datetime.now().timestamp())
components: list[platform_message.MessageComponent] = [
platform_message.Source(
id=event.message_id or f'{event.user_id}:{timestamp}',
time=datetime.datetime.fromtimestamp(timestamp),
)
]
if event.type == 'text' and event.message:
components.append(platform_message.Plain(text=event.message))
elif event.type == 'image':
image_kwargs = {}
if event.picurl:
image_kwargs['url'] = event.picurl
if event.media_id:
image_kwargs['image_id'] = event.media_id
if image_kwargs:
components.append(platform_message.Image(**image_kwargs))
elif event.type == 'voice':
if event.media_id:
components.append(platform_message.Voice(voice_id=event.media_id))
else:
components.append(platform_message.Unknown(text='[officialaccount voice message without media id]'))
elif event.type == 'event':
components.append(
platform_message.Unknown(text=f'[officialaccount event: {event.detail_type or "unknown"}]')
)
else:
components.append(
platform_message.Unknown(text=f'[unsupported officialaccount msgtype: {event.type or "unknown"}]')
)
return platform_message.MessageChain(components)