refactor: 架构重组 — doc/bot → core/infra,新增 Agent 调度模块

- src/doc/ 拆分为 src/core/extraction/, matching/, validation/(核心业务逻辑)
- src/bot/ 重命名为 src/infra/browser/(浏览器自动化基础设施)
- fill_consumable_doc.py → src/infra/documents/consumable.py
- 新增 Agent 调度模块:coordinator.py, events.py, session.py,重构 orchestrator.py
- 更新 AGENTS.md、README.md 及所有子目录 README
This commit is contained in:
wandering
2026-07-02 18:36:19 +08:00
parent 7c137c5214
commit 1b35f07fd7
69 changed files with 2965 additions and 1548 deletions

View File

@@ -12,7 +12,7 @@ from typing import Any
import pytest
from src import exceptions
from src.doc.extractor import extract_invoices
from src.core.extraction import extract_invoices
# 字段键名(与源码中的字符串字面量保持一致)
K_INVOICE_TYPE = "invoice_type"
@@ -78,7 +78,7 @@ class TestExtractInvoices:
"""extract_invoices 编排函数"""
def test_empty_directory(self, tmp_path: Path, monkeypatch):
monkeypatch.setattr("src.doc.extractor._find_all_files", lambda d: [])
monkeypatch.setattr("src.core.extraction.extractor._find_all_files", lambda d: [])
records, apps, groups = extract_invoices(str(tmp_path))
assert records == []
@@ -89,8 +89,8 @@ class TestExtractInvoices:
pdf = tmp_path / "broken.pdf"
pdf.touch()
monkeypatch.setattr("src.doc.extractor._find_all_files", lambda d: [pdf])
monkeypatch.setattr("src.doc.extractor._extract_document", lambda p, c, s: (None, "parse error"))
monkeypatch.setattr("src.core.extraction.extractor._find_all_files", lambda d: [pdf])
monkeypatch.setattr("src.core.extraction.extractor._extract_document", lambda p, c, s: (None, "parse error"))
with pytest.raises(exceptions.ExtractionError) as exc_info:
extract_invoices(str(tmp_path))
@@ -107,16 +107,14 @@ class TestExtractInvoices:
inv1 = _make_invoice("INV001", 300.0, INVOICE_TYPE_GENERAL)
inv2 = _make_invoice("INV002", 200.0, INVOICE_TYPE_GENERAL)
monkeypatch.setattr("src.doc.extractor._find_all_files", lambda d: [pdf1, pdf2])
monkeypatch.setattr("src.core.extraction.extractor._find_all_files", lambda d: [pdf1, pdf2])
call_index = [0]
path_to_result = {pdf1: inv1, pdf2: inv2}
def fake_extract(path, cache_dir, source_dir):
idx = call_index[0]
call_index[0] += 1
return (inv1, None) if idx == 0 else (inv2, None)
return (path_to_result[path], None)
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
monkeypatch.setattr("src.core.extraction.extractor._extract_document", fake_extract)
def fake_match(invoices, cards):
return [
@@ -131,7 +129,7 @@ class TestExtractInvoices:
}
]
monkeypatch.setattr("src.doc.extractor.match_invoices_to_cards", fake_match)
monkeypatch.setattr("src.core.matching.matcher.match_invoices_to_cards", fake_match)
records, apps, groups = extract_invoices(str(tmp_path))
@@ -153,19 +151,17 @@ class TestExtractInvoices:
inv_general = _make_invoice("GEN001", 150.0, INVOICE_TYPE_GENERAL)
monkeypatch.setattr(
"src.doc.extractor._find_all_files",
"src.core.extraction.extractor._find_all_files",
lambda d: [pdf1, pdf2, pdf3],
)
invoices_list = [inv_train, inv_hotel, inv_general]
call_index = [0]
path_to_result = dict(zip([pdf1, pdf2, pdf3], invoices_list, strict=True))
def fake_extract(path, cache_dir, source_dir):
idx = call_index[0]
call_index[0] += 1
return (invoices_list[idx], None)
return (path_to_result[path], None)
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
monkeypatch.setattr("src.core.extraction.extractor._extract_document", fake_extract)
def fake_match(invoices, cards):
return [
@@ -198,7 +194,7 @@ class TestExtractInvoices:
},
]
monkeypatch.setattr("src.doc.extractor.match_invoices_to_cards", fake_match)
monkeypatch.setattr("src.core.matching.matcher.match_invoices_to_cards", fake_match)
records, apps, groups = extract_invoices(str(tmp_path))
@@ -221,19 +217,16 @@ class TestExtractInvoices:
app = _make_application()
monkeypatch.setattr(
"src.doc.extractor._find_all_files",
"src.core.extraction.extractor._find_all_files",
lambda d: [pdf1, pdf2],
)
results = [inv, app]
call_index = [0]
path_to_result = {pdf1: inv, pdf2: app}
def fake_extract(path, cache_dir, source_dir):
idx = call_index[0]
call_index[0] += 1
return (results[idx], None)
return (path_to_result[path], None)
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
monkeypatch.setattr("src.core.extraction.extractor._extract_document", fake_extract)
def fake_match(invoices, cards):
return [
@@ -248,7 +241,7 @@ class TestExtractInvoices:
}
]
monkeypatch.setattr("src.doc.extractor.match_invoices_to_cards", fake_match)
monkeypatch.setattr("src.core.matching.matcher.match_invoices_to_cards", fake_match)
records, apps, groups = extract_invoices(str(tmp_path))
@@ -266,19 +259,16 @@ class TestExtractInvoices:
card = _make_card(300.0)
monkeypatch.setattr(
"src.doc.extractor._find_all_files",
"src.core.extraction.extractor._find_all_files",
lambda d: [pdf1, pdf2],
)
results = [inv, card]
call_index = [0]
path_to_result = {pdf1: inv, pdf2: card}
def fake_extract(path, cache_dir, source_dir):
idx = call_index[0]
call_index[0] += 1
return (results[idx], None)
return (path_to_result[path], None)
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
monkeypatch.setattr("src.core.extraction.extractor._extract_document", fake_extract)
def fake_match(invoices, cards):
return [
@@ -293,7 +283,7 @@ class TestExtractInvoices:
}
]
monkeypatch.setattr("src.doc.extractor.match_invoices_to_cards", fake_match)
monkeypatch.setattr("src.core.matching.matcher.match_invoices_to_cards", fake_match)
records, apps, groups = extract_invoices(str(tmp_path))
@@ -309,19 +299,17 @@ class TestExtractInvoices:
inv = _make_invoice("INV001", 300.0, INVOICE_TYPE_GENERAL)
monkeypatch.setattr(
"src.doc.extractor._find_all_files",
"src.core.extraction.extractor._find_all_files",
lambda d: [pdf1, pdf2],
)
results = [inv, None]
call_index = [0]
path_to_result = {pdf1: inv, pdf2: None}
def fake_extract(path, cache_dir, source_dir):
idx = call_index[0]
call_index[0] += 1
return (results[idx], "parse error") if results[idx] is None else (results[idx], None)
result = path_to_result[path]
return (result, "parse error") if result is None else (result, None)
monkeypatch.setattr("src.doc.extractor._extract_document", fake_extract)
monkeypatch.setattr("src.core.extraction.extractor._extract_document", fake_extract)
def fake_match(invoices, cards):
return [
@@ -336,7 +324,7 @@ class TestExtractInvoices:
}
]
monkeypatch.setattr("src.doc.extractor.match_invoices_to_cards", fake_match)
monkeypatch.setattr("src.core.matching.matcher.match_invoices_to_cards", fake_match)
records, apps, groups = extract_invoices(str(tmp_path))