实现Agent对话,合格自动提交,不合格补充材料的能力
This commit is contained in:
@@ -9,6 +9,9 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from src import exceptions
|
||||
from src.doc.extractor import extract_invoices
|
||||
|
||||
# 字段键名(与源码中的字符串字面量保持一致)
|
||||
@@ -87,12 +90,13 @@ class TestExtractInvoices:
|
||||
pdf.touch()
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._find_all_files", lambda d: [pdf])
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", lambda p, c: None)
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", lambda p, c, s: (None, "parse error"))
|
||||
|
||||
records, apps, groups = extract_invoices(str(tmp_path))
|
||||
assert records == []
|
||||
assert apps == []
|
||||
assert groups == {"travel": [], "general": [], "application": []}
|
||||
with pytest.raises(exceptions.ExtractionError) as exc_info:
|
||||
extract_invoices(str(tmp_path))
|
||||
|
||||
assert "broken.pdf" in exc_info.value.failed_files
|
||||
assert exc_info.value.details["broken.pdf"] == "parse error"
|
||||
|
||||
def test_normal_flow_general_invoices(self, tmp_path: Path, monkeypatch):
|
||||
pdf1 = tmp_path / "inv1.pdf"
|
||||
@@ -107,10 +111,10 @@ class TestExtractInvoices:
|
||||
|
||||
call_index = [0]
|
||||
|
||||
def fake_extract(path, cache_dir):
|
||||
def fake_extract(path, cache_dir, source_dir):
|
||||
idx = call_index[0]
|
||||
call_index[0] += 1
|
||||
return inv1 if idx == 0 else inv2
|
||||
return (inv1, None) if idx == 0 else (inv2, None)
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
|
||||
|
||||
@@ -156,10 +160,10 @@ class TestExtractInvoices:
|
||||
invoices_list = [inv_train, inv_hotel, inv_general]
|
||||
call_index = [0]
|
||||
|
||||
def fake_extract(path, cache_dir):
|
||||
def fake_extract(path, cache_dir, source_dir):
|
||||
idx = call_index[0]
|
||||
call_index[0] += 1
|
||||
return invoices_list[idx]
|
||||
return (invoices_list[idx], None)
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
|
||||
|
||||
@@ -224,10 +228,10 @@ class TestExtractInvoices:
|
||||
results = [inv, app]
|
||||
call_index = [0]
|
||||
|
||||
def fake_extract(path, cache_dir):
|
||||
def fake_extract(path, cache_dir, source_dir):
|
||||
idx = call_index[0]
|
||||
call_index[0] += 1
|
||||
return results[idx]
|
||||
return (results[idx], None)
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
|
||||
|
||||
@@ -269,10 +273,10 @@ class TestExtractInvoices:
|
||||
results = [inv, card]
|
||||
call_index = [0]
|
||||
|
||||
def fake_extract(path, cache_dir):
|
||||
def fake_extract(path, cache_dir, source_dir):
|
||||
idx = call_index[0]
|
||||
call_index[0] += 1
|
||||
return results[idx]
|
||||
return (results[idx], None)
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
|
||||
|
||||
@@ -312,10 +316,10 @@ class TestExtractInvoices:
|
||||
results = [inv, None]
|
||||
call_index = [0]
|
||||
|
||||
def fake_extract(path, cache_dir):
|
||||
def fake_extract(path, cache_dir, source_dir):
|
||||
idx = call_index[0]
|
||||
call_index[0] += 1
|
||||
return results[idx]
|
||||
return (results[idx], "parse error") if results[idx] is None else (results[idx], None)
|
||||
|
||||
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
from src.doc.invoice import (
|
||||
INVOICE_LEVEL_COLUMNS,
|
||||
PAYMENT_RECORD_COLUMNS,
|
||||
)
|
||||
from src.doc.invoice import (
|
||||
_classify_invoice_batch as classify_invoice_batch,
|
||||
classify_invoice_batch,
|
||||
)
|
||||
|
||||
# 字段键名与发票类型(与源码中的字符串字面量保持一致)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""LLM 信息提取模块单元测试
|
||||
|
||||
覆盖范围:
|
||||
- _parse_json_response:纯 JSON、Markdown 包裹、带前缀、解析失败
|
||||
- `parse_json_response`:纯 JSON、Markdown 包裹、带前缀、解析失败
|
||||
- _image_to_base64:图片转 base64
|
||||
- extract_document:成功提取、LLM 失败
|
||||
"""
|
||||
@@ -16,8 +16,8 @@ import pytest
|
||||
|
||||
from src.doc.llm_extractor import (
|
||||
_image_to_base64,
|
||||
_parse_json_response,
|
||||
extract_document,
|
||||
parse_json_response,
|
||||
)
|
||||
|
||||
# 字段键名(与源码中的字符串字面量保持一致)
|
||||
@@ -28,7 +28,7 @@ K_CARD_NO = "card_no"
|
||||
K_CARD_AMOUNT = "card_amount"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# _parse_json_response
|
||||
# parse_json_response
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -37,47 +37,47 @@ class TestParseJsonResponse:
|
||||
|
||||
def test_pure_json(self):
|
||||
raw = json.dumps({K_INVOICE_NUMBER: "123456", K_TOTAL_AMOUNT: "100.00"})
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result[K_INVOICE_NUMBER] == "123456"
|
||||
assert result[K_TOTAL_AMOUNT] == "100.00"
|
||||
|
||||
def test_markdown_json_block(self):
|
||||
raw = f'```json\n{{"{K_INVOICE_NUMBER}": "789"}}\n```'
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result[K_INVOICE_NUMBER] == "789"
|
||||
|
||||
def test_markdown_block_without_lang(self):
|
||||
raw = '```\n{"key": "value"}\n```'
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result["key"] == "value"
|
||||
|
||||
def test_json_prefix(self):
|
||||
raw = f'json\n{{"{K_INVOICE_NUMBER}": "001"}}'
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result[K_INVOICE_NUMBER] == "001"
|
||||
|
||||
def test_json_prefix_with_whitespace(self):
|
||||
raw = ' json \n{"a": 1}'
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result["a"] == 1
|
||||
|
||||
def test_nested_json(self):
|
||||
raw = json.dumps({"outer": {"inner": [1, 2, 3]}})
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result["outer"]["inner"] == [1, 2, 3]
|
||||
|
||||
def test_whitespace_around_json(self):
|
||||
raw = ' \n {"x": 42} \n '
|
||||
result = _parse_json_response(raw)
|
||||
result = parse_json_response(raw)
|
||||
assert result["x"] == 42
|
||||
|
||||
def test_invalid_json_raises(self):
|
||||
with pytest.raises(ValueError):
|
||||
_parse_json_response("not json at all")
|
||||
parse_json_response("not json at all")
|
||||
|
||||
def test_empty_string_raises(self):
|
||||
with pytest.raises(ValueError):
|
||||
_parse_json_response("")
|
||||
parse_json_response("")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user