ForcePilot/backend/package/yuxi/channel/extensions/helpscout/customer_profile.py
Kris 432d5db970 feat(helpscout): 新增Help Scout客服工单渠道插件
完成Help Scout渠道的完整功能实现,包含API客户端、webhook处理、轮询同步、自动回复、工单标签分配、客户资料管理等核心能力,附带完整的配置Schema与插件元信息
2026-05-21 10:49:56 +08:00

120 lines
4.2 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__)
class HelpScoutCustomerProfile:
async def get_profile(
self,
customer_id: int,
account_id: str | None = None,
) -> dict | None:
account = resolve_account(account_id or "default")
client = self._build_client(account)
try:
data = await client.get_customer(customer_id)
profile = {
"id": data.get("id"),
"first_name": data.get("firstName", ""),
"last_name": data.get("lastName", ""),
"email": data.get("email", ""),
"emails": data.get("emails", []),
"photo_url": data.get("photoUrl", ""),
"created_at": data.get("createdAt", ""),
"updated_at": data.get("updatedAt", ""),
}
logger.debug("Help Scout customer profile fetched: id=%d", customer_id)
return profile
except Exception:
logger.exception("Help Scout get customer profile failed: id=%d", customer_id)
return None
finally:
await client.close()
async def resolve_customer_id_by_email(
self,
email: str,
account_id: str | None = None,
) -> int | None:
account = resolve_account(account_id or "default")
client = self._build_client(account)
try:
result = await client.list_customers(email=email, page=1)
customers = result.get("_embedded", {}).get("customers", [])
if customers:
logger.debug("Help Scout customer resolved: email=%s id=%d", email, customers[0]["id"])
return customers[0]["id"]
logger.debug("Help Scout customer not found by email: %s", email)
return None
except Exception:
logger.exception("Help Scout resolve customer by email failed: %s", email)
return None
finally:
await client.close()
async def get_recent_conversations(
self,
customer_id: int,
limit: int = 5,
account_id: str | None = None,
) -> list[dict]:
account = resolve_account(account_id or "default")
client = self._build_client(account)
try:
data = await client.get_customer(customer_id)
conversations = data.get("_embedded", {}).get("conversations", [])
recent = conversations[:limit]
return [
{
"id": c.get("id"),
"number": c.get("number"),
"subject": c.get("subject", ""),
"status": c.get("status", ""),
"created_at": c.get("createdAt", ""),
}
for c in recent
]
except Exception:
logger.exception(
"Help Scout get recent conversations failed: customer=%d",
customer_id,
)
return []
finally:
await client.close()
def build_context(
self,
profile: dict | None = None,
recent_convos: list[dict] | None = None,
) -> str:
lines = ["--- Customer Context ---"]
if profile:
name = f"{profile.get('first_name', '')} {profile.get('last_name', '')}".strip()
if name:
lines.append(f"Customer: {name}")
email = profile.get("email", "")
if email:
lines.append(f"Email: {email}")
if recent_convos:
lines.append(f"Recent conversations ({len(recent_convos)}):")
for c in recent_convos:
lines.append(f" #{c.get('id')} [{c.get('status')}] {c.get('subject', '')}")
return "\n".join(lines) if len(lines) > 1 else ""
@staticmethod
def _build_client(account: dict) -> HelpScoutClient:
auth = HelpScoutAuth(account["app_id"], account["app_secret"])
return HelpScoutClient(auth)