151 lines
4.2 KiB
Python
151 lines
4.2 KiB
Python
"""MAX Bot API payloads -> core Incoming* types."""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from core.protocol import Attachment, IncomingCallback, IncomingCommand, IncomingMessage
|
|
|
|
|
|
def incoming_from_text_commands(
|
|
*,
|
|
text: str,
|
|
max_user_id: str,
|
|
platform_chat_id: str,
|
|
attachments: list[Attachment],
|
|
) -> IncomingMessage | IncomingCommand | IncomingCallback:
|
|
"""Парсинг текста: только slash-команды (как в Telegram), обычное сообщение иначе."""
|
|
|
|
stripped = text.strip()
|
|
proto = stripped.lower()
|
|
|
|
if proto in {"/yes"}:
|
|
return IncomingCallback(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
action="confirm",
|
|
payload={},
|
|
)
|
|
if proto in {"/no"}:
|
|
return IncomingCallback(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
action="cancel",
|
|
payload={},
|
|
)
|
|
|
|
if not stripped.startswith("/"):
|
|
return IncomingMessage(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
text=text,
|
|
attachments=attachments,
|
|
reply_to=None,
|
|
)
|
|
|
|
raw = stripped[1:]
|
|
parts = raw.split(maxsplit=1)
|
|
name = (parts[0] or "").lower()
|
|
tail = parts[1] if len(parts) > 1 else ""
|
|
|
|
return IncomingCommand(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
command=name,
|
|
args=tail.split() if tail else [],
|
|
)
|
|
|
|
|
|
def incoming_from_message_callback_payload(
|
|
*,
|
|
max_user_id: str,
|
|
platform_chat_id: str,
|
|
payload_raw: str | None,
|
|
callback_message_id: str | None,
|
|
) -> IncomingCallback | None:
|
|
if not payload_raw:
|
|
return None
|
|
if payload_raw in {"confirm", "cancel", "toggle_skill"}:
|
|
return IncomingCallback(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
action=payload_raw,
|
|
payload={"message_id": callback_message_id or ""},
|
|
)
|
|
return IncomingCallback(
|
|
user_id=max_user_id,
|
|
platform="max",
|
|
chat_id=platform_chat_id,
|
|
action="max_callback",
|
|
payload={"payload": payload_raw, "message_id": callback_message_id},
|
|
)
|
|
|
|
|
|
def attachment_from_max_dict(raw: dict[str, Any]) -> tuple[Attachment, dict[str, Any]] | None:
|
|
"""Return core Attachment placeholder + raw attachment for download."""
|
|
|
|
kind = raw.get("type")
|
|
payload = raw.get("payload")
|
|
if not isinstance(kind, str) or not isinstance(payload, dict):
|
|
return None
|
|
|
|
url = payload.get("url")
|
|
if not isinstance(url, str):
|
|
url = ""
|
|
|
|
token = payload.get("token")
|
|
filename = "attachment.bin"
|
|
mapped = "document"
|
|
mime: str | None = None
|
|
|
|
if kind == "image":
|
|
mapped = "image"
|
|
filename = "image.jpg"
|
|
elif kind == "video":
|
|
mapped = "video"
|
|
filename = "video.mp4"
|
|
elif kind == "audio":
|
|
mapped = "audio"
|
|
mime = payload.get("mime_type") if isinstance(payload.get("mime_type"), str) else "audio/mpeg"
|
|
filename = "audio.bin"
|
|
elif kind == "file":
|
|
fname = payload.get("filename")
|
|
filename = fname if isinstance(fname, str) and fname else "file.bin"
|
|
mapped = "document"
|
|
else:
|
|
return None
|
|
|
|
attachment = Attachment(
|
|
type=mapped,
|
|
url=url or None,
|
|
content=None,
|
|
filename=filename,
|
|
mime_type=mime,
|
|
)
|
|
meta = dict(raw)
|
|
if token:
|
|
meta["_download_token_hint"] = token
|
|
return attachment, meta
|
|
|
|
|
|
def collect_max_attachments(message_body: dict[str, Any]) -> tuple[list[Attachment], list[dict[str, Any]]]:
|
|
attachments = message_body.get("attachments")
|
|
if not isinstance(attachments, list):
|
|
return [], []
|
|
|
|
core_list: list[Attachment] = []
|
|
raw_list: list[dict[str, Any]] = []
|
|
|
|
for item in attachments:
|
|
if isinstance(item, dict):
|
|
parsed = attachment_from_max_dict(item)
|
|
if parsed is None:
|
|
continue
|
|
core_a, raw_a = parsed
|
|
core_list.append(core_a)
|
|
raw_list.append(raw_a)
|
|
return core_list, raw_list
|