新增拼多多(Pinduoduo)渠道扩展,支持在 Yuxi 平台中集成拼多多电商客服渠道。 包含以下功能模块: - client: 拼多多 API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - pairing: 用户配对与绑定 - security: 安全校验 - signature: 请求签名验证 - token: Token 管理 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - tools: Agent 工具集成 - window: 窗口管理 - types: 类型定义
152 lines
6.8 KiB
Python
152 lines
6.8 KiB
Python
from __future__ import annotations
|
||
|
||
import os
|
||
|
||
from yuxi.channel.extensions.pinduoduo.types import PinduoduoAccount
|
||
|
||
ENV_MAP = {
|
||
"client_id": "PDD_CLIENT_ID",
|
||
"client_secret": "PDD_CLIENT_SECRET",
|
||
"access_token": "PDD_ACCESS_TOKEN",
|
||
"refresh_token": "PDD_REFRESH_TOKEN",
|
||
"mall_id": "PDD_MALL_ID",
|
||
"dm_policy": "PDD_DM_POLICY",
|
||
"poll_interval_sec": "PDD_POLL_INTERVAL",
|
||
"enable_push": "PDD_ENABLE_PUSH",
|
||
"push_verify_token": "PDD_PUSH_VERIFY_TOKEN",
|
||
"sign_method": "PDD_SIGN_METHOD",
|
||
}
|
||
|
||
|
||
class PinduoduoConfig:
|
||
def list_account_ids(self, config: dict | None = None) -> list[str]:
|
||
accounts = self._get_accounts(config or {})
|
||
if accounts:
|
||
return list(accounts.keys())
|
||
return ["default"]
|
||
|
||
async def resolve_account(self, account_id: str, config: dict | None = None) -> PinduoduoAccount:
|
||
config = config or {}
|
||
accounts = self._get_accounts(config)
|
||
|
||
if account_id in accounts:
|
||
acct = accounts[account_id]
|
||
return PinduoduoAccount(
|
||
account_id=account_id,
|
||
client_id=acct.get("clientId", "") or self._env("client_id"),
|
||
client_secret=acct.get("clientSecret", "") or self._env("client_secret"),
|
||
access_token=acct.get("accessToken") or self._env("access_token") or None,
|
||
refresh_token=acct.get("refreshToken") or self._env("refresh_token") or None,
|
||
mall_id=acct.get("mallId", "") or self._env("mall_id"),
|
||
dm_policy=(acct.get("dmPolicy") or self._env("dm_policy") or "pairing"),
|
||
poll_interval_sec=int(acct.get("pollInterval") or self._env("poll_interval_sec") or 30),
|
||
enable_push=(acct.get("enablePush") or self._env("enable_push", "").lower() == "true" or False),
|
||
push_verify_token=(acct.get("pushVerifyToken") or self._env("push_verify_token") or None),
|
||
sign_method=(acct.get("signMethod") or self._env("sign_method") or "md5"),
|
||
)
|
||
|
||
return PinduoduoAccount(
|
||
account_id="default",
|
||
client_id=self._env("client_id"),
|
||
client_secret=self._env("client_secret"),
|
||
access_token=self._env("access_token") or None,
|
||
refresh_token=self._env("refresh_token") or None,
|
||
mall_id=self._env("mall_id"),
|
||
dm_policy=self._env("dm_policy") or "pairing",
|
||
poll_interval_sec=int(self._env("poll_interval_sec") or 30),
|
||
enable_push=(self._env("enable_push") or "").lower() == "true",
|
||
push_verify_token=self._env("push_verify_token") or None,
|
||
sign_method=self._env("sign_method") or "md5",
|
||
)
|
||
|
||
def is_configured(self, account: dict) -> bool:
|
||
return bool(account.get("client_id") and account.get("client_secret") and account.get("mall_id"))
|
||
|
||
def _is_account_configured(self, account: PinduoduoAccount) -> bool:
|
||
return bool(account.client_id and account.client_secret and account.mall_id)
|
||
|
||
@staticmethod
|
||
def _get_accounts(config: dict) -> dict:
|
||
return config.get("accounts", {})
|
||
|
||
@staticmethod
|
||
def _env(key: str, default: str = "") -> str:
|
||
env_key = ENV_MAP.get(key, "")
|
||
return os.getenv(env_key, default) if env_key else default
|
||
|
||
def config_schema(self) -> dict:
|
||
return {
|
||
"$schema": "https://json-schema.org/draft-07/schema#",
|
||
"type": "object",
|
||
"title": "拼多多渠道配置",
|
||
"properties": {
|
||
"accounts": {
|
||
"type": "object",
|
||
"title": "账户配置",
|
||
"description": "按 account_id 组织的账户列表,支持多店铺",
|
||
"additionalProperties": {
|
||
"type": "object",
|
||
"properties": {
|
||
"clientId": {
|
||
"type": "string",
|
||
"title": "Client ID",
|
||
"description": "拼多多开放平台应用 Client ID",
|
||
},
|
||
"clientSecret": {
|
||
"type": "string",
|
||
"title": "Client Secret",
|
||
"x-ui-password": True,
|
||
},
|
||
"accessToken": {
|
||
"type": "string",
|
||
"title": "Access Token",
|
||
"description": "OAuth 授权后自动填充",
|
||
"x-ui-password": True,
|
||
},
|
||
"refreshToken": {
|
||
"type": "string",
|
||
"title": "Refresh Token",
|
||
"description": "OAuth 授权后自动填充",
|
||
"x-ui-password": True,
|
||
},
|
||
"mallId": {
|
||
"type": "string",
|
||
"title": "店铺 ID (Mall ID)",
|
||
},
|
||
"dmPolicy": {
|
||
"type": "string",
|
||
"title": "DM 策略",
|
||
"enum": ["pairing", "allowlist", "open", "disabled"],
|
||
"default": "pairing",
|
||
},
|
||
"pollInterval": {
|
||
"type": "integer",
|
||
"title": "轮询间隔(秒)",
|
||
"default": 30,
|
||
"minimum": 5,
|
||
"maximum": 300,
|
||
},
|
||
"enablePush": {
|
||
"type": "boolean",
|
||
"title": "启用消息推送",
|
||
"default": False,
|
||
},
|
||
"pushVerifyToken": {
|
||
"type": "string",
|
||
"title": "推送验证 Token",
|
||
"x-ui-password": True,
|
||
},
|
||
"signMethod": {
|
||
"type": "string",
|
||
"title": "签名算法",
|
||
"enum": ["md5", "hmac-sha256"],
|
||
"default": "md5",
|
||
"description": "MD5 为旧版,HMAC-SHA256 为新版,根据应用创建时间选择",
|
||
},
|
||
},
|
||
"required": ["clientId", "clientSecret", "mallId"],
|
||
},
|
||
},
|
||
},
|
||
}
|