增加生成学校易耗品填写的转换程序

This commit is contained in:
wandering
2026-08-31 18:25:35 +08:00
parent 44496a54e6
commit 4fbb4c36ed
19 changed files with 777 additions and 365 deletions
+5 -90
View File
@@ -43,7 +43,6 @@ from ...infra.documents.invoice import CACHE_DIR_NAME
from ...infra.llm.prompt import (
build_invoice_system_prompt,
build_normal_info_system_prompt,
build_supplement_system_prompt,
build_travel_info_system_prompt,
)
@@ -386,6 +385,7 @@ def build_extraction_user_message(
cache_map: dict[str, Any],
match_result: dict[str, list[dict[str, Any]]],
previous_analysis: dict[str, Any] | None = None,
user_supplement: str | None = None,
) -> str:
"""构建提取请求的用户消息(供 Agent 调度使用)。
@@ -393,6 +393,7 @@ def build_extraction_user_message(
cache_map: 缓存数据映射。
match_result: 匹配结果。
previous_analysis: 上一轮 LLM 分析结果(可选,补充文件时传入作为历史上下文)。
user_supplement: 用户文字补充(可选,传入时作为修正上下文)。
Returns:
拼接好的用户消息字符串。
@@ -411,6 +412,9 @@ def build_extraction_user_message(
+ json.dumps(previous_analysis, ensure_ascii=False, indent=2)
)
if user_supplement:
parts.append("【用户文字补充】用户补充了以下文字信息,请据此更新你的分析结果。\n" + user_supplement)
if match_result:
parts.append(
"【发票与支付记录匹配结果】"
@@ -500,92 +504,3 @@ def extract_normal_info(
包含报销说明、发票总数、总金额、支付方式、附件清单等字段的字典。
"""
return _extract_info(source_dir, build_normal_info_system_prompt(), "普通发票")
# ------------------------------------------------------------------
# 用户补充信息处理
# ------------------------------------------------------------------
def process_user_supplement(
user_text: str,
extracted_info: dict[str, Any],
invoice_type: str,
source_dir: Path | None = None,
) -> dict[str, Any]:
"""让用户补充的文字信息通过 LLM 分析,返回需要更新的字段。
Args:
user_text: 用户输入的文字。
extracted_info: 当前已提取的报销信息。
invoice_type: "travel" 或 "normal"。
source_dir: 会话目录(可选,传入时启用 SSE 流式事件写入)。
Returns:
包含 updated_fields, changes, confidence, unparsed_info 的字典。
"""
system_prompt = build_supplement_system_prompt()
parts = [
f"发票类型: {'差旅报销' if invoice_type == 'travel' else '普通报销'}",
"",
"以下是当前已提取的报销信息:",
json.dumps(extracted_info, ensure_ascii=False, indent=2),
"",
f"用户补充信息:{user_text}",
"",
"=== 请分析用户输入并返回需要更新的字段 ===",
]
user_message = "\n".join(parts)
try:
response = llm_query_text(
system_prompt=system_prompt,
text=user_message,
reasoning_effort="low",
source_dir=source_dir,
)
result = parse_json_response(response)
log.info("LLM 补充信息分析完成")
return result
except Exception as e:
log.error("LLM 补充信息分析失败: %s", e)
return {
"updated_fields": {},
"changes": [],
"confidence": 0.0,
"unparsed_info": f"分析失败: {e}",
}
def merge_supplement_into_info(
extracted_info: dict[str, Any],
updated_fields: dict[str, Any],
) -> dict[str, Any]:
"""将 LLM 返回的更新字段合并到已提取的信息中。
支持点号路径(如 basic_info.travel_purpose)表示嵌套更新。
Args:
extracted_info: 当前已提取的报销信息。
updated_fields: LLM 返回的需要更新的字段。
Returns:
更新后的报销信息。
"""
import copy
result = copy.deepcopy(extracted_info)
for field_path, value in updated_fields.items():
parts = field_path.split(".")
current = result
for part in parts[:-1]:
if part not in current:
current[part] = {}
current = current[part]
current[parts[-1]] = value
log.info("更新字段 %s = %s", field_path, value)
return result