ForcePilot/backend/package/yuxi/channels/adapters/matrix/reaction_utils.py
Kris 2063145ce1 feat(matrix): 新增完整的Matrix适配器工具集
新增了20+个Matrix相关工具模块,包含线程处理、自动加入、消息去重、配置管理、安全策略、媒体处理、命令解析等功能,完善Matrix适配器基础能力
2026-05-12 00:45:54 +08:00

99 lines
2.7 KiB
Python

from __future__ import annotations
from collections import Counter
from typing import Any
def build_reaction(emoji: str, target_event_id: str) -> dict[str, Any]:
return {
"m.relates_to": {
"rel_type": "m.annotation",
"event_id": target_event_id,
"key": emoji,
},
}
def extract_reaction(event: Any) -> dict[str, str] | None:
content = event.source.get("content", {}) if hasattr(event, "source") else {}
relates_to = content.get("m.relates_to", {})
if relates_to.get("rel_type") != "m.annotation":
return None
return {
"target_event_id": relates_to.get("event_id", ""),
"key": relates_to.get("key", ""),
}
def summarize_reactions(events: list[dict[str, Any]]) -> dict[str, dict]:
key_counter: Counter[str] = Counter()
user_keys: dict[str, set[str]] = {}
last_sender: dict[str, str] = {}
for evt in events:
sender = evt.get("sender", "")
key = evt.get("key", "")
target = evt.get("target_event_id", "")
if not key or not target:
continue
key_counter[key] += 1
if target not in user_keys:
user_keys[target] = set()
user_keys[target].add(sender)
last_sender[key] = sender
result: dict[str, dict] = {}
for target, users in user_keys.items():
result[target] = {
"total_reactions": sum(
count
for k, count in key_counter.items()
if any(e.get("target_event_id") == target and e.get("key") == k for e in events)
),
"unique_reactors": len(users),
"keys": [
{"key": k, "count": count}
for k, count in key_counter.items()
if any(e.get("target_event_id") == target and e.get("key") == k for e in events)
],
}
return result
_COMMON_EMOJI_MAP = {
"👍": "+1",
"👎": "-1",
"❤️": "heart",
"😄": "smile",
"🎉": "party",
"🚀": "rocket",
"👀": "eyes",
"": "check",
}
def select_reaction(available: list[dict[str, Any]], query: str) -> dict[str, Any] | None:
normalized = _COMMON_EMOJI_MAP.get(query, query).lower()
for entry in available:
key = entry.get("key", "")
if key == query or key.lower() == normalized:
return entry
return available[0] if available else None
def build_batch_remove(
client_reactions: list[dict[str, Any]],
target_event_id: str,
) -> list[dict[str, Any]]:
return [
build_reaction(r.get("key", ""), target_event_id)
for r in client_reactions
if r.get("target_event_id") == target_event_id
]