refactor!: 删除 Web/CLI 应用层与内置 LLM 抽取,出库单功能下线(2b)
入口只剩 MCP 服务器;编排由宿主 Agent 负责,本项目只留工具与确定性内核。
删除:
- src/web/(Flask 路由、SSE 轮询、自研聊天前端、模板与静态资源,约 3400 行)
- src/main.py、src/pipeline.py、src/pipeline_core.py(CLI 全流程入口与两套重复管道)
- core/extraction/{extractor,llm_extractor}.py(内置 LLM 抽取、llm_stream.log、file_events.log、并行抽取)
- infra/documents/consumable.py 与 infra/documents/pdf.py:出库单功能下线(Word 模板 4fbb4c3 起已不在仓库,
该路径此前一直静默失败),PDF 渲染由 core/extraction/render.py 取代
- mcp__arb__doc_consumable 工具;exceptions.ExtractionError;config 的 consumable_storage / get_llm_config /
load_session_config / SESSION_CONFIG_KEYS(Web 专属,已无引用)
- 针对被删代码的 tests/test_extractor.py、tests/test_llm_extractor.py 与 scripts/ 下的 LLM 调试脚本
- 依赖:llama-index、llama-index-llms-openai-like、python-dotenv(连同其 50+ 传递依赖)
- 提交进来的调试截图 src/images/、根目录 images/ 与 .coverage(并补 .gitignore)
保留与新增:
- 材料入口改为独立进程 src/upload(手机扫码/PC 上传 → cases/<id>/inbox/)
- runner.py 自带 save_invoice_groups,不再依赖 pipeline_core
- scripts/mcp_smoke.py:stdio 自检(拉起自身、列工具、调 case_list、验证 instructions 下发)
- make mcp / mcp-smoke / upload 取代 make run;check 的 mypy 目标从 src/main.py 扩到 src
验证:mcp_smoke 通过(17 个工具、instructions 1449 字节、case_list 正常);申购单实机生成此前已验证。
门禁:ruff check / format --check(43) / mypy src(36 文件) / deptry / pytest 107 passed。
注:仍用 --no-verify 提交并手动跑等价检查(原因见 2f08bbd 提交说明)。
This commit is contained in:
+2
-3
@@ -33,8 +33,8 @@ INSTRUCTIONS = """财务报销自动化工具集(发票抽取交接 → 匹配
|
||||
或用 mcp__arb__validate_info(draft=...) 不落盘反复试。不完整就向用户要补充材料,禁止自己宣布可提交。
|
||||
拼 JSON 前先 mcp__arb__info_skeleton(info_type) 取骨架:required 为 true 的键必须存在(含值为空串的备注类
|
||||
字段),骨架与 validation_rules.json 同源,别凭记忆造结构。
|
||||
6. 普通发票用 mcp__arb__doc_consumable 生成 Word 出库单、mcp__arb__doc_requisition 生成 Excel 申购单
|
||||
(COM 自动化,需本机装有 Word/Excel;纯差旅会返回 skipped,不是错误)。
|
||||
6. 普通发票用 mcp__arb__doc_requisition 生成 Excel 申购单(COM 自动化,需本机装有 Excel;
|
||||
exclude 可剔除不参与申购的物品;纯差旅没有申购明细会返回失败提示,不是错误)。
|
||||
人工核对后要改单张票据的某个字段,用 mcp__arb__case_patch_extraction(只传要改的键,会回显 from/to)。
|
||||
7. 每步之后用 mcp__arb__case_status 复查态势;阶段由产物推导,没有内部状态机。
|
||||
mcp__arb__case_reset(scope) 可清派生产物重跑;mcp__arb__case_list 看全部会话。
|
||||
@@ -62,7 +62,6 @@ TOOLS: list[Callable[..., dict[str, Any]]] = [
|
||||
analysis.validate_info,
|
||||
analysis.rules_get,
|
||||
analysis.info_skeleton,
|
||||
documents.doc_consumable,
|
||||
documents.doc_requisition,
|
||||
]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Word 出库单与 Excel 申购单生成工具
|
||||
"""Excel 申购单生成工具(Word 出库单已随模板下线删除)
|
||||
|
||||
都是 COM 自动化,依赖 Windows + Microsoft Office;统一走 src.infra.com_thread
|
||||
的单线程 actor,避免两个工具调用同时驱动 Word/Excel。
|
||||
COM 自动化,依赖 Windows + Microsoft Excel;统一走 src.infra.com_thread 的单线程 actor,
|
||||
避免多个调用同时驱动 Office。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -10,68 +10,13 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from ...cases import ARTIFACTS_DIR_NAME, CACHE_DIR_NAME, PROJECT_ROOT, CaseStore
|
||||
from ...config import SESSION_CONFIG_KEYS, load_config
|
||||
from ...infra.com_thread import run_com
|
||||
from ...infra.documents import (
|
||||
CONSUMABLE_DOC_FILENAME,
|
||||
REQUISITION_FILENAME,
|
||||
fill_consumable_from_template,
|
||||
generate_requisition,
|
||||
load_requisition_items,
|
||||
)
|
||||
from ...infra.documents import REQUISITION_FILENAME, generate_requisition, load_requisition_items
|
||||
from ..envelope import fail, ok
|
||||
|
||||
_store = CaseStore()
|
||||
|
||||
|
||||
def _case_config(d: Path) -> dict[str, Any]:
|
||||
"""项目配置 + 会话目录里 config.json 的用户字段覆盖。"""
|
||||
config = load_config()
|
||||
cfg_path = d / "config.json"
|
||||
if cfg_path.exists():
|
||||
import json
|
||||
|
||||
try:
|
||||
raw: dict[str, Any] = json.loads(cfg_path.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
raw = {}
|
||||
for key in SESSION_CONFIG_KEYS:
|
||||
if key in raw:
|
||||
config[key] = raw[key]
|
||||
return config
|
||||
|
||||
|
||||
def doc_consumable(case_id: str, output_name: str | None = None) -> dict[str, Any]:
|
||||
"""生成易耗品出库单(Word,仅普通发票需要)。
|
||||
|
||||
取会话里的 payment_records.csv 填入项目根目录模板的副本,输出到
|
||||
cases/<id>/artifacts/。纯差旅发票会返回 skipped,不是错误。
|
||||
需要 Windows + 已安装 Microsoft Word。
|
||||
"""
|
||||
d = _store.resolve(case_id)
|
||||
if d is None:
|
||||
return fail(f"会话不存在: {case_id}")
|
||||
csv_path = d / "payment_records.csv"
|
||||
if not csv_path.exists():
|
||||
return fail("缺少 payment_records.csv", next_action="先 mcp__arb__match_payments 生成汇总")
|
||||
groups = _groups(d)
|
||||
if groups is not None and not groups.get("general_count", 0):
|
||||
return ok(skipped=True, reason="本会话没有普通发票(纯差旅),不需要易耗品出库单")
|
||||
template = PROJECT_ROOT / CONSUMABLE_DOC_FILENAME
|
||||
if not template.exists():
|
||||
return fail(f"出库单模板不存在: {template}", next_action="把模板放回项目根目录")
|
||||
out = d / ARTIFACTS_DIR_NAME / (output_name or CONSUMABLE_DOC_FILENAME)
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
config = _case_config(d)
|
||||
try:
|
||||
run_com(fill_consumable_from_template, csv_path, template, out, config=config)
|
||||
except ImportError:
|
||||
return fail("缺少 pywin32,无法驱动 Word", next_action="uv sync 安装项目依赖", needs="pywin32")
|
||||
except Exception as e:
|
||||
return fail(f"生成出库单失败: {e}", next_action="检查 Word 是否被其他实例占用或有弹窗未关闭", doc=str(out))
|
||||
return ok(doc=str(out), filename=out.name, bytes=out.stat().st_size, skipped=False)
|
||||
|
||||
|
||||
def doc_requisition(case_id: str, exclude: list[str] | None = None, project: str | None = None) -> dict[str, Any]:
|
||||
"""生成低值易耗品申购单(Excel,仅普通发票)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user