mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-19 17:00:59 +00:00
feat: Telegram EBA adapter - full implementation
- TelegramAdapter inherits AbstractPlatformAdapter with all capabilities - TelegramEventConverter handles all Update types: message, edited_message, chat_member, my_chat_member, callback_query, message_reaction - TelegramAPIMixin implements: edit_message, delete_message, forward_message, get_group_info, get_group_member_list/info, get_user_info, get_file_url, mute/unmute/kick_member, leave_group - PLATFORM_API_MAP for call_platform_api: pin/unpin message, set chat title/desc, get admins, send chat action, create invite link, answer callback query - Full backward compat: legacy FriendMessage/GroupMessage listeners still work - Preserves all existing functionality: stream output, markdown card, forum topics - Old sources/telegram.py untouched for gradual migration
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
"""Telegram message chain converter.
|
||||
|
||||
Migrated from the original sources/telegram.py TelegramMessageConverter. Logic unchanged.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import typing
|
||||
|
||||
import telegram
|
||||
|
||||
from langbot.pkg.utils import httpclient
|
||||
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
||||
import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
||||
|
||||
|
||||
class TelegramMessageConverter(abstract_platform_adapter.AbstractMessageConverter):
|
||||
@staticmethod
|
||||
async def yiri2target(message_chain: platform_message.MessageChain, bot: telegram.Bot) -> list[dict]:
|
||||
"""Convert a LangBot MessageChain to a list of Telegram-sendable components."""
|
||||
components = []
|
||||
|
||||
for component in message_chain:
|
||||
if isinstance(component, platform_message.Plain):
|
||||
components.append({'type': 'text', 'text': component.text})
|
||||
elif isinstance(component, platform_message.Image):
|
||||
photo_bytes = None
|
||||
|
||||
if component.base64:
|
||||
photo_bytes = base64.b64decode(component.base64)
|
||||
elif component.url:
|
||||
session = httpclient.get_session()
|
||||
async with session.get(component.url) as response:
|
||||
photo_bytes = await response.read()
|
||||
elif component.path:
|
||||
with open(component.path, 'rb') as f:
|
||||
photo_bytes = f.read()
|
||||
|
||||
components.append({'type': 'photo', 'photo': photo_bytes})
|
||||
elif isinstance(component, platform_message.File):
|
||||
file_bytes = None
|
||||
|
||||
if component.base64:
|
||||
b64_data = component.base64
|
||||
if ';base64,' in b64_data:
|
||||
b64_data = b64_data.split(';base64,', 1)[1]
|
||||
file_bytes = base64.b64decode(b64_data)
|
||||
elif component.url:
|
||||
session = httpclient.get_session()
|
||||
async with session.get(component.url) as response:
|
||||
file_bytes = await response.read()
|
||||
elif component.path:
|
||||
with open(component.path, 'rb') as f:
|
||||
file_bytes = f.read()
|
||||
|
||||
file_name = getattr(component, 'name', None) or 'file'
|
||||
components.append({'type': 'document', 'document': file_bytes, 'filename': file_name})
|
||||
elif isinstance(component, platform_message.Forward):
|
||||
for node in component.node_list:
|
||||
components.extend(await TelegramMessageConverter.yiri2target(node.message_chain, bot))
|
||||
|
||||
return components
|
||||
|
||||
@staticmethod
|
||||
async def target2yiri(message: telegram.Message, bot: telegram.Bot, bot_account_id: str):
|
||||
"""Convert a Telegram Message to a LangBot MessageChain."""
|
||||
message_components = []
|
||||
|
||||
def parse_message_text(text: str) -> list[platform_message.MessageComponent]:
|
||||
msg_components = []
|
||||
|
||||
if f'@{bot_account_id}' in text:
|
||||
msg_components.append(platform_message.At(target=bot_account_id))
|
||||
text = text.replace(f'@{bot_account_id}', '')
|
||||
msg_components.append(platform_message.Plain(text=text))
|
||||
|
||||
return msg_components
|
||||
|
||||
if message.text:
|
||||
message_text = message.text
|
||||
message_components.extend(parse_message_text(message_text))
|
||||
|
||||
if message.photo:
|
||||
if message.caption:
|
||||
message_components.extend(parse_message_text(message.caption))
|
||||
|
||||
file = await message.photo[-1].get_file()
|
||||
|
||||
file_bytes = None
|
||||
file_format = ''
|
||||
|
||||
async with httpclient.get_session(trust_env=True).get(file.file_path) as response:
|
||||
file_bytes = await response.read()
|
||||
file_format = 'image/jpeg'
|
||||
|
||||
message_components.append(
|
||||
platform_message.Image(
|
||||
base64=f'data:{file_format};base64,{base64.b64encode(file_bytes).decode("utf-8")}'
|
||||
)
|
||||
)
|
||||
|
||||
if message.voice:
|
||||
if message.caption:
|
||||
message_components.extend(parse_message_text(message.caption))
|
||||
|
||||
file = await message.voice.get_file()
|
||||
|
||||
file_bytes = None
|
||||
file_format = message.voice.mime_type or 'audio/ogg'
|
||||
|
||||
async with httpclient.get_session(trust_env=True).get(file.file_path) as response:
|
||||
file_bytes = await response.read()
|
||||
|
||||
message_components.append(
|
||||
platform_message.Voice(
|
||||
base64=f'data:{file_format};base64,{base64.b64encode(file_bytes).decode("utf-8")}',
|
||||
length=message.voice.duration,
|
||||
)
|
||||
)
|
||||
|
||||
if message.document:
|
||||
if message.caption:
|
||||
message_components.extend(parse_message_text(message.caption))
|
||||
|
||||
file = await message.document.get_file()
|
||||
file_name = message.document.file_name or 'document'
|
||||
file_size = message.document.file_size or 0
|
||||
file_format = message.document.mime_type or 'application/octet-stream'
|
||||
|
||||
file_bytes = None
|
||||
async with httpclient.get_session(trust_env=True).get(file.file_path) as response:
|
||||
file_bytes = await response.read()
|
||||
|
||||
message_components.append(
|
||||
platform_message.File(
|
||||
name=file_name,
|
||||
size=file_size,
|
||||
base64=f'data:{file_format};base64,{base64.b64encode(file_bytes).decode("utf-8")}',
|
||||
)
|
||||
)
|
||||
|
||||
return platform_message.MessageChain(message_components)
|
||||
Reference in New Issue
Block a user