feat: 读标补齐五类清单与项目基本信息,修复国动样本暴露的 4 个问题
- 文字层 v2:页眉页脚带单独成句;写到页尾的句子和下一页首句接续(出处两页各一条) - 结构识别(最小版):十进制编号、冒号引出的列表找上级条款;上级条款写明无效的,条目照样认定 - 抽取:资格、评分、日期与递交、技术参数、项目基本信息各一份提示词;实质性条款出 v2 (认上级条款、补「做无效响应处理」等写法);各类取值核对;按首句合并; 拆开被合成一条的列举条款;描述标注方式的句子和表头碎片不当条款;* 号标注 - 项目:解析出的名称、编号、采购人、预算、截止时间、分包写回项目,用户改过的不覆盖 - 前端:清单项显示分值、参数要求、日期、证明材料 - 测试 40 个,新增两页虚构样例 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -132,3 +132,41 @@ export function fmtSize(bytes: number): string {
|
||||
if (bytes < 1024 * 1024) return `${Math.max(1, Math.round(bytes / 1024))} KB`;
|
||||
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
||||
}
|
||||
|
||||
/* ---------- 清单项的结构化取值(ItemSpec,openapi.yaml):只把原文里有的值整理出来显示,不推测 ---------- */
|
||||
const PART: Record<string, string> = { price: "价格分", technical: "技术分", commercial: "商务分" };
|
||||
const QUAL_KIND: Record<string, string> = { general: "通用资格", specific: "特定资格", credit: "信用要求" };
|
||||
const OP: Record<string, string> = { ">=": "≥", "<=": "≤", "=": "=", contains: "包含", supports: "支持" };
|
||||
const DATE_KIND: Record<string, string> = {
|
||||
question_deadline: "提疑截止",
|
||||
bid_deadline: "投标截止",
|
||||
opening: "开标",
|
||||
deposit_deadline: "保证金截止",
|
||||
validity: "有效期",
|
||||
};
|
||||
const SUBMISSION: Record<string, string> = { electronic: "电子递交", paper: "纸质递交", ca_encrypted: "CA 加密", mixed: "电子 + 纸质" };
|
||||
|
||||
type Spec = Record<string, Record<string, unknown> | undefined>;
|
||||
const str = (v: unknown): string => (v === null || v === undefined ? "" : String(v));
|
||||
|
||||
export function specFacts(spec: unknown): string[] {
|
||||
const s = (spec ?? {}) as Spec;
|
||||
const out: string[] = [];
|
||||
const q = s.qualification;
|
||||
if (q && QUAL_KIND[str(q.kind)]) out.push(QUAL_KIND[str(q.kind)]!);
|
||||
const sc = s.scoring;
|
||||
if (sc) {
|
||||
if (sc.points) out.push(`分值 ${str(sc.points)}`);
|
||||
if (PART[str(sc.part)]) out.push(PART[str(sc.part)]!);
|
||||
}
|
||||
const t = s.tech_param;
|
||||
if (t && t.value) out.push([str(t.param), OP[str(t.op)] ?? "", `${str(t.value)}${str(t.unit)}`].filter(Boolean).join(" "));
|
||||
const d = s.schedule;
|
||||
if (d) {
|
||||
if (d.at) out.push(`${DATE_KIND[str(d.date_kind)] ?? "时间"} ${fmtDateTime(str(d.at))}`);
|
||||
else if (DATE_KIND[str(d.date_kind)]) out.push(DATE_KIND[str(d.date_kind)]!);
|
||||
if (d.deposit_amount) out.push(`保证金 ${str(d.deposit_amount)}`);
|
||||
if (SUBMISSION[str(d.submission_mode)]) out.push(SUBMISSION[str(d.submission_mode)]!);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user