From dd18c0d47b8c179d53787bc160f3e520c2e01cca Mon Sep 17 00:00:00 2001 From: zy123 <646228430@qq.com> Date: Fri, 29 Nov 2024 15:02:07 +0800 Subject: [PATCH] =?UTF-8?q?11.29=20=E4=BC=98=E5=8C=96=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flask_app/general/接口_技术偏离表.py | 60 ++++++------ flask_app/货物标/商务服务其他要求提取.py | 117 ++++++++++------------- 2 files changed, 79 insertions(+), 98 deletions(-) diff --git a/flask_app/general/接口_技术偏离表.py b/flask_app/general/接口_技术偏离表.py index 42e682f..c3efbe3 100644 --- a/flask_app/general/接口_技术偏离表.py +++ b/flask_app/general/接口_技术偏离表.py @@ -174,38 +174,40 @@ def extract_business_deviation(procurement): business_requirements_string = json.dumps(new_data, ensure_ascii=False, indent=4) # print(business_requirements_string) - prompt_template1 = """请帮我从以下文本中摘取商务要求部分,并将信息重新组织,外键名为'商务要求',键值为字符串列表,其中每个字符串为一条商务要求,去除开头的序号(若有)。 -#角色 -你是一个专业的招投标业务专家,擅长从招标文件中总结商务要求的部分,并逐条列出,作为编写商务要求偏离表的前置准备。 + prompt_template1 = """请帮我从以下文本中摘取商务要求部分,并将信息重新组织,外键名为'商务要求',键值为字符串列表,其中每个字符串为一条商务要求,保留三角▲、五角星★(若有),但是去除开头的序号(若有)。 + #角色 + 你是一个专业的招投标业务专家,擅长从招标文件中总结商务要求的部分,并逐条列出,作为编写商务要求偏离表的前置准备。 -#要求与指南: -1. 每条内容需要有实际的含义、要求,不能光有标题性质的表述如'售后服务期限(质保期)及要求'。 -2. 你的回答内容需从所给文本中整理,尽量不改变原文的表达,对于嵌套键值对,若键值本身符合'商务要求',可直接将其返回;若键值本身语义表达不完整,可将键值对拼接之后作为一条商务要求,拼接符号可以是冒号,即':'。 -3. 若无商务要求,键值为空列表,即[] + #要求与指南: + 1. 每条内容需要有实际的含义、要求,不能光有标题性质的表述如'售后服务期限(质保期)及要求'。 + 2. 你的回答内容需从所给文本中整理,尽量不改变原文的表达,请勿擅自添加三角▲、五角星★;若输入文本中存在嵌套键值对格式,且键值本身符合'商务要求',可直接将其添加至'商务要求'的键值中;若键值本身语义表达不完整,可将键值对拼接之后作为一条商务要求,拼接符号可以是冒号,即':'。 + 3. 输入文本中出现三角▲或五角星★开头的地方,请格外重视,不可漏提,若其后面的内容是标题性质的表述、不具备实际的要求,请你保留三角▲或五角星★,根据语义添加至紧跟着的字符串开头中。 + 3. 若无商务要求,键值为空列表,即[] -### 示例输入如下: -{{ - "招标要求1": "整个平台运行运维服务,须安排人员驻场对平台进行运行维护,采用 4人轮流值班,依照 7×12小时对可视化督察巡控平台进行操作,确保平台稳定运行,并对线上发现违规操作进行记录,通过督察平台推送督办单给线下监督员小程序进行检查。" - "招标要求2": {{ - "合同履行期限": "交货期(工期):合同签订之日起 15个日历天内完成,并通过项目验收。", - "交货地点": "采购人指定地点", - "报价方式": "本项目报价须为固定总价,包含但不限于:采购、实施、调试、试运行、验收、运维等所有完成本项目相关的一切费用。", - "其他要求": "无。" - }}, - "招标要求3": "路口必须在各方向埋设双管。" -}} -### 对应的参考输出如下: -{{ - "商务要求":[ - "整个平台运行运维服务,须安排人员驻场对平台进行运行维护,采用 4人轮流值班,依照 7×12小时对可视化督察巡控平台进行操作,确保平台稳定运行,并对线上发现违规操作进行记录,通过督察平台推送督办单给线下监督员小程序进行检查。", - "交货期(工期):合同签订之日起 15个日历天内完成,并通过项目验收。", - "交货地点:采购人指定地点", - "本项目报价须为固定总价,包含但不限于:采购、实施、调试、试运行、验收、运维等所有完成本项目相关的一切费用。" - ] -}} -文本内容:{full_text} -""" + ### 示例输入如下: + {{ + "招标要求1": ["▲(1)整个平台运行运维服务,须安排人员驻场对平台进行运行维护,采用 4人轮流值班,依照 7×12小时对可视化督察巡控平台进行操作,确保平台稳定运行,并对线上发现违规操作进行记录,通过督察平台推送督办单给线下监督员小程序进行检查。"] + "招标要求2": {{ + "合同履行期限": ["★交货期(工期):合同签订之日起 15个日历天内完成,并通过项目验收。"], + "交货地点": ["采购人指定地点"], + "报价方式": ["(1)本项目报价须为固定总价,包含但不限于:采购、实施、调试、试运行、验收、运维等所有完成本项目相关的一切费用。","(2)因投标人自身原因造成漏报、少报皆由其自行承担责任,采购人不再补偿。"], + "其他要求": ["无。"] + }} + }} + ### 对应的参考输出如下: + {{ + "商务要求":[ + "▲整个平台运行运维服务,须安排人员驻场对平台进行运行维护,采用 4人轮流值班,依照 7×12小时对可视化督察巡控平台进行操作,确保平台稳定运行,并对线上发现违规操作进行记录,通过督察平台推送督办单给线下监督员小程序进行检查。", + "★交货期(工期):合同签订之日起 15个日历天内完成,并通过项目验收。", + "交货地点:采购人指定地点", + "本项目报价须为固定总价,包含但不限于:采购、实施、调试、试运行、验收、运维等所有完成本项目相关的一切费用。", + "因投标人自身原因造成漏报、少报皆由其自行承担责任,采购人不再补偿。" + ] + }} + + 文本内容:{full_text} + """ user_query1 = prompt_template1.format(full_text=business_requirements_string) model_res1 = doubao_model(user_query1) # print(model_res) diff --git a/flask_app/货物标/商务服务其他要求提取.py b/flask_app/货物标/商务服务其他要求提取.py index 3691297..f0a90c4 100644 --- a/flask_app/货物标/商务服务其他要求提取.py +++ b/flask_app/货物标/商务服务其他要求提取.py @@ -77,30 +77,46 @@ def find_exists(truncate_file, required_keys): matched_requirements = [] punctuation = r"[,。?!、;:,.?!]*" for req in required_keys: - # required_keys 中的元素本身已包含 \s*,直接作为正则模式 if re.search(req, relevant_text): - if req == "服\s*务\s*要\s*求": - # 提取所有包含"服务要求"的行 + # 替换特定的关键词 + if req in [r"总\s*体\s*要\s*求", r"建\s*设\s*要\s*求"]: + # 匹配到“总体要求”或“建设要求”时,添加“技术要求”而非原关键词 + tech_req = r"技\s*术\s*要\s*求" + if tech_req not in matched_requirements: + matched_requirements.append(tech_req) + elif req in [r"培\s*训\s*要\s*求",r"质\s*保\s*要\s*求",r"售\s*后\s*要\s*求"]: + # 匹配到“培训要求”时,添加“服务要求”而非原关键词 + service_req = r"服\s*务\s*要\s*求" + if service_req not in matched_requirements: + matched_requirements.append(service_req) + elif req in [r"进\s*度\s*要\s*求",r"工\s*期\s*要\s*求"]: + busi_req = r"商\s*务\s*要\s*求" + if busi_req not in matched_requirements: + matched_requirements.append(busi_req) + elif req == r"服\s*务\s*要\s*求": + # 处理“服务要求”时的特殊逻辑 lines = [line for line in relevant_text.split('\n') if re.search(req, line)] - # 检查是否存在'技术'紧跟在'服务要求'前面(中间只有标点,标点是可选的) - pattern = "技\s*术" + punctuation + req + pattern = r"技\s*术" + punctuation + req if any(re.search(pattern, line) for line in lines): - # 如果存在'技术'紧跟'服务要求',添加"技术、服务要求" - if "技\s*术\s*、\s*服\s*务\s*要\s*求" not in matched_requirements: - matched_requirements.append("技\s*术\s*、\s*服\s*务\s*要\s*求") + combined_req = r"技\s*术\s*、\s*服\s*务\s*要\s*求" + if combined_req not in matched_requirements: + matched_requirements.append(combined_req) else: - # 如果不存在'技术'紧跟'服务要求',正常添加"服务要求" - matched_requirements.append(req) + if req not in matched_requirements: + matched_requirements.append(req) else: - matched_requirements.append(req) - + # 对于其他匹配的关键词,直接添加 + if req not in matched_requirements: + matched_requirements.append(req) # 去除 \s*,仅返回原始关键词 clean_requirements = [re.sub(r'\\s\*', '', req) for req in matched_requirements] # 判断互斥关系:如果有"技术、服务要求",删除"技术要求"和"服务要求" if "技术、服务要求" in clean_requirements: clean_requirements = [req for req in clean_requirements if req not in ["技术要求", "服务要求"]] - + # 确保最终返回的列表仅包含指定的五项 + # allowed_requirements = {"技术要求", "服务要求", "商务要求", "其他要求", "技术、服务要求"} + # final_requirements = [req for req in clean_requirements if req in allowed_requirements] return clean_requirements @@ -125,10 +141,7 @@ def generate_template(required_keys, type=1): "技术要求": ["相关技术要求1", "相关技术要求2"], "服务要求": ["服务要求1", "服务要求2", "服务要求3"], "商务要求": ["商务要求1", "商务要求2"], - "其他要求": { - "子因素名1": ["关于项目采购的其他要求1...", "关于项目采购的其他要求2..."], - "子因素名2": ["关于项目采购的其他要求3..."] - }, + "其他要求": ["关于项目采购的其他要求1...", "关于项目采购的其他要求2...", "关于项目采购的其他要求3..."], "技术、服务要求": ["相关技术、服务要求内容1", "相关技术、服务要求内容2", "相关技术、服务要求内容3"] } example_content2 = { @@ -143,7 +156,10 @@ def generate_template(required_keys, type=1): "子因素名1": ["商务要求1"], "子因素名2": ["商务要求2"] }, - "其他要求": ["关于项目采购的其他要求1...", "关于项目采购的其他要求2...", "关于项目采购的其他要求3..."], + "其他要求": { + "子因素名1": ["关于项目采购的其他要求1...", "关于项目采购的其他要求2..."], + "子因素名2": ["关于项目采购的其他要求3..."] + }, "技术、服务要求": { "子因素名1": ["相关技术、服务要求内容1"], "子因素名2": ["相关技术、服务要求内容2", "相关技术、服务要求内容3"] @@ -180,29 +196,31 @@ def generate_template(required_keys, type=1): def generate_prompt_instruction(keys_str, outer_keys_str, another_keys_str, type): if type == 1: specific_instructions = textwrap.dedent( - """4. 若章节开头位置或者采购清单中除了需要采购的货物、数量、单位之外,还有带三角▲或五角星★的描述内容(如工期要求、质保要求等商务要求),请将该部分内容提取出来,添加在外层键名为'商务要求'的键值部分。 - 5. 在提取'服务要求'的时候,通常包含'售后、维护、培训'等要求,若原文中有这些要求,请一并提取置于'服务要求'的键值中,。 + """4. 若章节开头位置或者采购清单中除了需要采购的货物、数量、单位之外,还有带三角▲或五角星★的描述内容(如工期要求、进度要求、品牌要求等商务要求),也请将该部分内容提取出来,添加在外层键名为'商务要求'的键值部分;若存在标题包含'工期要求'、'进度要求'等和商务要求有关的关键字,也请将该标题下的内容提取,添加在外层键名为'商务要求'的键值部分。请不要遗漏这部分的'商务要求'。 + 5. 在提取'服务要求'的时候,若原文(包含正文和表格)中存在'安装要求'、'售后要求'、'维护要求'、'培训要求'等服务相关的要求说明,请添加至'服务要求'的键值部分,不要遗漏这部分的'服务要求'。 """ ) else: specific_instructions = textwrap.dedent( - """4. 在提取技术要求或技术、服务要求时,你无需从采购清单或表格中提取技术要求以及参数要求,你仅需定位到原文中包含'技术要求'或'技术、服务要求'关键字的标题并提取其后相关内容;若技术要求的内容全在表格中,键值为空列表[]。 - 5. 在提取'技术要求'时,注意不要提取有关'售后、维护、运维、培训、质保'等要求,它们不属于'技术要求'。 + """4. 在提取技术要求或技术、服务要求时,你无需从采购清单或表格中提取技术要求以及参数要求,你仅需定位到原文中包含'技术要求'或'技术、服务要求'关键字的标题并提取其后相关内容,从正文中提取;若技术要求或技术服务要求的内容全在表格中,键值为空列表[]。 + 5. 在提取'技术要求'时,注意不要提取有关'安装、售后、维护、运维、培训、质保'等要求,它们不属于'技术要求',但是若大标题中包含'总体要求''建设要求'等和技术要求相关的关键字,请添加到'技术要求'的键值部分。 """ ) return textwrap.dedent( - f"""请你根据该货物类招标文件中的采购要求部分内容,请告诉我该项目采购的{keys_str}分别是什么,请以json格式返回结果,默认情况下外层键名是{outer_keys_str},键值为字符串列表,每个字符串表示具体的一条要求,可以按原文中的序号作划分(若有序号的话),请按原文内容回答,保留三角▲、五角星★和序号(若有),不要擅自增添内容及序号。请不要提取{another_keys_str}中的内容。 + f"""请你根据该货物类招标文件中的采购要求部分内容,请告诉我该项目采购的{keys_str}分别是什么,请以json格式返回结果,默认情况下外层键名是{outer_keys_str},键值为字符串列表,每个字符串表示具体的一条要求,可以按原文中的序号作划分(若有序号的话),请按原文内容回答,保留三角▲、五角星★和序号(若有),不要擅自增添内容及序号。注意:1. 若相应要求下存在子标题表示子要求因素,可以将它忽略而不是将它与下文具体要求进行多行合并,或者作为该要求下的嵌套键名,总之字符串列表中只提取具体的要求。2. 请不要提取{another_keys_str}中的内容。 要求与指南: 1. JSON 的结构要求: - - 默认情况无需嵌套键值对,键值为字符串列表;若存在嵌套结构(即有明确标题表示各子要求),则嵌套键名是原文中该要求下相应子标题,最多一层嵌套。 + - 默认情况无需嵌套键值对,键值为字符串列表;若存在嵌套结构(即有明确标题表示各子要求),则嵌套键名是各子要求,嵌套键值为字符串列表,为该子要求下的若干要求,最多一层嵌套。 - 每个外层键对应的值可以是: a. 一个字符串列表,表示具体的一条条要求。若只有一条要求,也用字符串列表表示。 b. 一个对象(字典),其键为子因素名,值为字符串列表。 + c. 若文档中无符合的相关要求,键值为空列表[] - 最多只允许一层嵌套。 2. 请优先且准确定位正文部分包含以下关键字的标题:{outer_keys_str},在其之后提取'XX要求'相关内容,尽量避免在无关地方提取内容。 - 3. 注意请不要返回Markdown语法,必要时使用冒号':'将相关信息拼接在一起。若文档中无符合的相关要求,键值为空列表[] + 3. 注意请不要返回Markdown表格语法,必要时使用冒号':'将相关信息拼接在一起 {specific_instructions} + 6. 字符串列表中的每个字符串内容需与原文内容保持一致,保留前面的三角▲、五角星★和序号(若有),而且你不可以擅自添加序号。 """) # 过滤示例内容 @@ -223,56 +241,17 @@ def generate_template(required_keys, type=1): user_query_template = f""" {prompt_instruction} 以下为示例输出,仅供格式参考: - 示例 1: + 示例 1,无嵌套键值对: {tech_json_example1_str} - 示例 2: + 示例 2,嵌套键值对形式: {tech_json_example2_str} """ return user_query_template -def merge_requirements(input_dict): - # 初始化一个临时字典,用于存储标准化后的键 - temp_dict = {} - # 初始化最终字典,只包含指定的四个键 - final_keys = ['技术要求', '商务要求', '服务要求', '其他要求'] - final_dict = {key: "" for key in final_keys} - - # 如果输入字典中有'其他要求',保留其内容 - if '其他要求' in temp_dict and temp_dict['其他要求'].strip(): - final_dict['其他要求'] = temp_dict['其他要求'].strip() - - # 处理'技术要求', '商务要求', '服务要求' - for key in ['技术要求', '商务要求', '服务要求']: - if key in temp_dict: - final_dict[key] = temp_dict[key].strip() - - # 收集需要合并到'其他要求'的内容 - merge_keys = ['总体要求', '进度要求', '培训要求'] - merged_contents = [] - for key in merge_keys: - if key in temp_dict and temp_dict[key].strip(): - merged_contents.append(temp_dict[key].strip()) - - # 如果有需要合并的内容 - if merged_contents: - merged_text = " ".join(merged_contents) - if final_dict['其他要求']: - final_dict['其他要求'] += " " + merged_text - else: - final_dict['其他要求'] = merged_text - - # 移除多余的空格 - for key in final_dict: - final_dict[key] = final_dict[key].strip() - - return final_dict - - -# ,"总\s*体\s*要\s*求","进\s*度\s*要\s*求","培\s*训\s*要\s*求" def get_business_requirements(procurement_path,procurement_docpath): file_id = upload_file(procurement_docpath) print(file_id) - required_keys = ["技\s*术\s*要\s*求", "商\s*务\s*要\s*求", "服\s*务\s*要\s*求", "其\s*他\s*要\s*求"] + required_keys = ["技\s*术\s*要\s*求", "商\s*务\s*要\s*求", "服\s*务\s*要\s*求", "其\s*他\s*要\s*求","总\s*体\s*要\s*求","建\s*设\s*要\s*求","进\s*度\s*要\s*求","工\s*期\s*要\s*求","质\s*保\s*要\s*求","培\s*训\s*要\s*求","售\s*后\s*要\s*求"] contained_keys = find_exists(procurement_path, required_keys) print(contained_keys) if not contained_keys: @@ -301,8 +280,8 @@ def get_business_requirements(procurement_path,procurement_docpath): # TODO:改为先判断,再摘取 if __name__ == "__main__": # truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\e4be098d-b378-4126-9c32-a742b237b3b1\\ztbfile_procurement.docx" - truncate_file = r"C:\Users\Administrator\Desktop\货物标\output1\交警支队机动车查验监管系统项目采购_procurement.pdf" - docx_path=r'C:\Users\Administrator\Desktop\货物标\output1\交警支队机动车查验监管系统项目采购_procurement.docx' + truncate_file = r"C:\Users\Administrator\Desktop\货物标\output1\陕西省公安厅交通警察总队高速公路交通安全智能感知巡查系统项目 (1)_procurement.pdf" + docx_path=r'C:\Users\Administrator\Desktop\货物标\output1\陕西省公安厅交通警察总队高速公路交通安全智能感知巡查系统项目 (1)_procurement.docx' # truncate_file=r"C:\Users\Administrator\Desktop\new招标文件\output5\HBDL-2024-0519-001-招标文件_procurement.pdf" # file_id = upload_file(truncate_file) processed_filepath = pdf2txt(truncate_file)