- Add complete Python backend (Litestar + LangGraph) with chat, conversations, tickets APIs - Add GitHub Actions workflow for auto-deploying backend to Azure Web App (soc-backend) - Add gunicorn to requirements.txt for production serving - Update CLAUDE.md and EXTERNAL_SERVICES.md with latest config - Remove obsolete claudehd.md (merged into gpthd.md) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
118 lines
3.7 KiB
Python
118 lines
3.7 KiB
Python
"""Ticket system tools — proxy to Gongdan API (read-only)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
from langchain_core.tools import tool
|
|
|
|
from app.config import settings
|
|
|
|
|
|
def _gongdan_headers() -> dict[str, str]:
|
|
return {"X-Api-Key": settings.gongdan_api_key}
|
|
|
|
|
|
def _map_status(raw: str) -> str:
|
|
"""Map Gongdan status values to frontend-friendly values."""
|
|
mapping = {
|
|
"OPEN": "pending",
|
|
"ASSIGNED": "processing",
|
|
"IN_PROGRESS": "processing",
|
|
"PENDING_CUSTOMER": "processing",
|
|
"RESOLVED": "resolved",
|
|
"CLOSED": "resolved",
|
|
}
|
|
return mapping.get(raw, "pending")
|
|
|
|
|
|
def _map_priority(raw: str) -> str:
|
|
"""Map Gongdan priority to P0-P3."""
|
|
mapping = {
|
|
"URGENT": "P0",
|
|
"PRIORITY": "P1",
|
|
"NORMAL": "P2",
|
|
"LOW": "P3",
|
|
}
|
|
return mapping.get(raw, "P2")
|
|
|
|
|
|
@tool
|
|
async def ticket_list(page: int = 1, page_size: int = 20) -> str:
|
|
"""List tickets from the ticket system.
|
|
|
|
Use this tool when the user asks about tickets, work orders, issues,
|
|
or wants to see a summary of current support requests.
|
|
|
|
Args:
|
|
page: Page number (default 1).
|
|
page_size: Number of tickets per page (default 20).
|
|
"""
|
|
url = f"{settings.gongdan_api_base}/api/tickets"
|
|
params = {"page": page, "pageSize": page_size}
|
|
|
|
async with httpx.AsyncClient(timeout=15) as client:
|
|
resp = await client.get(url, params=params, headers=_gongdan_headers())
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
|
|
tickets = data.get("tickets", [])
|
|
if not tickets:
|
|
return "No tickets found."
|
|
|
|
lines: list[str] = []
|
|
for t in tickets:
|
|
ticket_id = t.get("ticketNumber", t.get("id", "?"))
|
|
title = t.get("description", "")[:80]
|
|
status = _map_status(t.get("status", ""))
|
|
priority = _map_priority(t.get("priority", ""))
|
|
created = t.get("createdAt", "")[:10]
|
|
customer = t.get("customer", {}).get("name", "Unknown")
|
|
lines.append(
|
|
f"- [{ticket_id}] {title} | status={status} priority={priority} "
|
|
f"customer={customer} created={created}"
|
|
)
|
|
|
|
return f"Found {len(tickets)} tickets:\n" + "\n".join(lines)
|
|
|
|
|
|
@tool
|
|
async def ticket_detail(ticket_id: str) -> str:
|
|
"""Get detailed information about a specific ticket.
|
|
|
|
Use this tool when the user asks for details on a particular ticket
|
|
or work order, providing its ID.
|
|
|
|
Args:
|
|
ticket_id: The ticket UUID or ticket number.
|
|
"""
|
|
url = f"{settings.gongdan_api_base}/api/tickets/{ticket_id}"
|
|
|
|
async with httpx.AsyncClient(timeout=15) as client:
|
|
resp = await client.get(url, headers=_gongdan_headers())
|
|
resp.raise_for_status()
|
|
t = resp.json()
|
|
|
|
ticket_number = t.get("ticketNumber", t.get("id", "?"))
|
|
description = t.get("description", "N/A")
|
|
status = _map_status(t.get("status", ""))
|
|
priority = _map_priority(t.get("priority", ""))
|
|
platform = t.get("platform", "N/A")
|
|
model_used = t.get("modelUsed", "N/A")
|
|
account = t.get("accountInfo", "N/A")
|
|
request_example = t.get("requestExample", "")
|
|
customer_name = t.get("customer", {}).get("name", "Unknown")
|
|
engineer = t.get("assignedEngineer", {}).get("username", "Unassigned")
|
|
created = t.get("createdAt", "")
|
|
sla = t.get("slaDeadline", "")
|
|
|
|
return (
|
|
f"Ticket: {ticket_number}\n"
|
|
f"Status: {status} | Priority: {priority}\n"
|
|
f"Platform: {platform} | Model: {model_used}\n"
|
|
f"Customer: {customer_name} | Account: {account}\n"
|
|
f"Engineer: {engineer}\n"
|
|
f"Created: {created} | SLA: {sla}\n"
|
|
f"Description: {description}\n"
|
|
f"Request Example: {request_example}"
|
|
)
|