日常报销和差旅报销都可以走通
This commit is contained in:
@@ -26,6 +26,7 @@ from typing import Any, cast
|
||||
from .. import get_logger
|
||||
from .prompt import (
|
||||
build_invoice_system_prompt,
|
||||
build_normal_info_system_prompt,
|
||||
build_travel_info_system_prompt,
|
||||
)
|
||||
|
||||
@@ -218,9 +219,9 @@ def load_cache(source_dir: Path) -> dict[str, Any]:
|
||||
with open(json_path, encoding="utf-8") as f:
|
||||
cache_data = json.load(f)
|
||||
|
||||
# travel_info.json 结构不同,直接存储
|
||||
if json_path.name == "travel_info.json":
|
||||
cache_map["travel_info"] = cache_data
|
||||
# travel_info.json / normal_info.json 结构不同,直接存储
|
||||
if json_path.name in ("travel_info.json", "normal_info.json"):
|
||||
cache_map[json_path.name.replace(".json", "")] = cache_data
|
||||
continue
|
||||
|
||||
extracted = cache_data.get("extracted_data", {})
|
||||
@@ -324,3 +325,71 @@ def extract_travel_info(
|
||||
except Exception as e:
|
||||
log.error("LLM 差旅信息提取失败: %s", e)
|
||||
raise
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 普通发票信息提取
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
def extract_normal_info(
|
||||
source_dir: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""根据普通发票(非差旅),让 LLM 提取报销相关信息。
|
||||
|
||||
仅支持从 JSON 缓存加载数据。
|
||||
|
||||
Args:
|
||||
source_dir: 源文件目录(必填,包含 .invoice_cache 子目录)。
|
||||
|
||||
Returns:
|
||||
包含报销说明、发票总数、总金额、支付方式、附件清单等字段的字典。
|
||||
"""
|
||||
if not source_dir:
|
||||
log.warning("未提供 source_dir,无法加载缓存数据")
|
||||
return {}
|
||||
|
||||
system_prompt = build_normal_info_system_prompt()
|
||||
|
||||
# 构建 source filename -> 缓存数据的映射
|
||||
cache_map = load_cache(source_dir)
|
||||
|
||||
# 加载发票与支付记录的匹配结果
|
||||
match_result = load_match_result(source_dir)
|
||||
|
||||
# 拼接纯文本消息
|
||||
parts = [
|
||||
"以下是本次报销的所有源文件及其提取出的结构化数据。"
|
||||
"每个源文件的数据来自 OCR 识别和发票信息提取,已按文件名分组展示。"
|
||||
]
|
||||
|
||||
# 如果有匹配结果,作为额外上下文提供
|
||||
if match_result:
|
||||
parts.append(
|
||||
"【发票与支付记录匹配结果】"
|
||||
"以下数据已将发票信息与对应的支付记录进行关联匹配,"
|
||||
"用于判断每笔支付对应的发票和商户信息。\n" + json.dumps(match_result, ensure_ascii=False, indent=2)
|
||||
)
|
||||
|
||||
# 按源文件名提供结构化数据
|
||||
for filename, extracted in cache_map.items():
|
||||
parts.append(
|
||||
f"【源文件: {filename}】"
|
||||
"以下为从该文件提取的结构化发票/支付/申请单数据。\n" + json.dumps(extracted, ensure_ascii=False, indent=2)
|
||||
)
|
||||
|
||||
parts.append("\n=== 请返回 JSON 格式结果 ===")
|
||||
user_message = "\n".join(parts)
|
||||
log.info(f"user_message: {user_message}")
|
||||
try:
|
||||
response = _llm_query_multimodal(
|
||||
system_prompt=system_prompt,
|
||||
text=user_message,
|
||||
reasoning_effort="low",
|
||||
)
|
||||
result = _parse_json_response(response)
|
||||
log.info("LLM 普通发票信息提取成功")
|
||||
return result
|
||||
except Exception as e:
|
||||
log.error("LLM 普通发票信息提取失败: %s", e)
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user