新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
92 lines
2.5 KiB
Python
92 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from yuxi.channels.models import ChannelResponse
|
|
|
|
_PARAGRAPH_SEP = "\n\n"
|
|
_DEFAULT_CHUNK_LIMIT = 16383
|
|
|
|
|
|
def build_post_options(response: ChannelResponse) -> dict[str, Any]:
|
|
return {
|
|
"channel_id": response.identity.channel_chat_id,
|
|
"message": response.content,
|
|
"root_id": response.reply_to_message_id or "",
|
|
"props": response.metadata.get("props", {}),
|
|
"file_ids": response.metadata.get("file_ids", []),
|
|
}
|
|
|
|
|
|
def build_patch_options(chunk_text: str) -> dict[str, Any]:
|
|
return {"message": chunk_text}
|
|
|
|
|
|
def chunk_text_for_outbound(text: str, limit: int = _DEFAULT_CHUNK_LIMIT) -> list[str]:
|
|
"""按段落边界将文本拆分为不超过 limit 的分块。
|
|
|
|
优先在双换行符(段落)边界拆分;如果单段仍超限,
|
|
则在单换行符(行)边界拆分;如果单行仍超限,则硬截断。
|
|
"""
|
|
if len(text) <= limit:
|
|
return [text]
|
|
|
|
chunks: list[str] = []
|
|
paragraphs = text.split(_PARAGRAPH_SEP)
|
|
|
|
current = ""
|
|
for para in paragraphs:
|
|
if len(para) > limit:
|
|
if current:
|
|
chunks.append(current.rstrip())
|
|
current = ""
|
|
|
|
chunks.extend(_split_by_lines(para, limit))
|
|
continue
|
|
|
|
candidate = f"{current}{_PARAGRAPH_SEP}{para}" if current else para
|
|
if len(candidate) > limit:
|
|
chunks.append(current.rstrip())
|
|
current = para
|
|
else:
|
|
current = candidate
|
|
|
|
if current:
|
|
chunks.append(current.rstrip())
|
|
|
|
if not chunks:
|
|
chunks.append(text[:limit])
|
|
|
|
return chunks
|
|
|
|
|
|
def _split_by_lines(text: str, limit: int) -> list[str]:
|
|
"""在换行符边界拆分超限段落。"""
|
|
chunks: list[str] = []
|
|
lines = text.split("\n")
|
|
current = ""
|
|
for line in lines:
|
|
if len(line) > limit:
|
|
if current:
|
|
chunks.append(current.rstrip())
|
|
current = ""
|
|
chunks.extend(_split_hard(line, limit))
|
|
continue
|
|
|
|
candidate = f"{current}\n{line}" if current else line
|
|
if len(candidate) > limit:
|
|
chunks.append(current.rstrip())
|
|
current = line
|
|
else:
|
|
current = candidate
|
|
|
|
if current:
|
|
chunks.append(current.rstrip())
|
|
|
|
return chunks
|
|
|
|
|
|
def _split_hard(text: str, limit: int) -> list[str]:
|
|
"""硬截断超长行。"""
|
|
return [text[i : i + limit] for i in range(0, len(text), limit)]
|