| name | bid-template-fill |
| description | 投标书模板填充引擎。当用户明确要求「填模板」「写标书」「出标书」「生成投标文件」「标书填充」「套模板」「做标书」,或提供了脱敏 DOCX 模板需要填充时使用。扫描模板中的占位符和虚拟文本,提取招标信息、收集投标人数据、构建替换映射、执行填充,输出可直接提交的成品标书。覆盖商务标+技术标+报价书全部章节。 |
| trigger_keywords | ["填模板","写标书","投标","出标书","生成投标文件","标书填充"] |
标书模板填充 SKILL
概述
将脱敏 DOCX 模板填充为可提交的投标文件。覆盖设备采购类投标的商务标 + 技术标 + 报价书全部章节。
智能提取流程(新增 v2.3)
技能现在支持直接读取公司信息 DOCX 和招标 PDF/DOCX,自动提取并映射到模板:
公司信息.docx ──→ scripts/extract_company.py ──→ company.json(自动映射脱敏Key) 招标文件.pdf ──→ scripts/extract_bid.py ──→ 招标方结构化数据 ↓ scripts/bid_pipeline.py ──→ 合并+填充 ──→ 成品标书.docx
一键命令:
python scripts/bid_pipeline.py 招标文件.pdf --company-docx 公司信息.docx --templates-dir ./模板/
**输出文件夹:**生成的标书文件默认保存在招标文件同目录下的 成品标书/ 子文件夹中,文件命名格式:标书类型_项目名.docx。可通过 --output-dir 自定义。
分步使用:
python scripts/extract_company.py 公司信息.docx -o company.json
python scripts/extract_bid.py 招标文件.pdf --print
python scripts/bid_pipeline.py 招标文件.md --company-json company.json
首次使用:编辑 desensitize_map.json,将 template_desensitize_map 中的虚拟文本改为你模板中实际出现的脱敏名。也可通过 --map 指定自定义映射文件:python scripts/extract_company.py 公司信息.docx --map my_map.json
环境要求
- Python 方式(推荐):Python 3.7+,安装
python-docx:pip install python-docx
- Node.js 方式(零依赖备选,仅 Windows):Node.js 16+
- 管道方式:Python 3.7+,
python-docx,模板需按约定命名
工作流
步骤1: 读取招标文件 → 提取招标方信息
步骤2: 扫描脱敏模板 → 发现占位符与脱敏文本
步骤3: 收集投标人信息 → 向用户询问必要数据
步骤4: 构建替换数据 → 映射数据到占位符
步骤5: 执行填充 → 调用 scripts/fill_py.py 或 scripts/fill_template.js
步骤6: 验证输出 → 检查遗漏占位符
步骤1: 读取招标文件,提取招标方信息
读取招标文件(PDF 或 Markdown/Word),提取并保存为结构化数据:
| 提取项 | 常见模板占位符 | 用途 |
|---|
| 项目名称 | [项目名称]、_[项目名称]_ | 保证金表、页眉 |
| 招标编号 | _[招标编号]_、[招标编号] | 投标函、授权书、保证金表 |
| 招标方名称 | _[招标方名称]_、[招标方名称] | 投标函抬头 |
| 招标代理名称 | _[招标代理名称]_、[招标代理名称] | 投标函抬头、保证金表抬头 |
| 投标有效期天数 | 【 30 】 | 投标函第4款 |
| 投标保证金金额 | 脱敏金额文本 | 保证金表 |
| 付款方式/质保期/交货期 | — | 差异表 |
| 是否接受联合体/分包 | — | 投标函 |
| 需何种认证 | _[认证承诺]_ | 投标函第12款 |
| 标段名称 | (标段1名称) | 报价总表 |
如招标文件为 PDF,使用可用的 PDF 读取工具提取文本。如已有解析好的 Markdown,可直接用 scripts/bid_pipeline.py 自动提取。
步骤2: 扫描脱敏模板,发现占位符
脱敏模板中需要替换的内容分三类:
2.1 通用占位符(三套格式)
模板中可能同时存在以下格式的占位符,全部需要替换:
| 格式 | 示例 |
|---|
_[xxx]_ 双下划线 | _[招标方名称]_、_[招标编号]_ |
[xxx] 纯方括号 | [招标方名称]、[项目名称] |
(xxx) 中文全角括号 | (标段1名称) |
操作:解包模板扫描所有占位符:
Add-Type -AssemblyName System.IO.Compression.FileSystem
$tmp = "$env:TEMP\scan_tmpl"
[System.IO.Compression.ZipFile]::ExtractToDirectory("模板.docx", $tmp)
Get-ChildItem -Recurse $tmp -Filter *.xml | ForEach-Object {
$txt = Get-Content $_.FullName -Raw
[regex]::Matches($txt, `'_[^_]+_`') | % { $_.Value }
[regex]::Matches($txt, `'\[[^\]]+\]`') | % { $_.Value }
[regex]::Matches($txt, `'([^)]+)`') | % { $_.Value }
} | Sort-Object -Unique
2.2 脱敏文本(公司特定字符串)
脱敏模板中的敏感信息已被替换为虚拟文本。常见模式:
- 公司全称 →
XX重工股份有限公司
- 公司简称 →
XX重工
- 法人姓名 →
金红萍
- 授权代表 →
沈小芳
- 地址 →
[公司地址]、江苏省 苏州市
- 银行信息 →
[开户银行名称]、[银行账号]
- 联系方式 →
[电话已脱敏]、[手机已脱敏] 等
- 金额占位 →
【 随机金额万美元 ... 】
操作:阅读 word/document.xml 和 word/header*.xml,找出上述模式的文本。
2.3 日期处理(自动,无需手动配键)
日期由引擎自动处理,不需要在 JSON 中配置。
处理顺序:阶段1先替换日期 → 阶段2再替换占位符。日期优先处理避免占位符值干扰日期匹配。
引擎通过三套正则覆盖所有日期变体,自动替换为当天实时日期:
| 正则 | 覆盖格式 | 示例 |
|---|
| 完整日期(含下划线/空格分隔) | 2014年7月29日、__2014__年__7__月__29__日 | |
| 有年份无月日数字 | 2014年 月 日、__2014__年_____月_____日 | |
| 无年份的月日占位 | 年 月 日 | |
日期始终替换为当天(YYYY年MM月DD日),当日日期自动跳过。如招标文件有特定截止日期要求,在 pipeline 解析时会保留。
⚠️ 不要在 JSON 中添加日期碎片键(如 "2014"、"7月"、"29日" 等),这会导致与正则替换冲突产生乱码。
2.4 构建占位符清单
汇总为表格,标注每项的数据来源:
| 原文(模板中) | 类型 | 需填入 | 来源 |
|---|
_[招标方名称]_ | 占位符 | 招标方全称 | 步骤1 |
[招标编号] | 占位符 | 招标编号 | 步骤1 |
XX重工股份有限公司 | 脱敏文本 | 投标人全称 | 步骤3 |
金红萍 | 脱敏文本 | 法人姓名 | 步骤3 |
【 30 】 | 脱敏文本 | 投标有效期 | 步骤1 |
【 随机金额... 】 | 脱敏文本 | 实际报价金额 | 步骤3 |
日期 2014年7月29日 | 自动替换 | 今天日期 | 引擎 |
步骤3: 收集投标人信息
向用户逐项询问。严禁编造:
1. 投标人全称(营业执照名称):
2. 投标人简称:
3. 统一社会信用代码:
4. 法定代表人姓名:
5. 授权代表姓名:
6. 注册地址、邮编:
7. 开户银行全称、账号:
8. 联系人姓名、电话、手机、传真:
9. 报价总价(大写+小写):
10. 近3年类似项目业绩:
11. 持有资质证书清单:
12. 设备主要技术参数:
报价金额必须由用户确认,绝不自行决定。
步骤4: 构建替换数据
将步骤1-3 的数据映射为 JSON。
规则
- 占位符原文作为 JSON key,实际数据作为 value
- 不要包含日期碎片键(日期由引擎自动处理)
- 公司名全称 + 简称两个键都要配
- 不需要手动 XML 转义,引擎自动处理
快速开始:最小可用的 basic.json
将下方保存为 basic.json,替换【】内容为实际数据:
{
"_[招标方名称]_": "【招标方全称】",
"[招标方名称]": "【招标方全称】",
"_[招标编号]_": "【招标编号】",
"[招标编号]": "【招标编号】",
"_[招标代理名称]_": "【招标代理全称】",
"[招标代理名称]": "【招标代理全称】",
"[项目名称]": "【项目全称】",
"(标段1名称)": "【标段1名称】",
"(标段2名称)": "【标段2名称】",
"(标段3名称)": "【标段3名称】",
"【 30 】": "【 90 】",
"XX重工股份有限公司": "【你的公司全称】",
"XX重工": "【你的公司简称】",
"金红萍": "【法定代表人】",
"沈小芳":
> **金额空白占位符**:模板中金额可能显示为仅有空格无数字(如 `¥ 元`),需在 JSON 中精确匹配替换。扫描模板中所有 `¥` 或 `大写` 附近文本,确保 JSON 覆盖所有空白金额模式。
> **页眉页脚**:引擎会自动修补 python-docx 可能遗漏的非默认页眉类型(header1//xml 等),确保页眉中的占位符也被替换。
日期不需要配置,引擎自动将所有旧日期替换为当天实时日期。
JSON 模板示例
{
"_[招标方名称]_": "华能国际电力股份有限公司",
"[招标方名称]": "华能国际电力股份有限公司",
"_[招标编号]_": "HNZB2026-00123",
"[招标编号]": "HNZB2026-00123",
"_[招标代理名称]_": "华能招标有限公司",
"[招标代理名称]": "华能招标有限公司",
"[项目名称]": "华能XX电厂锅炉设备采购",
"XX重工股份有限公司": "大连华锐重工集团股份有限公司",
"XX重工": "大连重工",
"金红萍": "张三",
"沈小芳": "李四",
"[公司地址]": "辽宁省大连市西岗区八一路169号",
"[开户银行名称]": "中国工商银行大连分行",
"[银行账号]": "3400200123456789012",
"[电话已脱敏]"
特殊值处理
| 类型 | 规则 | 示例 |
|---|
| 大写金额 | 用户提供,不自行转换 | "捌佰伍拾陆万元整" |
| 认证承诺 | 根据招标文件要求撰写 | "我单位承诺在收到中标通知书后6个月内..." |
| 公司名称 | 全称+简称都要配 | 页眉可能只有简称 |
| 随机金额 | 整串文本匹配替换 | 不是占位符,是脱敏示例文本 |
| 日期 | 不要在JSON中配置,引擎自动处理 | — |
步骤5: 执行填充
> 大文件处理:模板 >5MB 时自动使用 fill_large 纯 Python zipfile 引擎,零外部依赖,同样支持日期优先 + 占位符后处理。
方式 A:Python(推荐)
python scripts/fill_py.py <模板.docx> <输出.docx> <替换数据.json>
两阶段引擎:先占位符替换,再整日期替换。自动报告遗漏占位符。
⚠️ 格式注意:当占位符跨多个 Word run 时,引擎会按比例将替换文本分配回各 run,保留原有加粗/斜体等格式属性。若替换文本长度与原占位符差异较大,可能导致文字在不同格式 run 间重新分配,但不会丢失格式定义。
页眉页脚处理:python-docx 只能访问默认页眉。引擎保存后会额外解包 DOCX,直接修补 header*.xml 和 footer*.xml 中遗漏的占位符和日期。
方式 B:Node.js(零依赖,仅 Windows)
node scripts/fill_template.js <模板.docx> <输出.docx> <替换数据.json>
同两阶段策略,额外自动检查遗漏占位符。依赖 PowerShell 进行 ZIP 操作,不支持 macOS/Linux。
方式 C:管道一键生成
python scripts/bid_pipeline.py 招标文件.md [--company-json 公司数据.json] [--templates 模板1.docx 模板2.docx ...]
自动完成步骤1→4→5,从招标文件 Markdown 到成品标书。
成品文件默认输出到招标文件同目录下的 成品标书/ 子文件夹。文件命名格式: 标书类型_项目名称.docx。
- 默认查找模板目录下
*脱敏*.docx 文件
- 可通过
--templates 显式指定模板列表
--company-json 指定公司脱敏数据(格式同步骤4中的公司部分)
- 大文件(>5MB)自动切换纯 Python zipfile 引擎,跨平台兼容
步骤6: 验证输出
填充完成后自动运行 scripts/verify_bid.py 进行二次核对:
python scripts/bid_pipeline.py 招标文件.pdf --company-docx 公司信息.docx
python scripts/verify_bid.py 成品标书.docx --company-docx 公司信息.docx
python scripts/bid_pipeline.py 招标文件.md --company-json company.json --no-verify
检查等级:
| 等级 | 检查项 | 示例 |
|---|
| P0 致命 | 遗漏占位符、日期未更新、公司名不一致 | [招标编号] 未替换 |
| P1 严重 | 关键字段为空、疑似乱码、金额不一致 | 投标报价字段空白 |
| P2 提示 | 空白方括号、签名区提醒、异常标点 | 【 】 未填充 |
手动补充检查:
- 投标函抬头、授权书姓名、保证金账户
- 报价总表金额、签名区
- 页眉页脚信息
故障排除
| 问题 | 可能原因 | 解决方案 |
|---|
| 占位符未被替换 | JSON 中的 key 与模板中的文本不完全一致 | 检查空格、全角/半角字符 |
| 日期没有被替换 | 日期格式不匹配正则 | 确保日期为"YYYY年MM月DD日"格式 |
scripts/fill_py.py 报 ModuleNotFoundError | 未安装 python-docx | pip install python-docx |
scripts/fill_template.js 报错 | 非 Windows 系统 | 改用 Python 方式 |
| 输出文件格式错乱 | 模板中的复杂格式 | 参见步骤5的格式警告 |
| 保证金表格金额为空 | 模板金额为空白占位符(¥ 元) | 在 JSON 中精确匹配该空白模式 |
| 页眉未更新 | 模板使用了非默认页眉类型 | 引擎已自动处理,无需手动干预 |
| 模板未找到 | 命名不符合约定 | 使用 --templates 显式指定 |
严禁事项
- 绝不编造业绩、资质、人员、报价等任何信息
- 绝不跳过招标文件要求的任何附件
- 报价金额必须经用户确认
- 模板中已有的标准条款结构不要修改,只替换变量
- 不要在 JSON 中配置日期碎片键,日期由引擎自动整日期替换