微信扫码
添加专属顾问
AI助力标书制作,告别繁琐格式调整,让投标人重获自由! 核心内容: 1. 标书制作的痛点:格式调整与图片插入的繁琐流程 2. AI解决方案:智能解析招标文件,自动提取并精准插入附件 3. 实践案例:知识库管理与企业资质图片的自动化处理
"投标人员的时间守恒定律:格式调整耗时 = 插入图片数 × 标书页数/10" ⏰
graph LR A[招标文件] --> B[智能解析] B --> C[自动提取附件] C --> D[精准插入图片] D --> E[完美格式标书]
温馨提示:观看时请勿羡慕到流泪 😭
数据是LLM的血液,没有数据的Agent就像没有汽油的超跑 —— 只能看不能开
我们采用"分治策略"管理企业资质:
知识库:这里存放着价值百万的"数字房产证"🏠
温馨提示:本流程已通过ISO-9001"防加班"认证 🕒
import requestsimport tempfileimport osimport refrom collections.abc import Generatorfrom typing import Any, Dict, List, Optionalfrom io import BytesIOfrom docx import Documentfrom dify_plugin import Toolfrom dify_plugin.entities.tool import ToolInvokeMessageclass DocxTitleTool(Tool):def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:"""提取DOCX文件中的标题Args:tool_parameters: 包含docx文件和title_level参数"""# 获取参数uploaded_file = tool_parameters.get('docx')title_level = tool_parameters.get('title_level', 1)if not uploaded_file:yield self.create_text_message("请上传DOCX文件")returntry:title_level = int(title_level)if title_level < 1 or title_level > 9:yield self.create_text_message("标题级别必须在1-9之间")returnexcept (ValueError, TypeError):yield self.create_text_message("标题级别必须是有效的数字")returntry:# 下载文件file_url = "http://api:5001" + uploaded_file.urlresponse = requests.get(file_url)if response.status_code != 200:yield self.create_text_message(f"文件下载失败,状态码: {response.status_code}")return# 创建临时文件保存DOCX内容with tempfile.NamedTemporaryFile(suffix='.docx', delete=False) as temp_file:temp_file.write(response.content)temp_file_path = temp_file.nametry:# 提取标题headings_result = self._extract_headings_by_level(temp_file_path, title_level)if not headings_result:yield self.create_text_message("未在文档中找到指定级别的标题")return# 返回结果yield self.create_json_message({"result": headings_result,"summary": f"成功提取了{title_level}级及以上的标题"})finally:# 清理临时文件if os.path.exists(temp_file_path):os.unlink(temp_file_path)except Exception as e:yield self.create_text_message(f"处理文件时发生错误: {str(e)}")def _get_heading_level(self, paragraph) -> Optional[int]:"""获取段落的标题级别Args:paragraph: 文档段落对象Returns:int: 标题级别 (1-9),如果不是标题则返回None"""# 方法1: 通过样式名称判断style_name = paragraph.style.name.lower()# 检查标准的标题样式if 'heading' in style_name:# 提取数字,如 'Heading 1' -> 1match = re.search(r'heading\s*(\d+)', style_name)if match:return int(match.group(1))# 检查中文标题样式if '标题' in style_name:match = re.search(r'标题\s*(\d+)', style_name)if match:return int(match.group(1))# 方法2: 通过outline_level属性判断if hasattr(paragraph, '_p') and hasattr(paragraph._p, 'pPr'):pPr = paragraph._p.pPrif pPr is not None and hasattr(pPr, 'outlineLvl_val'):outline_level = pPr.outlineLvl_valif outline_level is not None:return outline_level + 1 # outline_level是0-based,转换为1-based# 方法3: 通过样式的outline_level属性try:if hasattr(paragraph.style, '_element') and hasattr(paragraph.style._element, 'pPr'):pPr = paragraph.style._element.pPrif pPr is not None:outline_lvl = pPr.find('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}outlineLvl')if outline_lvl is not None:val = outline_lvl.get('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val')if val is not None:return int(val) + 1except:passreturn Nonedef _extract_headings_by_level(self, file_path: str, max_level: int) -> List[Dict[str, List[str]]]:"""提取指定级别的标题Args:file_path: DOCX文件路径max_level: 最大标题级别Returns:List[Dict[str, List[str]]]: 按用户要求格式返回的标题列表"""try:# 加载文档doc = Document(file_path)# 按级别收集标题headings_by_level = {}for level in range(1, max_level + 1):headings_by_level[level] = []# 遍历所有段落for paragraph in doc.paragraphs:# 跳过空段落if not paragraph.text.strip():continue# 获取标题级别heading_level = self._get_heading_level(paragraph)if heading_level is not None and heading_level <= max_level:headings_by_level[heading_level].append(paragraph.text.strip())# 转换为用户要求的格式result = []level_names = {1: "一级标题",2: "二级标题",3: "三级标题",4: "四级标题",5: "五级标题",6: "六级标题",7: "七级标题",8: "八级标题",9: "九级标题"}for level in range(1, max_level + 1):if headings_by_level[level]: # 只添加有内容的级别level_name = level_names.get(level, f"{level}级标题")result.append({level_name: headings_by_level[level]})return resultexcept Exception as e:raise Exception(f"提取标题时发生错误: {str(e)}")
你是一个招标文件分析助手,在招投标领域,乙方投标文件,必须按照甲方招标文件中规定的格式进行撰写#输入是招标文件的章节标题,请判断对于投标文件的格式要求,所在的章节,然后返回开始章节标题,和结束章节标题#符合条件的章节,一般包含有"附件"字样,即该章,附带了许多格式化的表格,投标人照此写标书#如果没有结束章节标题,则置为空参考输出格式:{"开始标题":”XXX“,”结束标题“:"XXX"}{{#投标文件的章节名称.result#}}/no_think经过LLM后,去掉输出结果的think标签import re,jsonfrom typing import Listimport jsondef main(arg1): tmp = re.sub(r"<think>[\s\S]*?</think>", "", arg1, flags=re.DOTALL) tmp = re.sub(r'^\s*```(?:json)?\s*\n?', '', tmp,flags=re.IGNORECASE) tmp = re.sub(r'\n?```\s*$', '', tmp) tmp = tmp.replace(r'\n', '\n').replace(r'\"', '"').strip() result=tmp return { 'result':result }# ===== 数据结构定义 =====定义 ElementInfo: 元素类型: 'paragraph' 或 'table' XML内容: 字符串 文本内容: 字符串 (用于预览) 索引: 整数 分区格式: 字典 (可选)定义 SectionInfo: 标题: 字符串 元素列表: [ElementInfo]定义 PageFormatInfo: 页面宽度, 高度, 方向, 四周边距: 整数/字符串定义 DocumentExtractResult: 章节列表: [SectionInfo] 页面格式: PageFormatInfo 源文件路径: 字符串 元素总数: 整数 抽取信息: 字典 分区格式列表: [字典] (可选) 样式XML: 字符串 (可选) 编号XML: 字符串 (可选)# ===== 文档解析器类 =====类 DocxExtractor: 初始化(文档路径): 加载DOCX文档 获取页面格式(章节索引=0): 尝试从文档获取页面设置 失败则返回默认A4格式 查找单章节(开始标题, 标题级别=1, 结束标题=None): 预处理标题(移除空格) 收集所有文档元素(段落+表格) 遍历元素: - 发现匹配的开始标题 → 创建新章节 - 继续收集元素直到: a) 遇到结束标题 b) 遇到同级标题(无结束标题时) 返回找到的章节列表 抽取单章节(开始标题, 标题级别=1, 结束标题=None): 调用查找单章节 收集分区格式信息 确定最终页面格式: 优先使用提取的分区格式 否则调用获取页面格式 构建DocumentExtractResult对象 返回结果# ===== 插件工具类 =====类 DocxExtractorTool (继承Tool): 执行入口(参数): 验证必要参数(文档文件, 开始标题) 下载DOCX文件 → 保存为临时文件 创建DocxExtractor实例 调用抽取单章节方法 处理结果: 添加成功元数据 转换为JSON格式 生成输出文件 异常处理: 值错误/通用错误 → 生成错误JSON文件 返回处理结果(文件blob或错误信息)
// XML数据结构:标书的DNA{ "element_type": "paragraph", "xml_content": "<w:p>7-2纳税证明</w:p>", "text_content": "7-2纳税证明", "index": 642}智能匹配流程:a.文字:"7-2纳税证明"发出相亲请求b.知识库:匹配到纳税证明图片集c.LLM媒人:生成"结婚证"(XML数据)d.输出:文字+图片的完美组合
大模型将图片转换为xml的prompt:
你是一个json数据处理专家,请将数据A,按照参考格式,进行构造,然后返回一个新的json数据#如果待处理数据只有文字,则生成element_type为paragraph。如果待处理数据还有图像,则生成element_type为picture。#index字段,与B保持一致,举例B为100,则输出的所有index都是100数据A:{{检索到的图片url.result#}}数据B:{{#当前数据索引#}}如果只有文字,输出格式参考 { "element_type": "paragraph", "xml_content": "xxxx", "text_content": "xxx", "index": xxx, "section_format": null }如果是图像,输出格式参考{ "element_type": "picture", "image_path": "XXX, "index": XXX}函数 assemble_document(输入: 抽取结果, 输出路径, 是否清理分区属性):尝试:创建临时目录和DOCX基础结构初始化XML内容列表添加DOCX文档头部到XML列表收集所有元素并按原始索引排序遍历每个元素:如果元素类型是图片:从Docker获取图片数据生成图片XML并保存到媒体目录将图片XML添加到内容列表如果元素类型是段落或表格:获取元素XML内容根据标志决定是否清理分区属性将处理后的XML添加到内容列表添加DOCX文档尾部到XML列表将完整XML写入document.xml文件创建辅助文件:[Content_Types].xml主关系文件(.rels)文档关系文件(document.xml.rels)样式文件(styles.xml)编号文件(numbering.xml)将临时目录打包为DOCX文件输出处理统计信息异常处理:抛出错误信息最终:清理临时目录
使用xml标签,确保了生成标书的格式的正确性,而且自动插入图片,节省了投标人员一部分时间。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-07-03
10分钟干完咨询公司一个月的活,消费者洞察Skill
2026-07-02
从一个售前场景开始:一次组织级 AI 落地项目复盘
2026-07-01
半小时,100页标书,AI替你熬的夜
2026-07-01
被AI识破的“分工陷阱”:为什么前端部署工程师本质就是销售?
2026-06-27
人人都在抢邮件和私信,却忘了那个打开率最高的老渠道——还没人用AI做好
2026-06-25
Codex最强替代!我用这款全场景Agent搞定整套营销方案
2026-06-24
装修、服装、家具,正在用 AI 把生意讲清楚
2026-06-16
万字长文|AI 正在重塑营销范式:未来市场部,不是提效,而是重构组织方式(上篇)
2026-04-20
2026-04-27
2026-05-11
2026-05-07
2026-06-01
2026-05-26
2026-06-08
2026-05-25
2026-07-01
2026-06-16
2026-07-01
2026-03-16
2026-01-25
2025-09-30
2025-06-26
2025-06-15
2025-06-03
2025-05-29
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。