Handle media files (voice messages, audio, images, documents) on Telegram Channel

This commit is contained in:
Darye 2026-02-16 16:29:03 +01:00
parent 1207b89adb
commit 23b7e1ef5e
2 changed files with 65 additions and 11 deletions

View File

@ -52,6 +52,11 @@ class MessageTool(Tool):
"chat_id": { "chat_id": {
"type": "string", "type": "string",
"description": "Optional: target chat/user ID" "description": "Optional: target chat/user ID"
},
"media": {
"type": "array",
"items": {"type": "string"},
"description": "Optional: list of file paths to attach (images, audio, documents)"
} }
}, },
"required": ["content"] "required": ["content"]
@ -62,6 +67,7 @@ class MessageTool(Tool):
content: str, content: str,
channel: str | None = None, channel: str | None = None,
chat_id: str | None = None, chat_id: str | None = None,
media: list[str] | None = None,
**kwargs: Any **kwargs: Any
) -> str: ) -> str:
channel = channel or self._default_channel channel = channel or self._default_channel
@ -76,11 +82,13 @@ class MessageTool(Tool):
msg = OutboundMessage( msg = OutboundMessage(
channel=channel, channel=channel,
chat_id=chat_id, chat_id=chat_id,
content=content content=content,
media=media or []
) )
try: try:
await self._send_callback(msg) await self._send_callback(msg)
return f"Message sent to {channel}:{chat_id}" media_info = f" with {len(media)} attachments" if media else ""
return f"Message sent to {channel}:{chat_id}{media_info}"
except Exception as e: except Exception as e:
return f"Error sending message: {str(e)}" return f"Error sending message: {str(e)}"

View File

@ -198,6 +198,18 @@ class TelegramChannel(BaseChannel):
await self._app.shutdown() await self._app.shutdown()
self._app = None self._app = None
def _get_media_type(self, path: str) -> str:
"""Guess media type from file extension."""
path = path.lower()
if path.endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')):
return "photo"
elif path.endswith('.ogg'):
return "voice"
elif path.endswith(('.mp3', '.m4a', '.wav', '.aac')):
return "audio"
else:
return "document"
async def send(self, msg: OutboundMessage) -> None: async def send(self, msg: OutboundMessage) -> None:
"""Send a message through Telegram.""" """Send a message through Telegram."""
if not self._app: if not self._app:
@ -212,16 +224,50 @@ class TelegramChannel(BaseChannel):
logger.error(f"Invalid chat_id: {msg.chat_id}") logger.error(f"Invalid chat_id: {msg.chat_id}")
return return
for chunk in _split_message(msg.content): # Handle media files
try: if msg.media:
html = _markdown_to_telegram_html(chunk) for media_path in msg.media:
await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML")
except Exception as e:
logger.warning(f"HTML parse failed, falling back to plain text: {e}")
try: try:
await self._app.bot.send_message(chat_id=chat_id, text=chunk) media_type = self._get_media_type(media_path)
except Exception as e2:
logger.error(f"Error sending Telegram message: {e2}") # Determine caption (only for first media or if explicitly set,
# but here we keep it simple: content is sent separately if media is present
# to avoid length issues, unless we want to attach it to the first media)
# For simplicity: send media first, then text if present.
# Or: if single media, attach text as caption.
# Let's attach content as caption to the last media if single,
# otherwise send text separately.
with open(media_path, 'rb') as f:
if media_type == "photo":
await self._app.bot.send_photo(chat_id=chat_id, photo=f)
elif media_type == "voice":
await self._app.bot.send_voice(chat_id=chat_id, voice=f)
elif media_type == "audio":
await self._app.bot.send_audio(chat_id=chat_id, audio=f)
else:
await self._app.bot.send_document(chat_id=chat_id, document=f)
except Exception as e:
logger.error(f"Failed to send media {media_path}: {e}")
await self._app.bot.send_message(
chat_id=chat_id,
text=f"[Failed to send file: {media_path}]"
)
# Send text content if present
if msg.content and msg.content != "[empty message]":
for chunk in _split_message(msg.content):
try:
html = _markdown_to_telegram_html(chunk)
await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML")
except Exception as e:
logger.warning(f"HTML parse failed, falling back to plain text: {e}")
try:
await self._app.bot.send_message(chat_id=chat_id, text=chunk)
except Exception as e2:
logger.error(f"Error sending Telegram message: {e2}")
async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Handle /start command.""" """Handle /start command."""