from __future__ import annotations from typing import Any from yuxi.channels.models import ( Attachment, ChannelIdentity, ChannelMessage, ChannelType, ChatType, EventType, MessageType, ) from yuxi.utils.logging_config import logger def normalize_poll_input(poll: dict[str, Any], max_options: int = 12) -> dict[str, Any] | None: name = poll.get("name", "").strip() if not name: logger.warning("Poll normalization: empty name") return None options = poll.get("options", []) if isinstance(options, str): options = [o.strip() for o in options.split(",") if o.strip()] options = [o.strip() for o in options if o.strip()] if len(options) < 2: logger.warning("Poll normalization: less than 2 valid options") return None if len(options) > max_options: logger.warning(f"Poll normalization: {len(options)} options exceeds max {max_options}, truncating") options = options[:max_options] selectable_count = poll.get("selectableCount", poll.get("selectable_count", 1)) try: selectable_count = min(max(int(selectable_count), 1), len(options)) except (TypeError, ValueError): selectable_count = 1 return { "name": name, "options": options, "selectable_count": selectable_count, } def parse_poll_vote(raw_payload: dict[str, Any], channel_id: str) -> ChannelMessage | None: key = raw_payload.get("key", {}) msg = raw_payload.get("message", {}) poll_update = msg.get("pollUpdateMessage", {}) if not poll_update: return None poll_creation_key = poll_update.get("pollCreationMessageKey", {}) vote_info = poll_update.get("vote", {}) remote_jid = key.get("remoteJid", "unknown") msg_id = key.get("id") selected_options = [] if isinstance(vote_info, dict): selected = vote_info.get("selectedOptions", []) if isinstance(selected, list): selected_options = selected elif isinstance(vote_info, list): selected_options = vote_info option_names = [o.get("name", str(o)) if isinstance(o, dict) else str(o) for o in selected_options] vote_text = f"[Poll Vote] {' | '.join(option_names)}" if option_names else "[Poll Vote]" return ChannelMessage( identity=ChannelIdentity( channel_id=channel_id, channel_type=ChannelType.WHATSAPP, channel_user_id=_extract_sender_number(remote_jid), channel_chat_id=remote_jid, channel_message_id=msg_id, ), event_type=EventType.MESSAGE_RECEIVED, message_type=MessageType.TEXT, chat_type=_jid_to_chat_type(remote_jid), content=vote_text, metadata={ "raw_type": "poll_vote", "remote_jid": remote_jid, "poll_msg_id": poll_creation_key.get("id"), "poll_remote_jid": poll_creation_key.get("remoteJid"), "selected_options": selected_options, }, attachments=[ Attachment( type="poll_vote", file_id=msg_id, metadata={ "poll_msg_id": poll_creation_key.get("id"), "poll_remote_jid": poll_creation_key.get("remoteJid"), "selected": option_names, }, ) ], ) def _jid_to_chat_type(jid: str) -> ChatType: if "@g.us" in jid: return ChatType.GROUP return ChatType.DIRECT def _extract_sender_number(jid: str) -> str: return jid.split("@")[0]