新增 RocketChat 渠道扩展,支持在 Yuxi 平台中集成 RocketChat 团队协作平台。 包含以下功能模块: - client: RocketChat API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - websocket: WebSocket 实时连接 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - dedup: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - gating: 门控管理 - threading: 线程管理 - reactions: 表情反应 - types: 类型定义
89 lines
2.8 KiB
Python
89 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
import time
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from yuxi.channel.extensions.rocketchat.outbound import RocketChatOutbound
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class RocketChatEditStream:
|
|
def __init__(
|
|
self,
|
|
outbound: RocketChatOutbound,
|
|
room_id: str,
|
|
thread_id: str | None = None,
|
|
max_chars: int = 4000,
|
|
throttle_ms: int = 1200,
|
|
):
|
|
self.outbound = outbound
|
|
self.room_id = room_id
|
|
self.thread_id = thread_id
|
|
self.max_chars = max_chars
|
|
self.throttle_ms = max(throttle_ms, 250)
|
|
self.stream_msg_id: str | None = None
|
|
self.last_update_at: float = 0
|
|
self._dirty: bool = False
|
|
|
|
async def update(self, text: str) -> None:
|
|
now = time.monotonic()
|
|
elapsed = now - self.last_update_at
|
|
if elapsed < self.throttle_ms / 1000:
|
|
self._dirty = True
|
|
return
|
|
|
|
if self._dirty or elapsed >= self.throttle_ms / 1000:
|
|
await self._flush(text)
|
|
|
|
async def _flush(self, text: str) -> None:
|
|
truncated = text[: self.max_chars]
|
|
try:
|
|
if self.stream_msg_id:
|
|
await self.outbound.edit_message(
|
|
self.room_id,
|
|
self.stream_msg_id,
|
|
truncated,
|
|
)
|
|
else:
|
|
resp = await self.outbound.client.post_message(
|
|
self.room_id,
|
|
truncated + "\n\n_Thinking…_",
|
|
thread_id=self.thread_id,
|
|
)
|
|
self.stream_msg_id = resp.get("message", {}).get("_id", "")
|
|
except Exception as e:
|
|
logger.debug("Stream flush error: %s", e)
|
|
self.last_update_at = time.monotonic()
|
|
self._dirty = False
|
|
|
|
async def finalize(self, final_text: str) -> None:
|
|
if self.stream_msg_id:
|
|
try:
|
|
await self.outbound.edit_message(
|
|
self.room_id,
|
|
self.stream_msg_id,
|
|
final_text[: self.max_chars],
|
|
)
|
|
except Exception as e:
|
|
logger.debug("Stream finalize error: %s", e)
|
|
else:
|
|
try:
|
|
await self.outbound.send_text(
|
|
self.room_id,
|
|
final_text,
|
|
thread_id=self.thread_id,
|
|
)
|
|
except Exception as e:
|
|
logger.debug("Stream finalize send error: %s", e)
|
|
|
|
async def cancel(self) -> None:
|
|
if self.stream_msg_id:
|
|
try:
|
|
await self.outbound.delete_message(self.room_id, self.stream_msg_id)
|
|
except Exception:
|
|
pass
|
|
self.stream_msg_id = None
|