Merge PR #747: add media file sending support for Telegram
This commit is contained in:
commit
8053193a36
@ -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)}"
|
||||||
|
|||||||
@ -198,6 +198,18 @@ class TelegramChannel(BaseChannel):
|
|||||||
await self._app.shutdown()
|
await self._app.shutdown()
|
||||||
self._app = None
|
self._app = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_media_type(path: str) -> str:
|
||||||
|
"""Guess media type from file extension."""
|
||||||
|
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
|
||||||
|
if ext in ("jpg", "jpeg", "png", "gif", "webp"):
|
||||||
|
return "photo"
|
||||||
|
if ext == "ogg":
|
||||||
|
return "voice"
|
||||||
|
if ext in ("mp3", "m4a", "wav", "aac"):
|
||||||
|
return "audio"
|
||||||
|
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,35 @@ 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):
|
# Send media files
|
||||||
|
for media_path in (msg.media or []):
|
||||||
try:
|
try:
|
||||||
html = _markdown_to_telegram_html(chunk)
|
media_type = self._get_media_type(media_path)
|
||||||
await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML")
|
sender = {
|
||||||
|
"photo": self._app.bot.send_photo,
|
||||||
|
"voice": self._app.bot.send_voice,
|
||||||
|
"audio": self._app.bot.send_audio,
|
||||||
|
}.get(media_type, self._app.bot.send_document)
|
||||||
|
param = "photo" if media_type == "photo" else media_type if media_type in ("voice", "audio") else "document"
|
||||||
|
with open(media_path, 'rb') as f:
|
||||||
|
await sender(chat_id=chat_id, **{param: f})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"HTML parse failed, falling back to plain text: {e}")
|
filename = media_path.rsplit("/", 1)[-1]
|
||||||
|
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: {filename}]")
|
||||||
|
|
||||||
|
# Send text content
|
||||||
|
if msg.content and msg.content != "[empty message]":
|
||||||
|
for chunk in _split_message(msg.content):
|
||||||
try:
|
try:
|
||||||
await self._app.bot.send_message(chat_id=chat_id, text=chunk)
|
html = _markdown_to_telegram_html(chunk)
|
||||||
except Exception as e2:
|
await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML")
|
||||||
logger.error(f"Error sending Telegram message: {e2}")
|
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."""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user