完成Help Scout渠道的完整功能实现,包含API客户端、webhook处理、轮询同步、自动回复、工单标签分配、客户资料管理等核心能力,附带完整的配置Schema与插件元信息
82 lines
2.8 KiB
Python
82 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from yuxi.channel.extensions.helpscout.auth import HelpScoutAuth
|
|
from yuxi.channel.extensions.helpscout.client import HelpScoutClient
|
|
from yuxi.channel.extensions.helpscout.config import resolve_account
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CATEGORY_KEYWORDS: dict[str, list[str]] = {
|
|
"billing": ["refund", "invoice", "payment", "charge", "subscription", "billing"],
|
|
"technical": ["bug", "error", "crash", "not working", "broken", "issue", "problem"],
|
|
"account": ["login", "password", "access", "account", "sign in", "sign up"],
|
|
"general": ["question", "help", "how to", "what is", "inquiry"],
|
|
}
|
|
|
|
ASSIGNEE_RULES: dict[str, str] = {
|
|
"billing": "billing",
|
|
"technical": "engineering",
|
|
"account": "support",
|
|
"general": "support",
|
|
}
|
|
|
|
|
|
class HelpScoutAssigner:
|
|
async def auto_assign(
|
|
self,
|
|
conversation_id: int,
|
|
body_text: str,
|
|
account_id: str | None = None,
|
|
) -> int | None:
|
|
account = resolve_account(account_id or "default")
|
|
category = self._classify_conversation(body_text)
|
|
team_name = ASSIGNEE_RULES.get(category)
|
|
|
|
logger.debug(
|
|
"Help Scout auto-assign: conv=%d category=%s team=%s",
|
|
conversation_id,
|
|
category,
|
|
team_name,
|
|
)
|
|
|
|
if not team_name:
|
|
return None
|
|
|
|
client = self._build_client(account)
|
|
try:
|
|
teams_resp = await client.list_teams(mailbox=account["mailbox_id"])
|
|
teams = teams_resp.get("_embedded", {}).get("teams", [])
|
|
matched_team = next((t for t in teams if t.get("name", "").lower() == team_name), None)
|
|
if matched_team:
|
|
await client.update_conversation(conversation_id, {"assignTo": matched_team["id"]})
|
|
logger.info(
|
|
"Help Scout assigned: conv=%d team=%s(%d)",
|
|
conversation_id,
|
|
team_name,
|
|
matched_team["id"],
|
|
)
|
|
return matched_team["id"]
|
|
logger.debug("Help Scout team not found: %s for conv=%d", team_name, conversation_id)
|
|
return None
|
|
except Exception:
|
|
logger.exception("Help Scout auto-assign failed: conv=%d", conversation_id)
|
|
return None
|
|
finally:
|
|
await client.close()
|
|
|
|
@staticmethod
|
|
def _classify_conversation(body_text: str) -> str:
|
|
text_lower = body_text.lower()
|
|
for category, keywords in CATEGORY_KEYWORDS.items():
|
|
for keyword in keywords:
|
|
if keyword in text_lower:
|
|
return category
|
|
return "general"
|
|
|
|
@staticmethod
|
|
def _build_client(account: dict) -> HelpScoutClient:
|
|
auth = HelpScoutAuth(account["app_id"], account["app_secret"])
|
|
return HelpScoutClient(auth)
|