feat(check): 规则检查(报价形式、形式要件、响应表),表格按单元格分行
- check/rules.py(规则集 2026.11-r1,不调模型):大小写金额、分项合计、超最高限价、 多个报价、别的项目名称、没填的地方、落款日期、投标有效期、附加条件、响应表里的未响应; 每条挂投标原文,有依据的挂招标侧出处;缺限价、截止时间、有效期要求时写进覆盖范围 - 文字层的句子带上单元格框,表格按单元格上沿分行 - 按 Fable 审读意见收紧致命级:认不准的降为重要或提示 - 评测:score.py 评规则问题;P07 注入记录改为空白处前后原文,剔除注入到人员表的 D10 - 上传页的检查范围文案同步 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,7 @@ class Sentence:
|
||||
fmt_runs: list[tuple[int, int, str]] = field(default_factory=list) # [起, 止, 格式],格式取 b / i / u 的组合
|
||||
location: str = "body"
|
||||
open_end: bool = False # 写到页面末尾还没结束(没有句末标点、末行写满),可能接续到下一页
|
||||
cell: list[float] | None = None # 在有框线的表格里:所在单元格 [x0, top, x1, bottom](查标按单元格分行)
|
||||
|
||||
@property
|
||||
def marked(self) -> str:
|
||||
@@ -83,6 +84,7 @@ class Sentence:
|
||||
"format_runs": [list(r) for r in self.fmt_runs],
|
||||
"location": self.location,
|
||||
"open_end": self.open_end,
|
||||
**({"cell": self.cell} if self.cell else {}),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -96,6 +98,7 @@ class Sentence:
|
||||
fmt_runs=[(a, b, f) for a, b, f in d["format_runs"]],
|
||||
location=d["location"],
|
||||
open_end=d.get("open_end", False),
|
||||
cell=d.get("cell"),
|
||||
)
|
||||
|
||||
|
||||
@@ -150,6 +153,7 @@ Cell = tuple[float, float, float, float] # 单元格 (x0, top, x1, bottom)
|
||||
class FragInfo:
|
||||
right: float | None = None # 单元格的右边界:判断段落末行用它,不用页面右边距
|
||||
cell_end: bool = False # 单元格的最后一个片段:句子在这里结束
|
||||
cell: Cell | None = None
|
||||
|
||||
|
||||
def _cell_of(c: dict[str, Any], cells: list[Cell]) -> int | None:
|
||||
@@ -171,13 +175,13 @@ def _fragments(
|
||||
for i, cell_chars in by_cell.items():
|
||||
assert i is not None
|
||||
x0, top, x1, _ = cells[i]
|
||||
blocks.append(((top, x0), _line_fragments(cell_chars), FragInfo(right=x1)))
|
||||
blocks.append(((top, x0), _line_fragments(cell_chars), FragInfo(right=x1, cell=cells[i])))
|
||||
frags: list[list[dict[str, Any]]] = []
|
||||
infos: list[FragInfo] = []
|
||||
for _, fs, info in sorted(blocks, key=lambda b: b[0]):
|
||||
for j, f in enumerate(fs):
|
||||
frags.append(f)
|
||||
infos.append(FragInfo(right=info.right, cell_end=j == len(fs) - 1) if info else FragInfo())
|
||||
infos.append(FragInfo(right=info.right, cell_end=j == len(fs) - 1, cell=info.cell) if info else FragInfo())
|
||||
return frags, infos
|
||||
|
||||
|
||||
@@ -310,6 +314,7 @@ def _page(doc_id: str, page: Any, frags: list[list[dict[str, Any]]], infos: list
|
||||
fmt_runs=runs,
|
||||
location=location,
|
||||
open_end=seq == tail_seq,
|
||||
cell=[round(v, 2) for v in cell] if (cell := infos[g[0][0]].cell) and location == "body" else None,
|
||||
)
|
||||
)
|
||||
return Page(
|
||||
|
||||
Reference in New Issue
Block a user