ForcePilot/backend/package/yuxi/channel/extensions/freshdesk/config.py
Kris 3e861d6cd1 feat(freshdesk): 新增Freshdesk/Freshchat渠道插件
实现完整的Freshdesk和Freshchat集成支持,包含会话守卫、错误定义、消息去重、配置管理、webhook处理、出站消息发送、状态监控、安全校验、配对功能和流式回复支持
2026-05-21 10:47:20 +08:00

122 lines
4.9 KiB
Python

import os
from yuxi.channel.extensions.freshdesk.types import FreshdeskAccount, FreshdeskMode
class FreshdeskConfigAdapter:
def list_account_ids(self, config: dict | None = None) -> list[str]:
if config is None:
config = {}
accounts = config.get("channels", {}).get("freshdesk", {}).get("accounts", {})
if accounts:
return list(accounts.keys())
return ["default"]
def resolve_account(self, account_id: str = "default", config: dict | None = None) -> FreshdeskAccount:
if config is None:
config = {}
channel_cfg = config.get("channels", {}).get("freshdesk", {})
accounts = channel_cfg.get("accounts", {})
account_cfg = accounts.get(account_id, {}) if accounts else channel_cfg
mode = account_cfg.get("mode", "both")
freshdesk_domain = account_cfg.get("freshdeskDomain") or os.getenv("FRESHDESK_DOMAIN", "")
freshdesk_api_key = account_cfg.get("freshdeskApiKey") or os.getenv("FRESHDESK_API_KEY", "")
freshchat_domain = account_cfg.get("freshchatDomain") or freshdesk_domain
freshchat_api_key = (
account_cfg.get("freshchatApiKey") or os.getenv("FRESHCHAT_API_KEY", "") or freshdesk_api_key
)
webhook_secret = account_cfg.get("webhookSecret") or os.getenv("FRESHDESK_WEBHOOK_SECRET", "")
return FreshdeskAccount(
account_id=account_id,
mode=FreshdeskMode(mode),
freshdesk_domain=freshdesk_domain,
freshdesk_api_key=freshdesk_api_key,
freshchat_domain=freshchat_domain,
freshchat_api_key=freshchat_api_key,
webhook_secret=webhook_secret,
agent_id=account_cfg.get("agentId", ""),
dm_policy=account_cfg.get("dmPolicy", "open"),
allow_from=account_cfg.get("allowFrom", []),
auto_skip_closed=account_cfg.get("autoSkipClosed", True),
auto_skip_resolved=account_cfg.get("autoSkipResolved", True),
handoff_policy=account_cfg.get("handoffPolicy", "ignore"),
default_priority=account_cfg.get("defaultPriority", 2),
)
def is_configured(self, account: FreshdeskAccount) -> bool:
if account.mode in (FreshdeskMode.FRESHCHAT, FreshdeskMode.BOTH):
return bool(account.freshchat_api_key and account.freshchat_domain)
return bool(account.freshdesk_api_key and account.freshdesk_domain)
def config_schema(self) -> dict:
return {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": ["freshdesk", "freshchat", "both"],
"default": "both",
"title": "集成模式",
},
"freshdeskDomain": {
"type": "string",
"title": "Freshdesk 域名",
},
"freshdeskApiKey": {
"type": "string",
"title": "Freshdesk API Key",
"writeOnly": True,
},
"freshchatDomain": {
"type": "string",
"title": "Freshchat 域名",
},
"freshchatApiKey": {
"type": "string",
"title": "Freshchat API Key",
"writeOnly": True,
},
"webhookSecret": {
"type": "string",
"title": "Webhook Secret",
"writeOnly": True,
},
"agentId": {
"type": "string",
"title": "Agent ID",
},
"dmPolicy": {
"type": "string",
"enum": ["open", "pairing", "allowlist", "disabled"],
"default": "open",
"title": "DM 安全策略",
},
"allowFrom": {
"type": "array",
"items": {"type": "string"},
"title": "白名单",
},
"autoSkipClosed": {"type": "boolean", "default": True, "title": "跳过已关闭会话"},
"autoSkipResolved": {"type": "boolean", "default": True, "title": "跳过已解决工单"},
"handoffPolicy": {
"type": "string",
"enum": ["ignore", "note_only", "continue"],
"default": "ignore",
"title": "人工接管策略",
},
"defaultPriority": {
"type": "integer",
"enum": [1, 2, 3, 4],
"default": 2,
"title": "默认优先级",
},
},
"required": ["freshdeskDomain"],
}