ForcePilot/backend/package/yuxi/channel/extensions/intercom/streaming.py
Kris 2ddcf1cc55 feat(channel): 添加 Intercom 渠道扩展
新增 Intercom 渠道扩展,支持在 Yuxi 平台中集成 Intercom 客服渠道。

包含以下功能模块:
- client: Intercom API 客户端封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- streaming: 流式消息处理
- format: 消息格式转换
- outbound: 外发消息管理
- handoff: 转人工会话切换
- pairing: 用户配对与绑定
- security: 安全签名校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session_guard: 会话防护
- types: 类型定义
2026-05-21 11:01:49 +08:00

68 lines
2.1 KiB
Python

import logging
import time
from yuxi.channel.extensions.intercom.constants import (
INTERCOM_BLOCK_STREAMING_CHUNK_MIN_CHARS,
INTERCOM_BLOCK_STREAMING_CHUNK_MAX_CHARS,
)
logger = logging.getLogger(__name__)
class IntercomStreaming:
streaming_mode = "block"
preview_stream_throttle_ms = 2000
preview_min_initial_chars = 100
block_streaming_enabled = True
block_streaming_break = "\n"
block_streaming_chunk_min_chars = INTERCOM_BLOCK_STREAMING_CHUNK_MIN_CHARS
block_streaming_chunk_max_chars = INTERCOM_BLOCK_STREAMING_CHUNK_MAX_CHARS
block_streaming_chunk_break_preference = "paragraph"
block_streaming_coalesce_defaults = None
def create_draft_stream_session(self, target_id: str) -> object:
return {"target_id": target_id, "content": ""}
def create_block_chunker(self) -> object:
return {"mode": "length"}
async def stream_reply(
self,
client,
conversation_id: str,
full_text_generator,
bot_admin_id: str,
) -> str:
accumulated = ""
note_id = None
last_note_update = 0.0
NOTE_THROTTLE = 2.0
async for chunk in full_text_generator:
accumulated += chunk
now = time.monotonic()
if note_id is None:
try:
resp = await client.reply_conversation(
conversation_id,
"正在生成回复...",
message_type="note",
reply_type="admin",
admin_id=bot_admin_id,
)
note_id = resp.get("id", "")
except Exception:
logger.warning("Failed to create draft note for streaming")
if now - last_note_update >= NOTE_THROTTLE and len(accumulated) > 100:
last_note_update = now
if note_id:
try:
await client.delete_conversation_part(conversation_id, str(note_id))
except Exception:
logger.warning("Failed to delete draft note %s", note_id)
return accumulated