refactor(backend): update service layers
- services/ontology.py: update ontology service logic - services/user_agent.py: update user agent service logic
This commit is contained in:
@@ -325,7 +325,11 @@ class SemanticOntologyService:
|
||||
|
||||
entities = self._extract_entities(query, compact_query, reference)
|
||||
rule_scenario, scenario_score = self._detect_scenario(compact_query)
|
||||
time_range, _time_score = self._extract_time_range(query, compact_query)
|
||||
time_range, _time_score = self._extract_time_range(
|
||||
query,
|
||||
compact_query,
|
||||
context_json=context_json,
|
||||
)
|
||||
context_scenario = self._resolve_context_scenario(context_json)
|
||||
if rule_scenario == "unknown" and context_scenario is not None:
|
||||
rule_scenario = context_scenario
|
||||
@@ -1175,16 +1179,22 @@ class SemanticOntologyService:
|
||||
self,
|
||||
query: str,
|
||||
compact_query: str,
|
||||
*,
|
||||
context_json: dict[str, Any],
|
||||
) -> tuple[OntologyTimeRange, float]:
|
||||
today = datetime.now(UTC).date()
|
||||
today = self._resolve_reference_today(context_json)
|
||||
|
||||
direct_mappings = {
|
||||
"今天": self._single_day_range(today, "今天", "day"),
|
||||
"昨日": self._single_day_range(today - timedelta(days=1), "昨日", "day"),
|
||||
"昨天": self._single_day_range(today - timedelta(days=1), "昨天", "day"),
|
||||
"明天": self._single_day_range(today + timedelta(days=1), "明天", "day"),
|
||||
}
|
||||
for keyword, value in direct_mappings.items():
|
||||
direct_mappings = [
|
||||
("大前天", self._single_day_range(today - timedelta(days=3), "大前天", "day")),
|
||||
("前天", self._single_day_range(today - timedelta(days=2), "前天", "day")),
|
||||
("昨日", self._single_day_range(today - timedelta(days=1), "昨日", "day")),
|
||||
("昨天", self._single_day_range(today - timedelta(days=1), "昨天", "day")),
|
||||
("今天", self._single_day_range(today, "今天", "day")),
|
||||
("明天", self._single_day_range(today + timedelta(days=1), "明天", "day")),
|
||||
("后天", self._single_day_range(today + timedelta(days=2), "后天", "day")),
|
||||
("大后天", self._single_day_range(today + timedelta(days=3), "大后天", "day")),
|
||||
]
|
||||
for keyword, value in direct_mappings:
|
||||
if keyword in query:
|
||||
return value, 0.10
|
||||
|
||||
@@ -1263,6 +1273,29 @@ class SemanticOntologyService:
|
||||
|
||||
return OntologyTimeRange(), 0.0
|
||||
|
||||
@staticmethod
|
||||
def _resolve_reference_today(context_json: dict[str, Any]) -> date:
|
||||
client_now_iso = str(context_json.get("client_now_iso") or "").strip()
|
||||
if not client_now_iso:
|
||||
return datetime.now(UTC).date()
|
||||
|
||||
normalized = client_now_iso.replace("Z", "+00:00")
|
||||
try:
|
||||
client_now = datetime.fromisoformat(normalized)
|
||||
except ValueError:
|
||||
return datetime.now(UTC).date()
|
||||
|
||||
if client_now.tzinfo is None:
|
||||
client_now = client_now.replace(tzinfo=UTC)
|
||||
|
||||
try:
|
||||
offset_minutes = int(context_json.get("client_timezone_offset_minutes") or 0)
|
||||
except (TypeError, ValueError):
|
||||
offset_minutes = 0
|
||||
|
||||
local_now = client_now - timedelta(minutes=offset_minutes)
|
||||
return local_now.date()
|
||||
|
||||
@staticmethod
|
||||
def _single_day_range(target: date, raw: str, granularity: str) -> OntologyTimeRange:
|
||||
return OntologyTimeRange(
|
||||
|
||||
@@ -595,6 +595,7 @@ class UserAgentService:
|
||||
payload,
|
||||
can_proceed=can_proceed,
|
||||
draft_payload=draft_payload,
|
||||
missing_slot_labels=[SLOT_LABELS.get(key, key) for key in missing_slot_keys],
|
||||
)
|
||||
|
||||
return UserAgentReviewPayload(
|
||||
@@ -936,7 +937,7 @@ class UserAgentService:
|
||||
emphasis="secondary",
|
||||
),
|
||||
UserAgentReviewAction(
|
||||
label="修改",
|
||||
label="修改识别信息",
|
||||
action_type="edit_review",
|
||||
description="打开结构化模板,按已识别字段逐项修改。",
|
||||
emphasis="secondary",
|
||||
@@ -958,9 +959,9 @@ class UserAgentService:
|
||||
location = slots.get("location")
|
||||
customer = slots.get("customer_name")
|
||||
|
||||
summary = "系统识别出您想要发起一笔报销。"
|
||||
summary = "我先按你当前提供的信息整理出一笔报销。"
|
||||
if expense_type and expense_type.value:
|
||||
summary = f"系统识别出您想要报销{expense_type.value}。"
|
||||
summary = f"我理解你这次想报销{expense_type.value}。"
|
||||
details: list[str] = []
|
||||
if customer and customer.value:
|
||||
details.append(f"客户名称:{customer.value}")
|
||||
@@ -970,8 +971,6 @@ class UserAgentService:
|
||||
details.append(f"地点:{location.value}")
|
||||
if amount and amount.value:
|
||||
details.append(f"金额:{amount.value}")
|
||||
if claim_groups and len(claim_groups) > 1:
|
||||
details.append(f"建议拆分为 {len(claim_groups)} 张报销单")
|
||||
if details:
|
||||
return f"{summary} {';'.join(details)}。"
|
||||
return summary
|
||||
@@ -993,12 +992,15 @@ class UserAgentService:
|
||||
review_action = str(payload.context_json.get("review_action") or "").strip()
|
||||
if review_action == "save_draft":
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return f"相关识别信息已在右侧展示,请核对。当前已先保存到草稿 {draft_payload.claim_no},缺失信息后续可继续补充。"
|
||||
return "相关识别信息已在右侧展示,请核对。当前信息未补齐,已按你的要求先保存草稿。"
|
||||
return (
|
||||
f"我已经把本轮识别结果整理好了,右侧可以继续核对。"
|
||||
f"当前先替你保存到草稿 {draft_payload.claim_no},后面把缺的信息补齐就可以继续。"
|
||||
)
|
||||
return "我已经把本轮识别结果整理好了,右侧可以继续核对。当前信息还没补全,我先按你的要求保存为草稿。"
|
||||
if review_action == "next_step":
|
||||
return "相关识别信息已在右侧展示,请核对。当前信息已满足继续流转条件,可进入下一步。"
|
||||
return "我已经把识别到的关键信息整理好了,右侧是本轮识别结果。你确认无误后,可以直接进入下一步。"
|
||||
if review_action == "edit_review":
|
||||
return "相关识别信息已在右侧展示,请核对。我已根据你的修改更新识别结果,请继续确认。"
|
||||
return "我已经按你修改后的内容重新识别了一遍。右侧是最新结果,下方还有待补信息和注意事项,你继续确认即可。"
|
||||
return review_payload.body_message or None
|
||||
|
||||
def _build_review_body_message(
|
||||
@@ -1007,12 +1009,21 @@ class UserAgentService:
|
||||
*,
|
||||
can_proceed: bool,
|
||||
draft_payload: UserAgentDraftPayload | None,
|
||||
missing_slot_labels: list[str],
|
||||
) -> str:
|
||||
if can_proceed:
|
||||
return "相关识别信息已在右侧展示,请核对。确认无误后可点击“下一步”。"
|
||||
return "我已经把识别结果整理在右侧了。当前关键信息基本齐全,你核对无误后可以直接点“下一步”继续处理。"
|
||||
missing_hint = "、".join(missing_slot_labels[:4])
|
||||
missing_message = f"当前还缺少 {missing_hint}。" if missing_hint else "当前仍有信息待补充。"
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return f"相关识别信息已在右侧展示,请核对。当前信息还未补齐,可修改后继续,或先保存到草稿 {draft_payload.claim_no}。"
|
||||
return "相关识别信息已在右侧展示,请核对。当前信息还未补齐,可点击“修改”继续补充,或先“保存草稿”。"
|
||||
return (
|
||||
f"我先根据你当前提供的信息完成了初步识别,右侧是识别结果。{missing_message}"
|
||||
f"如果现在还拿不全,也可以先保存到草稿 {draft_payload.claim_no},后面再补。"
|
||||
)
|
||||
return (
|
||||
f"我先根据你当前提供的信息完成了初步识别,右侧是识别结果。{missing_message}"
|
||||
"你可以继续补充;如果暂时不方便提供,也可以先保存草稿。"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _can_proceed_review(
|
||||
@@ -1413,12 +1424,8 @@ class UserAgentService:
|
||||
time_range = payload.ontology.time_range
|
||||
if time_range.start_date and time_range.end_date:
|
||||
if time_range.start_date == time_range.end_date:
|
||||
if time_range.raw and time_range.raw != time_range.start_date:
|
||||
return f"{time_range.start_date}(原文:{time_range.raw})"
|
||||
return time_range.start_date
|
||||
normalized = f"{time_range.start_date} 至 {time_range.end_date}"
|
||||
if time_range.raw and time_range.raw != normalized:
|
||||
return f"{normalized}(原文:{time_range.raw})"
|
||||
return normalized
|
||||
if time_range.raw:
|
||||
return time_range.raw
|
||||
@@ -1493,7 +1500,7 @@ class UserAgentService:
|
||||
if edited_value:
|
||||
raw_value = str(review_form_values.get("time_range_raw") or edited_value).strip()
|
||||
return self._build_slot_value(
|
||||
value=edited_value if raw_value == edited_value else f"{edited_value}(原文:{raw_value})",
|
||||
value=edited_value,
|
||||
raw_value=raw_value,
|
||||
normalized_value=edited_value,
|
||||
source="user_form",
|
||||
@@ -1509,9 +1516,8 @@ class UserAgentService:
|
||||
else f"{time_range.start_date} 至 {time_range.end_date}"
|
||||
)
|
||||
raw_value = str(time_range.raw or "").strip()
|
||||
value = normalized_value if not raw_value or raw_value == normalized_value else f"{normalized_value}(原文:{raw_value})"
|
||||
return self._build_slot_value(
|
||||
value=value,
|
||||
value=normalized_value,
|
||||
raw_value=raw_value,
|
||||
normalized_value=normalized_value,
|
||||
source="user_text",
|
||||
|
||||
Reference in New Issue
Block a user