新增 Intercom 渠道扩展,支持在 Yuxi 平台中集成 Intercom 客服渠道。 包含以下功能模块: - client: Intercom API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - streaming: 流式消息处理 - format: 消息格式转换 - outbound: 外发消息管理 - handoff: 转人工会话切换 - pairing: 用户配对与绑定 - security: 安全签名校验 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session_guard: 会话防护 - types: 类型定义
68 lines
2.1 KiB
Python
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
|