fix max-bot, add tests
This commit is contained in:
parent
7abbaf7e7a
commit
2ad1438e1c
17 changed files with 1621 additions and 494 deletions
|
|
@ -1,88 +1,151 @@
|
|||
"""MAX event to internal protocol converter."""
|
||||
from typing import Union, List
|
||||
from core.protocol import (
|
||||
IncomingMessage,
|
||||
IncomingCommand,
|
||||
IncomingCallback,
|
||||
Attachment,
|
||||
)
|
||||
"""MAX Bot API payloads -> core Incoming* types."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from core.protocol import Attachment, IncomingCallback, IncomingCommand, IncomingMessage
|
||||
|
||||
|
||||
def _extract_command(text: str) -> Union[IncomingCommand, IncomingCallback, None]:
|
||||
if not text.startswith("!"):
|
||||
return None
|
||||
|
||||
parts = text.strip().split(maxsplit=1)
|
||||
cmd = parts[0].lower()
|
||||
args = parts[1] if len(parts) > 1 else ""
|
||||
|
||||
if cmd == "!yes":
|
||||
return IncomingCallback(
|
||||
user_id="",
|
||||
platform="max",
|
||||
chat_id="",
|
||||
action="confirm",
|
||||
)
|
||||
elif cmd == "!no":
|
||||
return IncomingCallback(
|
||||
user_id="",
|
||||
platform="max",
|
||||
chat_id="",
|
||||
action="cancel",
|
||||
)
|
||||
else:
|
||||
return IncomingCommand(
|
||||
user_id="",
|
||||
platform="max",
|
||||
chat_id="",
|
||||
command=cmd.lstrip("!"),
|
||||
args=args.split() if args else [],
|
||||
)
|
||||
|
||||
|
||||
def max_message_to_incoming(
|
||||
def incoming_from_text_commands(
|
||||
*,
|
||||
text: str,
|
||||
user_id: str,
|
||||
chat_id: str,
|
||||
attachments: List[Attachment] = None,
|
||||
callback_data: str = None,
|
||||
message_id: str = None,
|
||||
) -> Union[IncomingMessage, IncomingCommand, IncomingCallback]:
|
||||
if callback_data:
|
||||
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=user_id,
|
||||
user_id=max_user_id,
|
||||
platform="max",
|
||||
chat_id=chat_id,
|
||||
action=callback_data,
|
||||
payload={"message_id": message_id} if message_id else {},
|
||||
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 text:
|
||||
cmd = _extract_command(text)
|
||||
if cmd is not None:
|
||||
cmd.user_id = user_id
|
||||
cmd.chat_id = chat_id
|
||||
return cmd
|
||||
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,
|
||||
)
|
||||
|
||||
return IncomingMessage(
|
||||
user_id=user_id,
|
||||
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=chat_id,
|
||||
text=text or "",
|
||||
attachments=attachments or [],
|
||||
chat_id=platform_chat_id,
|
||||
command=name,
|
||||
args=tail.split() if tail else [],
|
||||
)
|
||||
|
||||
|
||||
def max_attachment_to_internal(
|
||||
def incoming_from_message_callback_payload(
|
||||
*,
|
||||
filename: str,
|
||||
mime_type: str,
|
||||
download_url: str,
|
||||
) -> Attachment:
|
||||
return Attachment(
|
||||
type="document",
|
||||
url=download_url,
|
||||
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_type,
|
||||
)
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue