ForcePilot/backend/package/yuxi/channel/extensions/googlechat/reply_delivery.py
Kris c4e301a5e0 feat(googlechat): 新增Google Chat渠道完整实现
新增Google Chat插件的所有核心功能模块,包括账户配置、消息收发、权限控制、媒体处理、会话管理等完整能力
2026-05-21 10:49:33 +08:00

97 lines
2.9 KiB
Python

from __future__ import annotations
import logging
from yuxi.channel.extensions.googlechat.api import (
delete_message,
send_message,
update_message,
)
from yuxi.channel.extensions.googlechat.formatting import (
build_typing_indicator_text,
chunk_markdown_text,
resolve_bot_display_name,
)
from yuxi.channel.extensions.googlechat.types import ResolvedGoogleChatAccount
logger = logging.getLogger(__name__)
class TypingPlaceholder:
def __init__(self, message_name: str, space_name: str, consumed: bool = False):
self.message_name = message_name
self.space_name = space_name
self.consumed = consumed
async def send_typing_placeholder(
account: ResolvedGoogleChatAccount,
space_name: str,
bot_name: str | None = None,
) -> TypingPlaceholder:
name = bot_name or resolve_bot_display_name(account.config if hasattr(account, "config") else {})
text = build_typing_indicator_text(name)
result = await send_message(account, space_name, text)
message_name = result.get("name", "")
return TypingPlaceholder(message_name=message_name, space_name=space_name)
async def deliver_text_chunk(
account: ResolvedGoogleChatAccount,
space_name: str,
text: str,
placeholder: TypingPlaceholder | None = None,
thread_name: str | None = None,
) -> str:
if placeholder and not placeholder.consumed:
await update_message(account, placeholder.message_name, text)
placeholder.consumed = True
return placeholder.message_name
if placeholder and placeholder.consumed:
result = await send_message(account, space_name, text, thread_name=thread_name)
return result.get("name", "")
result = await send_message(account, space_name, text, thread_name=thread_name)
return result.get("name", "")
async def deliver_text_with_streaming(
account: ResolvedGoogleChatAccount,
space_name: str,
full_text: str,
bot_name: str | None = None,
thread_name: str | None = None,
text_chunk_limit: int = 4000,
) -> list[str]:
chunks = chunk_markdown_text(full_text, text_chunk_limit)
if not chunks:
return []
placeholder = await send_typing_placeholder(account, space_name, bot_name)
message_names = []
for i, chunk in enumerate(chunks):
try:
name = await deliver_text_chunk(
account, space_name, chunk, placeholder if i == 0 else None, thread_name
)
if name:
message_names.append(name)
except Exception as e:
logger.warning("Failed to deliver chunk %d: %s", i, e)
return message_names
async def clear_typing_placeholder(
account: ResolvedGoogleChatAccount,
placeholder: TypingPlaceholder,
) -> None:
try:
await delete_message(account, placeholder.message_name)
except Exception:
try:
await update_message(account, placeholder.message_name, "")
except Exception:
pass