ForcePilot/backend/package/yuxi/channel/extensions/ringcentral/media.py
Kris 7a9031ea53 feat(channel): 添加 RingCentral 渠道扩展
新增 RingCentral 渠道扩展,支持在 Yuxi 平台中集成 RingCentral 统一通信平台。

包含以下功能模块:
- sdk: RingCentral SDK 封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- subscription: 事件订阅
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session: 会话管理
- events: 事件处理
- adaptive_cards: 自适应卡片
- formatting: 格式化
- media: 媒体资源处理
- mentions: @提及
- notes: 笔记功能
- reactions: 表情反应
- tasks: 任务管理
- teams: 团队管理
- types: 类型定义
2026-05-21 11:37:49 +08:00

92 lines
2.4 KiB
Python

from __future__ import annotations
import asyncio
import logging
import httpx
from yuxi.channel.extensions.ringcentral.sdk import AsyncRingCentralClient
logger = logging.getLogger(__name__)
async def upload_file(
client: AsyncRingCentralClient,
group_id: str,
file_data: bytes,
filename: str,
content_type: str = "application/octet-stream",
) -> dict:
builder = client.platform.create_multipart_builder()
builder.set_body({"groupId": group_id})
builder.add_file(None, content=file_data, content_type=content_type, file_name=filename)
def _send():
request = builder.request("/restapi/v1.0/glip/files")
return client.platform.send_request(request)
resp = await asyncio.to_thread(_send)
return resp.json()
async def download_file_content(
client: AsyncRingCentralClient,
file_id: str,
) -> bytes:
def _download():
resp = client.platform.get(f"/restapi/v1.0/glip/files/{file_id}/content")
return resp.response.content
return await asyncio.to_thread(_download)
async def send_media_message(
client: AsyncRingCentralClient,
group_id: str,
text: str,
file_info: dict,
) -> dict:
return await client.post(
f"/restapi/v1.0/glip/chats/{group_id}/posts",
body={
"text": text,
"attachments": [
{
"type": "File",
"id": file_info.get("id"),
"name": file_info.get("name", ""),
"contentUri": file_info.get("contentUri", ""),
}
],
},
)
async def send_media_from_url(
client: AsyncRingCentralClient,
group_id: str,
media_url: str,
media_type: str,
) -> None:
async with httpx.AsyncClient(timeout=httpx.Timeout(60.0)) as http:
resp = await http.get(media_url)
resp.raise_for_status()
content = resp.content
filename = _extract_filename(media_url, media_type)
upload_result = await upload_file(client, group_id, content, filename, media_type)
await send_media_message(client, group_id, "", upload_result)
def _extract_filename(url: str, content_type: str) -> str:
ext_map = {
"image/jpeg": ".jpg",
"image/png": ".png",
"image/gif": ".gif",
"image/webp": ".webp",
"video/mp4": ".mp4",
"application/pdf": ".pdf",
}
ext = ext_map.get(content_type, ".bin")
return f"attachment{ext}"