diff --git a/flask_app/general/读取文件/按页读取pdf.py b/flask_app/general/读取文件/按页读取pdf.py index 696ed1f..c19f3c5 100644 --- a/flask_app/general/读取文件/按页读取pdf.py +++ b/flask_app/general/读取文件/按页读取pdf.py @@ -96,7 +96,7 @@ def extract_text_by_page(file_path): if __name__ == '__main__': # file_path='D:\\flask_project\\flask_app\\static\\output\\output1\\648e094b-e677-47ce-9073-09e0c82af210\\ztbfile_tobidders_notice_part2.pdf' - file_path = 'C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_tobidders_notice_part2.pdf' + file_path = 'C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_procurement.pdf' # file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\磋商文件_tobidders_notice_part2.pdf' # file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\截取test\\交警支队机动车查验监管系统项目采购_tobidders_notice_part1.pdf' # file_path = "C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\zbtest8.pdf" diff --git a/flask_app/general/通义千问long.py b/flask_app/general/通义千问long.py index bff54e5..08cb0c4 100644 --- a/flask_app/general/通义千问long.py +++ b/flask_app/general/通义千问long.py @@ -1,3 +1,4 @@ +import random import time from pathlib import Path from openai import OpenAI diff --git a/flask_app/货物标/商务服务其他要求提取.py b/flask_app/货物标/商务服务其他要求提取.py index c092179..877dfd4 100644 --- a/flask_app/货物标/商务服务其他要求提取.py +++ b/flask_app/货物标/商务服务其他要求提取.py @@ -1,3 +1,4 @@ +# -*- encoding:utf-8 -*- import json import re from PyPDF2 import PdfReader @@ -10,12 +11,13 @@ from flask_app.货物标.截取pdf货物标版 import extract_common_header, cle #正则表达式判断原文中是否有商务、服务、其他要求 def find_exists(truncate_file, required_keys): if not truncate_file: - return ["商务要求", "服务要求", "其他要求"] + return ["技术要求","商务要求", "服务要求", "其他要求"] common_header = extract_common_header(truncate_file) pdf_document = PdfReader(truncate_file) text = "" + begin_pattern = re.compile( - r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务).*?要求|' + r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务|技术).*?要求|' r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:采购|技术标准).*|' r'^[一二三四五六七八九十百千]+、\s*采购清单', re.MULTILINE) end_pattern = re.compile( @@ -62,7 +64,7 @@ def find_exists(truncate_file, required_keys): def generate_queries(truncate_file, required_keys): key_list = find_exists(truncate_file, required_keys) queries = [] - user_query_template = "这是一份货物标中采购要求部分的内容,请告诉我\"{}\"是什么,请以json格式返回结果,外层键名是\"{}\",内层键值对中的键是你对该要求的总结,而值需要完全与原文保持一致,不可擅自总结删减,注意你无需回答具体设备的技术要求。" + user_query_template = "这是一份货物标中采购要求部分的内容,请告诉我\"{}\"是什么,请以json格式返回结果,外层键名是\"{}\",内层键值对中的键名是原文中的标题或者是你对相关子要求的总结,而键值需要完全与原文保持一致,不可擅自总结删减,注意你无需回答采购清单中具体设备的技术参数要求,仅需从正文部分开始提取," for key in key_list: query_base = user_query_template.format(key, key) other_keys = [k for k in key_list if k != key] @@ -75,20 +77,29 @@ def generate_queries(truncate_file, required_keys): def get_business_requirements(truncate_file,file_id): - required_keys = ["商务要求", "服务要求", "其他要求"] - queries = generate_queries(truncate_file, required_keys) + # required_keys = ["技术要求","商务要求", "服务要求", "其他要求"] + # queries = generate_queries(truncate_file, required_keys) + #一起问了,效率慢点,但内容准 + queries=[ + """ +请你根据该货物类招标文件中的采购要求部分内容,请告诉我文档中技术要求、服务要求、商务要求、其他要求分别是什么,请以json格式返回结果,可以用嵌套键值对的形式组织回答,默认情况下外层键名是'技术要求','服务要求','商务要求','其他要求',内层键名是原文中的相应子标题或者是你对相关子要求的总结,而键值需要完全与原文保持一致,不可擅自总结删减。注意你无需回答采购清单中具体设备的技术参数要求,仅需从正文部分开始提取。以下是你需要考虑的特殊情况:如果原文中技术要求与服务要求在一块,那么你应该用外键'技术、服务要求'替换默认外键'技术要求'和'服务要求',若相关要求不存在,对应的键值设为'未知'。以下为示例输出,仅供格式参考: +{ + "技术、服务要求":"相关技术要求以及服务要求", + "商务要求":"相关商务要求", + "其他要求":"其他要求内容" +} +""" + ] results = multi_threading(queries, "", file_id, 2) business_requirements = [res for _, res in results] if results else [] - # Combine and fill missing keys with default values final_res = combine_json_results(business_requirements) - final_res.update({key: final_res.get(key, "") for key in required_keys}) - + # final_res.update({key: final_res.get(key, "") for key in required_keys}) return final_res if __name__ == "__main__": - truncate_file = "C:\\Users\\Administrator\\Desktop\\货物标\\output1\\2-招标文件_procurement.pdf" + truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\469d2aee-9024-4993-896e-2ac7322d41b7\\ztbfile_procurement.docx" file_id = upload_file(truncate_file) res=get_business_requirements(truncate_file,file_id) print(json.dumps(res, ensure_ascii=False, indent=4)) diff --git a/flask_app/货物标/基础信息解析main.py b/flask_app/货物标/基础信息解析main.py index 6049ed9..1fe9ed2 100644 --- a/flask_app/货物标/基础信息解析main.py +++ b/flask_app/货物标/基础信息解析main.py @@ -27,7 +27,7 @@ def aggregate_basic_info_goods(baseinfo_list): key_groups = { "招标人/代理信息": ["招标人", "招标人联系方式", "招标代理机构", "招标代理机构联系方式","项目联系方式"], "项目信息": ["项目名称", "项目编号", "项目概况", "项目基本情况", "招标控制价", "投标竞争下浮率"], - "采购要求": ["技术要求","商务要求","服务要求","其他要求"], + "采购要求": ["采购需求","技术要求","服务要求","商务要求","其他要求"], "关键时间/内容": [ "投标文件递交截止日期", "开标时间", @@ -81,6 +81,24 @@ def aggregate_basic_info_goods(baseinfo_list): def dynamic_key_handling(key_groups, detected_keys): # 检查和调整键组配置 for key in detected_keys: + if "技术、服务要求" in detected_keys: + # 如果检测到“技术、服务要求”,则移除“技术要求”和“服务要求” + if "技术要求" in key_groups["采购要求"]: + key_groups["采购要求"].remove("技术要求") + if "服务要求" in key_groups["采购要求"]: + key_groups["采购要求"].remove("服务要求") + # 确保"技术、服务要求"存在于"采购要求"组中 + if "技术、服务要求" not in key_groups["采购要求"]: + key_groups["采购要求"].insert(1, "技术、服务要求") + else: + # 如果不存在“技术、服务要求”,确保“技术要求”和“服务要求”都在"采购要求"组中 + if "技术要求" not in key_groups["采购要求"]: + key_groups["采购要求"].insert(1, "技术要求") + if "服务要求" not in key_groups["采购要求"]: + key_groups["采购要求"].insert(2, "服务要求") + # 移除"技术、服务要求"以保持互斥 + if "技术、服务要求" in key_groups["采购要求"]: + key_groups["采购要求"].remove("技术、服务要求") # 处理“保证金相关”组 if "保证金" in key: group = key_groups["保证金相关"] diff --git a/flask_app/货物标/技术参数要求提取.py b/flask_app/货物标/技术参数要求提取.py index a3d8b8f..81ce497 100644 --- a/flask_app/货物标/技术参数要求提取.py +++ b/flask_app/货物标/技术参数要求提取.py @@ -1,6 +1,7 @@ # -*- encoding:utf-8 -*- import json import os +import re from flask_app.general.多线程提问 import multi_threading from flask_app.general.通义千问long import qianwen_long, upload_file @@ -10,17 +11,19 @@ from flask_app.货物标.截取pdf货物标版 import truncate_pdf_main def generate_key_paths(data, parent_key=''): """ 生成嵌套字典中的键路径,并提取最内层的键名。 + 同时,提取特定模式的键(如 '交换机-1', '交换机-2')的父路径。 参数: data (dict): 输入的字典数据 parent_key (str): 上级键路径,用于递归调用 返回: - tuple: 包含键路径列表和最内层键名列表的元组 - (key_paths, good_list) + tuple: 包含键路径列表、最内层键名列表、分组路径列表以及 no_keys_added 的元组 + (key_paths, good_list, grouped_paths, no_keys_added) """ key_paths = [] good_list = [] + grouped_paths = set() # 使用集合避免重复路径 no_keys_added = True # 默认假设没有添加任何键 for key, value in data.items(): @@ -29,43 +32,98 @@ def generate_key_paths(data, parent_key=''): if isinstance(value, dict): if value: - # 递归调用,并获取子路径和子 good_list - sub_key_paths, sub_good_list, sub_no_keys_added = generate_key_paths(value, current_key) + # 递归调用,并获取子路径、子 good_list、子分组路径以及子 no_keys_added + sub_key_paths, sub_good_list, sub_grouped_paths, sub_no_keys_added = generate_key_paths(value, current_key) key_paths.extend(sub_key_paths) good_list.extend(sub_good_list) + grouped_paths.update(sub_grouped_paths) # 合并子分组路径到当前分组路径 + # 更新 no_keys_added no_keys_added = no_keys_added and sub_no_keys_added else: # 空字典视为叶子节点 - key_paths.append(current_key.replace(" ","")) - good_list.append(key.replace(" ", "")) # 去掉空格后添加 + clean_key = key.replace(" ", "") + + # 使用正则提取具有相同前缀的键 + match = re.match(r'(.+)-\d+$', clean_key) + if match: + goods_name = match.group(1) # 提取货物名称前缀 + # 构建分组路径 + goods_path = f"{parent_key}.{goods_name}" if parent_key else goods_name + goods_path = goods_path.replace(" ", "") + grouped_paths.add(goods_path) # 添加到集合中,不添加到key_paths + else: + # 非匹配项则直接添加到key_paths中 + key_paths.append(current_key.replace(" ", "")) + good_list.append(clean_key) # 去掉空格后添加 + + # 更新 no_keys_added no_keys_added = False elif isinstance(value, list): if value: # 非空列表视为叶子节点 - key_paths.append(current_key.replace(" ","")) + key_paths.append(current_key.replace(" ", "")) good_list.append(key.replace(" ", "")) # 去掉空格后添加 + # 更新 no_keys_added no_keys_added = False else: # 空列表也视为叶子节点(根据需求可以调整) - key_paths.append(current_key.replace(" ","")) + key_paths.append(current_key.replace(" ", "")) good_list.append(key.replace(" ", "")) # 去掉空格后添加 + # 更新 no_keys_added no_keys_added = False elif value in {"未知", "", "/"}: # 特定值视为叶子节点 - key_paths.append(current_key.replace(" ","")) + key_paths.append(current_key.replace(" ", "")) good_list.append(key.replace(" ", "")) # 去掉空格后添加 + # 更新 no_keys_added no_keys_added = False else: - # 其他情况不视为叶子节点 - key_paths.append(current_key.replace(" ","")) + # 其他情况视为叶子节点 + key_paths.append(current_key.replace(" ", "")) good_list.append(key.replace(" ", "")) # 去掉空格后添加 + # 更新 no_keys_added no_keys_added = False - return key_paths, good_list, no_keys_added + return key_paths, good_list, grouped_paths, no_keys_added def combine_and_update_results(original_data, updates): + def normalize_key(key): + """ + 规范化键名: + - 替换全角点号为半角点号。 + - 删除所有空格(包括半角和全角)。 + """ + # 替换全角点号(.、。)为半角点号(.) + key = key.replace('.', '.').replace('。', '.') + # 删除所有空格(半角空格和全角空格) + key = key.replace(' ', '').replace('\u3000', '') + return key + + def normalize_original_data(d): + """ + 递归规范化原始数据字典的键。 + """ + if not isinstance(d, dict): + return d + normalized = {} + for k, v in d.items(): + nk = normalize_key(k) + normalized[nk] = normalize_original_data(v) + return normalized + + def normalize_update_value(value): + """ + 递归规范化更新字典中嵌套的字典的键。 + """ + if isinstance(value, dict): + return {normalize_key(k): normalize_update_value(v) for k, v in value.items()} + else: + return value + def recursive_update(data, key, value): - # 处理点分隔的键,递归定位并更新嵌套字典 + """ + 递归更新嵌套字典。 + """ keys = key.split('.') for k in keys[:-1]: data = data.setdefault(k, {}) @@ -73,8 +131,21 @@ def combine_and_update_results(original_data, updates): data[keys[-1]] = {**data.get(keys[-1], {}), **value} else: data[keys[-1]] = value + + # 1. 规范化原始数据字典的键 + original_data = normalize_original_data(original_data) + + # 2. 规范化更新字典的键 + normalized_updates = {} for key, value in updates.items(): + nk = normalize_key(key) + nv = normalize_update_value(value) + normalized_updates[nk] = nv + + # 3. 执行递归更新 + for key, value in normalized_updates.items(): recursive_update(original_data, key, value) + return original_data def postprocess(data): """递归地转换字典中的值为列表,如果所有键对应的值都是'/', '{}' 或 '未知'""" @@ -92,37 +163,36 @@ def postprocess(data): def get_technical_requirements(file_id,invalid_path): first_query="该文档中是否说明了采购需求,即需要采购哪些货物?如果有,请回答'是',否则,回答'否'" judge_res=qianwen_long(file_id,first_query) - # print(judge_res) if '否' in judge_res: file_id=upload_file(invalid_path) + print("调用invalid_path") user_query1 = """ -请你首先定位该采购文件中的采购清单或采购需求部分,请告诉我需要采购的货物,如果有采购清单,请直接根据清单上的货物(或系统)名称给出结果,若没有采购清单,你要从表格中或文中摘取需要采购的系统(或货物), -采购需求中可能包含层次关系,例如采购的某大系统中可能包含几种货物,那么你需要用嵌套键值对表示这种关系,且不要遗漏该系统中包含的货物,你的输出请以json格式返回,最外层键名为'采购需求',嵌套键名为对应的系统名称或货物名称,需与原文保持一致,无需给出采购数量和单位。以下为需要考虑的特殊情况:如果同一层级下存在同名货物且它们的技术参数要求有所不同,请在货物名后添加后缀'-n',n为自然数,依次递增;如有未知内容,在对应键值处填'未知'。以下为示例输出: +请你首先定位该采购文件中的采购清单或采购需求部分,请告诉我需要采购的货物,如果有采购清单,请直接根据清单上的货物(或系统)名称给出结果,注意不要返回'说明'或'规格'或'技术参数'列中的内容;若没有采购清单,你要从表格中或文中摘取需要采购的系统(或货物),采购需求中可能包含层次关系,例如采购的某大系统中可能包含几种货物,那么你需要用嵌套键值对表示这种关系,且不要遗漏该系统中包含的货物,你的输出请以json格式返回,最外层键名为'采购需求',嵌套键名为对应的系统名称或货物名称,需与原文保持一致,无需给出采购数量和单位。以下为需要考虑的特殊情况:如果采购清单中同一层级(或同一系统)下存在同名货物且它们的采购要求有所不同,请你以'货物名-编号'区分多种型号,编号为从 1 开始的自然数,依次递增,例如若采购清单中有两种型号的'交换机',那么你应返回两个键名,'交换机-1'和'交换机-2';如有未知内容,在对应键值处填'未知'。以下为考虑了特殊情况的示例输出: { "采购需求": { + "交换机-1":{}, + "交换机-2":{}, "门禁管理系统": {}, "交通监控视频子系统": { "高清视频抓拍像机":{}, "补光灯":{} }, - "LED全彩显示屏": {}, - "交换机-1":{}, - "交换机-2":{} + "LED全彩显示屏": {} } } """ res = qianwen_long(file_id, user_query1) print(res) cleaned_res = clean_json_string(res) #转字典 - keys_list,good_list,no_keys_added= generate_key_paths(cleaned_res['采购需求']) # 提取需要采购的货物清单 - if '采购需求' in cleaned_res: - cleaned_res['技术要求'] = cleaned_res.pop('采购需求') + keys_list,good_list,grouped_paths,no_keys_added= generate_key_paths(cleaned_res['采购需求']) # 提取需要采购的货物清单 key_list:交通监控视频子系统.高清视频抓拍像机 ... + # if '采购需求' in cleaned_res: + # cleaned_res['技术要求'] = cleaned_res.pop('采购需求') if no_keys_added: final_res = postprocess(cleaned_res) else: # user_query_template = "请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,外层键名为\"{}\", 键值对中的键是你对该要求的总结,而值需要完全与原文保持一致,不可擅自总结删减。" user_query_template = """ -请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,键名为\"{}\", 键值为一个列表,列表中包含若干描述\"{}\"的技术参数(或采购要求)的字符串,如果该货物没有相关要求,键值为空列表。示例输出格式如下: +请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,键名为\"{}\", 键值为一个列表,列表中包含若干描述\"{}\"的技术参数(或采购要求)的字符串。以下为需要考虑的特殊情况:如果该货物没有相关采购要求或技术参数要求,键值为空列表。示例输出格式如下: {{ "摄像机控制键盘": [ "支持串行 RS232/RS422 和 IP 混合控制,允许在一个控制器上使用 RS232/RS422/IP 控制单个系统中的摄像机;", @@ -130,12 +200,33 @@ def get_technical_requirements(file_id,invalid_path): ] }} """ + user_query_template_two=""" +请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),由于该货物存在多种不同的采购要求或技术参数,请你请逐一列出,请以json格式返回结果,请你以'货物名-编号'区分多种型号,编号为从 1 开始的自然数,依次递增,即第一个键名为\"{}-1\", 键值为一个列表,列表中包含若干描述\"{}\"的技术参数(或采购要求)的字符串。示例输出格式如下: +{{ + "交换机-1": [ + "支持固化千兆电口≥8 个,固化千兆光口≥2 个,桌面型设备;", + "支持静态链路聚合" + ] + "交换机-2":[ + "交换容量≥52Gbps,包转发率≥38.69Mpps,", + "提供国家强制性产品认证证书及测试报告(3C)" + ] +}} + """ queries = [] for key in keys_list: # 将键中的 '.' 替换为 '下的' modified_key = key.replace('.', '下的') # 使用修改后的键填充第一个占位符,原始键填充第二个占位符 - new_query = user_query_template.format(modified_key, key,modified_key) + new_query = user_query_template.format(modified_key, key, modified_key) + queries.append(new_query) + + # 处理 grouped_paths 中的项,应用 user_query_template_two + for grouped_key in grouped_paths: + # 将键中的 '.' 替换为 '下的' + modified_grouped_key = grouped_key.replace('.', '下的') + # 使用修改后的键填充第一个占位符,原始键填充第二个占位符 + new_query = user_query_template_two.format(modified_grouped_key, grouped_key, modified_grouped_key) queries.append(new_query) results = multi_threading(queries, "", file_id, 2) technical_requirements = [] @@ -146,13 +237,15 @@ def get_technical_requirements(file_id,invalid_path): for question, response in results: technical_requirements.append(response) technical_requirements_combined_res = combine_json_results(technical_requirements) + """根据所有键是否已添加处理技术要求""" # 更新原始采购需求字典 - combine_and_update_results(cleaned_res['技术要求'], technical_requirements_combined_res) - final_res = postprocess(cleaned_res) - final_res['技术要求']["货物列表"] = good_list #添加需要采购的货物 + update_res=combine_and_update_results(cleaned_res['采购需求'], technical_requirements_combined_res) + # final_res = postprocess(cleaned_res) + update_res["货物列表"] = good_list + # 输出最终的 JSON 字符串 - return final_res + return {"采购需求": update_res} def test_all_files_in_folder(input_folder, output_folder): # 确保输出文件夹存在 @@ -178,14 +271,14 @@ def test_all_files_in_folder(input_folder, output_folder): print(f"处理文件 {file_path} 时出错: {e}") if __name__ == "__main__": - # # truncate_file="D:\\flask_project\\flask_app\\static\\output\\output1\\bf225a5e-16d0-45c8-8c19-54a1a94cf3e2\\ztbfile_procurement.docx" + truncate_file="C:\\Users\\Administrator\\Desktop\\fsdownload\\469d2aee-9024-4993-896e-2ac7322d41b7\\ztbfile_procurement.docx" # # truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\zbfilesdocx\\招标文件(107国道).docx" # invalid_path="D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89\\ztbfile.pdf" # truncate_file="D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89\\ztbfile_procurement.docx" # output_folder="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\tmp" # file_id = upload_file(truncate_file) - invalid_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles\\包头市公安支队机动车查验监管系统招标文201907.pdf" - file_id="file-fe-FcOjv4FiOGjHRG1pKaFrIBeG" + invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile.pdf" + file_id=upload_file(truncate_file) res=get_technical_requirements(file_id,invalid_path) json_string = json.dumps(res, ensure_ascii=False, indent=4) print(json_string) diff --git a/flask_app/货物标/提取采购需求main.py b/flask_app/货物标/提取采购需求main.py index 84a1625..87fe3c0 100644 --- a/flask_app/货物标/提取采购需求main.py +++ b/flask_app/货物标/提取采购需求main.py @@ -7,17 +7,20 @@ from flask_app.货物标.商务服务其他要求提取 import get_business_requ #获取采购清单 -def fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path): +def fetch_procurement_reqs(procurement_path, procurement_docpath, invalid_path): # 定义默认的 procurement_reqs 字典 DEFAULT_PROCUREMENT_REQS = { + "采购需求": "", "技术要求": "", "商务要求": "", "服务要求": "", "其他要求": "" } - # 如果 truncate_file 是空字符串,直接返回包含空字符串的字典 + + # 如果 procurement_docpath 是空字符串,直接返回包含空字符串的字典 if not procurement_docpath: return DEFAULT_PROCUREMENT_REQS.copy() + try: # 上传文件并获取 file_id file_id = upload_file(procurement_docpath) @@ -25,22 +28,27 @@ def fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path): # 使用 ThreadPoolExecutor 并行处理 get_technical_requirements 和 get_business_requirements with concurrent.futures.ThreadPoolExecutor() as executor: # 提交任务给线程池 - future_technical = executor.submit(get_technical_requirements, file_id,invalid_path) - time.sleep(0.5) + future_technical = executor.submit(get_technical_requirements, file_id, invalid_path) + time.sleep(0.5) # 保持原有的延时 future_business = executor.submit(get_business_requirements, procurement_path, file_id) # 获取并行任务的结果 technical_requirements = future_technical.result() business_requirements = future_business.result() - # 构建最终的嵌套结构,确保四个键平级 + # 构建最终的采购需求字典 procurement_reqs = { - "技术要求": technical_requirements.get("技术要求", {}), - "商务要求": business_requirements.get("商务要求", {}), - "服务要求": business_requirements.get("服务要求", {}), - "其他要求": business_requirements.get("其他要求", {}), + "采购需求": technical_requirements.get("采购需求", "") } + # 合并 business_requirements 到 procurement_reqs 中 + # 这样无论 business_requirements 包含什么键(如 "技术要求"、"服务要求" 或 "技术、服务要求"),都将被保留 + procurement_reqs.update(business_requirements) + + # 如果需要确保所有默认键存在,可以取消下面的注释 + # for key, default_value in DEFAULT_PROCUREMENT_REQS.items(): + # procurement_reqs.setdefault(key, default_value) + return procurement_reqs except Exception as e: @@ -49,10 +57,13 @@ def fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path): return DEFAULT_PROCUREMENT_REQS.copy() if __name__ == "__main__": + start_time=time.time() output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\货物标output" # file_path="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\2-招标文件(2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目)_procurement.pdf" - procurement_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\a6168046-ad8c-43cb-8913-071ce7b248a1\\ztbfile_procurement.docx" - procurement_docpath="C:\\Users\\Administrator\\Desktop\\fsdownload\\a6168046-ad8c-43cb-8913-071ce7b248a1\\ztbfile_procurement.docx" - invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a6168046-ad8c-43cb-8913-071ce7b248a1\\ztbfile.pdf" + procurement_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_procurement.pdf" + procurement_docpath="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_procurement.docx" + invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile.pdf" res=fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path) print(json.dumps(res, ensure_ascii=False, indent=4)) + end_time=time.time() + print("耗时:"+str(end_time-start_time)) diff --git a/flask_app/货物标/货物标解析main.py b/flask_app/货物标/货物标解析main.py index 4238c73..17de695 100644 --- a/flask_app/货物标/货物标解析main.py +++ b/flask_app/货物标/货物标解析main.py @@ -244,8 +244,8 @@ def goods_bid_main(output_folder, file_path, file_type, unique_id): #广水市 2022 年义务教育学校多媒体补充采购项目 资格审查有问题 -#TODO:技术要求提取更全面一点 fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628 技术要求! #TODO:工程标的资格审查也增加第一章的内容。 +#TODO:工程标 资格审查 #good_list 金额 截取上下文 if __name__ == "__main__": # 配置日志器