完成Help Scout渠道的完整功能实现,包含API客户端、webhook处理、轮询同步、自动回复、工单标签分配、客户资料管理等核心能力,附带完整的配置Schema与插件元信息
120 lines
4.2 KiB
Python
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)
|