feat(server): 新增运行时聊天服务和用户代理服务,支持智能对话和用户行为分析
This commit is contained in:
@@ -27,7 +27,7 @@ class RuntimeChatService:
|
||||
|
||||
def complete(
|
||||
self,
|
||||
messages: list[dict[str, str]],
|
||||
messages: list[dict[str, Any]],
|
||||
*,
|
||||
slot_priority: tuple[str, ...] = ("main", "backup"),
|
||||
max_tokens: int = 500,
|
||||
@@ -91,7 +91,7 @@ class RuntimeChatService:
|
||||
def _request_chat_completion(
|
||||
self,
|
||||
config: dict[str, str],
|
||||
messages: list[dict[str, str]],
|
||||
messages: list[dict[str, Any]],
|
||||
*,
|
||||
max_tokens: int,
|
||||
temperature: float,
|
||||
@@ -136,7 +136,7 @@ class RuntimeChatService:
|
||||
endpoint: str,
|
||||
model: str,
|
||||
api_key: str,
|
||||
messages: list[dict[str, str]],
|
||||
messages: list[dict[str, Any]],
|
||||
max_tokens: int,
|
||||
temperature: float,
|
||||
) -> str:
|
||||
@@ -165,7 +165,7 @@ class RuntimeChatService:
|
||||
endpoint: str,
|
||||
model: str,
|
||||
api_key: str,
|
||||
messages: list[dict[str, str]],
|
||||
messages: list[dict[str, Any]],
|
||||
max_tokens: int,
|
||||
temperature: float,
|
||||
) -> str:
|
||||
@@ -197,7 +197,7 @@ class RuntimeChatService:
|
||||
endpoint: str,
|
||||
model: str,
|
||||
api_key: str,
|
||||
messages: list[dict[str, str]],
|
||||
messages: list[dict[str, Any]],
|
||||
max_tokens: int,
|
||||
temperature: float,
|
||||
) -> str:
|
||||
|
||||
@@ -2124,6 +2124,61 @@ class UserAgentService:
|
||||
item: dict[str, object],
|
||||
payload: UserAgentRequest,
|
||||
) -> dict[str, str]:
|
||||
provided_type = str(item.get("document_type") or "").strip().lower()
|
||||
expense_type_code = self._collect_entity_values(payload).get("expense_type_code", "")
|
||||
has_customer = bool(self._collect_entity_values(payload).get("customer"))
|
||||
if provided_type:
|
||||
if provided_type in {"flight_itinerary", "train_ticket"}:
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "travel",
|
||||
"group_code": "travel",
|
||||
"scene_label": "差旅票据",
|
||||
}
|
||||
if provided_type == "hotel_invoice":
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "hotel",
|
||||
"group_code": "travel",
|
||||
"scene_label": "住宿票据",
|
||||
}
|
||||
if provided_type in {"taxi_receipt", "parking_toll_receipt"}:
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "transport",
|
||||
"group_code": "travel",
|
||||
"scene_label": "交通票据",
|
||||
}
|
||||
if provided_type == "meal_receipt":
|
||||
group_code = "entertainment" if expense_type_code == "entertainment" or has_customer else "meal"
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": group_code,
|
||||
"group_code": group_code,
|
||||
"scene_label": "餐饮票据",
|
||||
}
|
||||
if provided_type == "office_invoice":
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "office",
|
||||
"group_code": "office",
|
||||
"scene_label": "办公用品票据",
|
||||
}
|
||||
if provided_type == "meeting_invoice":
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "meeting",
|
||||
"group_code": "meeting",
|
||||
"scene_label": "会务票据",
|
||||
}
|
||||
if provided_type == "training_invoice":
|
||||
return {
|
||||
"document_type": provided_type,
|
||||
"expense_type": "training",
|
||||
"group_code": "training",
|
||||
"scene_label": "培训票据",
|
||||
}
|
||||
|
||||
text = " ".join(
|
||||
[
|
||||
str(item.get("filename") or ""),
|
||||
@@ -2132,8 +2187,6 @@ class UserAgentService:
|
||||
]
|
||||
).lower()
|
||||
compact = text.replace(" ", "")
|
||||
expense_type_code = self._collect_entity_values(payload).get("expense_type_code", "")
|
||||
has_customer = bool(self._collect_entity_values(payload).get("customer"))
|
||||
|
||||
if any(keyword in compact for keyword in ("机票", "航班", "火车", "高铁", "行程单")):
|
||||
return {
|
||||
@@ -2187,6 +2240,19 @@ class UserAgentService:
|
||||
return "other"
|
||||
|
||||
def _extract_document_fields(self, item: dict[str, object]) -> dict[str, str]:
|
||||
raw_fields = item.get("document_fields")
|
||||
if isinstance(raw_fields, list):
|
||||
normalized_fields: dict[str, str] = {}
|
||||
for field in raw_fields:
|
||||
if not isinstance(field, dict):
|
||||
continue
|
||||
label = str(field.get("label") or "").strip()
|
||||
value = str(field.get("value") or "").strip()
|
||||
if label and value:
|
||||
normalized_fields[label] = value
|
||||
if normalized_fields:
|
||||
return normalized_fields
|
||||
|
||||
text = " ".join([str(item.get("summary") or ""), str(item.get("text") or "")]).strip()
|
||||
fields: dict[str, str] = {}
|
||||
amount_match = AMOUNT_TEXT_PATTERN.search(text)
|
||||
|
||||
Reference in New Issue
Block a user