ForcePilot/backend/package/yuxi/channel/extensions/rocketchat/streaming.py

89 lines
2.8 KiB
Python
Raw Normal View History

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