From e591850da180aa7a6b14bb2dd2b78fc79ce378f1 Mon Sep 17 00:00:00 2001 From: zy123 <646228430@qq.com> Date: Sat, 19 Oct 2024 12:53:25 +0800 Subject: [PATCH] =?UTF-8?q?10.18=E5=B0=8F=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flask_app/general/little_zbparse.py | 6 +- flask_app/main/test.py | 266 ++---------------- flask_app/main/基础信息整合快速版.py | 135 ++++++--- flask_app/main/截取pdf.py | 27 +- flask_app/main/投标人须知正文提取指定内容.py | 22 +- .../提示词/是否相关问题qianwen-long.txt | 18 ++ .../投标人须知正文提取指定内容货物标版.py | 14 +- flask_app/货物标/货物标截取pdf.py | 5 +- 8 files changed, 207 insertions(+), 286 deletions(-) create mode 100644 flask_app/static/提示词/是否相关问题qianwen-long.txt diff --git a/flask_app/general/little_zbparse.py b/flask_app/general/little_zbparse.py index c32fe64..dfd4717 100644 --- a/flask_app/general/little_zbparse.py +++ b/flask_app/general/little_zbparse.py @@ -38,7 +38,8 @@ def little_parse_goods(output_folder, file_path): dict: 包含 '基础信息' 的字典。 """ # 截取特定的货物 PDF 文件 - files = truncate_pdf_specific_goods(file_path, output_folder) + selections = [4, 5] # 仅处理 selection 4 和 5 + files = truncate_pdf_specific_goods(file_path, output_folder,selections) if not files: raise ValueError("未找到截取后的文件。") # 假设最后一个文件是需要处理的基础信息文件 @@ -71,7 +72,8 @@ def little_parse_engineering(output_folder, file_path): dict: 包含 '基础信息' 的字典。 """ # 截取特定的工程 PDF 文件 - files = truncate_pdf_specific_engineering(file_path, output_folder) + selections = [5, 1,3] + files = truncate_pdf_specific_engineering(file_path, output_folder,selections) if not files: raise ValueError("未找到截取后的文件。") # 假设最后一个文件是需要处理的基础信息文件 diff --git a/flask_app/main/test.py b/flask_app/main/test.py index 1d51832..b618d15 100644 --- a/flask_app/main/test.py +++ b/flask_app/main/test.py @@ -1,242 +1,36 @@ -import re +def second_query(baseinfo_list): + result_list = [] + for item in baseinfo_list: + for key, value in item.items(): + if isinstance(value, dict): + # 检查所有最内层的值是否都是 "未知" + if all(v == "未知" for v in value.values()): + result_list.append(key) + return result_list -data={ - "基础信息": { - "招标人/代理信息": { - "招标人": "广水市公安局", - "招标人联系方式": { - "名称": "广水市公安局", - "联系电话": "0722-6248000", - "地址": "广水市应山办事处应十大道189号" - }, - "招标代理机构": "湖北楚振捷工程项目管理有限公司", - "招标代理机构联系方式": { - "名称": "湖北楚振捷工程项目管理有限公司", - "联系电话": "0722-6256088", - "地址": "广水市永阳一路41号" - }, - "项目联系方式": { - "名称": "吴凡", - "联系电话": "18871130808" - } +# 示例用法 +baseinfo_list = [ + { + "招标人联系方式": { + "名称": "未知", + "地址": "未知", }, - "项目信息": { - "项目名称": "广水市公安局视频会议高清化改造项目", - "项目编号": "HBCZJ-2021-CS12", - "项目概况": "广水市公安局视频会议高清化改造项目", - "项目基本情况": { - "项目编号": "HBCZJ-2021-CS12", - "采购计划备案号": "2021-04-000399", - "项目名称": "广水市公安局视频会议高清化改造项目", - "采购方式": "竞争性磋商", - "预算金额": "192万元", - "最高限价": "192万元", - "采购需求": { - "项目概况及内容": "广水市公安局视频会议高清化改造项目。", - "招标范围": "广水市公安局视频会议高清化改造项目,具体内容见磋商文件第三章。", - "项目地点": "具体以合同约定为准。" - }, - "合同履行期限": "以合同签订为准。", - "本项目(是/否)接受联合体投标": "否", - "是否可采购进口产品": "否" - }, - "招标控制价": "192万元", - "投标竞争下浮率": "未知", - "是否允许分包": "未知", - "是否接受联合体投标": "否" + "项目名称": { + "名称": "项目A", + "地址": "未知", + } + }, + { + "供应商信息": { + "名称": "未知", + "联系方式": "未知", }, - "采购要求": { - "技术要求": "未提供", - "商务要求": "未提供", - "服务要求": "未提供", - "其他要求": "未提供" - }, - "关键时间/内容": { - "投标文件递交截止日期": "2021年 6月 18日 15点 00分", - "投标文件递交地点": "广水市公共资源交易中心五楼 501号开标室", - "开标时间": "2021年 6月 18日 15点 00分", - "开标地点": "广水市公共资源交易中心五楼 501号开标室", - "澄清招标文件的截止时间": "同采购文件获取截止时间(如有)", - "投标有效期": "90日历天", - "信息公示媒介": "中国湖北政府采购网:http://www.ccgp-hubei.gov.cn, 中国广水网:http://www.zggsw.gov.cn/" - }, - "保证金相关": { - "投标保证金": "不提交", - "履约保证金": "不提交", - "是否递交磋商保证金": "否", - "退还投标保证金": "/", - "质量保证金": "未知" - }, - "其他信息": { - "投标费用承担": "供应商应承担所有与准备和参加磋商有关的费用,不论磋商的结果如何,采购人和采购代理机构均无义务和责任承担这些费用。", - "招标代理服务费": { - "收费标准": "根据国家发展与改革委员会办公厅发改办价格【2003】857 号文的规定,经协商由成交供应商按国家发展和改革委员发改价格【2011】534号文规定货物类取费标准向采购代理机构支付招标代理服务费(包含“招标代理费、评标会务费、评标费”),如本项目各包服务费不足叁仟元则供应商按叁仟元支付服务费。", - "递交方式": "成交服务费由成交供应商在领取成交通知书的同时向代理机构支付,可使用现金或电汇办理,汇款账户信息如下: 账户名:湖北楚振捷工程项目管理有限公司 账户号码:580742561314 开户银行:中国银行股份有限公司广水支行营业部" - }, - "是否退还投标文件": "否", - "是否召开投标答疑会": "否", - "投标预备会": "不召开", - "踏勘现场": "不组织", - "偏离": { - "偏离项要求": "供应商需在响应文件中提供《采购需求响应、偏离说明表/导读表》,具体格式见第六章响应文件格式中的49页。供应商需对采购需求中的各项技术参数和服务要求进行逐项响应,明确表明无偏离、正偏离或负偏离的情况。", - "正偏离定义": "供应商提供的产品或服务优于采购需求中的技术参数和服务要求。", - "负偏离定义": "供应商提供的产品或服务未能完全满足采购需求中的技术参数和服务要求。", - "偏离项处理": "非★号条款允许的负偏离项数及范围见第四章评标办法,★号条款不允许负偏离。", - "偏离项数量限制": "非★号条款允许的负偏离项数及范围见第四章评标办法,具体数量限制未知。", - "偏离项评分影响": "负偏离可能会影响供应商的评分,具体评分标准见第四章评定办法。" - } + "合同详情": { + "金额": "100万", + "期限": "未知", } } -} -def inner_post_processing(base_info): - """ - 处理 '基础信息' 部分,提取所需字段。 +] - 参数: - base_info (dict): 包含 '基础信息' 的字典。 - - 返回: - dict: 提取的信息字典 extracted_info。 - """ - # 初始化提取的信息字典 - extracted_info = {} - - # 定义一个辅助函数用于获取嵌套字典中的值 - def get_nested(dic, keys, default=None): - for key in keys: - if isinstance(dic, dict): - dic = dic.get(key, default) - else: - return default - return dic - - # 定义一个辅助函数用于递归查找包含特定子字符串的键 - def find_keys_containing(dic, substring): - found_values = [] - if isinstance(dic, dict): - for key, value in dic.items(): - if substring in key: - found_values.append(value) - if isinstance(value, dict): - found_values.extend(find_keys_containing(value, substring)) - elif isinstance(value, list): - for item in value: - if isinstance(item, dict): - found_values.extend(find_keys_containing(item, substring)) - return found_values - - # 定义一个辅助函数用于根据候选键列表提取值(部分匹配) - def extract_field(contact_info, candidate_keys): - for candidate in candidate_keys: - for key, value in contact_info.items(): - if candidate in key and value not in ["未知", ""]: - return value - return "" - - # 定义一个辅助函数用于提取 '投标保证金' - def extract_bid_bond(guarantee_info): - # 定义投标保证金的候选键 - bid_bond_candidates = ["投标保证金", "磋商保证金"] - - # 第一步:查找包含 "投标保证金" 或 "磋商保证金" 的键 - for candidate in bid_bond_candidates: - for key, value in guarantee_info.items(): - if candidate in key: - if isinstance(value, dict): - # 在嵌套字典中查找包含 "金额" 的键 - for sub_key, sub_value in value.items(): - if "金额" in sub_key and sub_value not in ["未知", ""]: - return sub_value - elif isinstance(value, str): - if "金额" in key and value not in ["未知", ""]: - return value - else: - # 如果 value 既不是 dict 也不是 str,忽略 - continue - - # 第二步:如果没有找到包含 "金额" 的键,尝试在所有键值中查找符合模式的值 - amount_pattern = re.compile(r'(?:\d{1,3}(?:[,,]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?|[\u4e00-\u9fff]+(?:\.\d+)?)\s*(?:元|万元)') - for key, value in guarantee_info.items(): - if isinstance(value, str): - match = amount_pattern.search(value) - if match: - return match.group() - elif isinstance(value, dict): - # 递归查找嵌套字典中的金额 - found_amount = extract_bid_bond(value) - if found_amount: - return found_amount - # 如果都没有找到,则返回空字符串 - return "" - - # 定义所需字段的映射关系,暂时不包含'联系人'和'联系电话'以及'招标项目地点' - mapping = { - "代理机构名称": [["招标人/代理信息", "招标代理机构"]], - "招标项目名称": [["项目信息", "项目名称"], ["项目信息", "工程名称"]], - "招标项目编号": [["项目信息", "项目编号"], ["项目信息", "招标编号"]], - "开标时间": [["关键时间/内容", "开标时间"]], - "报名截止日期": [["关键时间/内容", "投标文件递交截止日期"]], - "招标项目预算": [["项目信息", "招标控制价"]], - "招标单位名称": [["招标人/代理信息", "招标人"]], - "招标公告地址": [["关键时间/内容", "信息公示媒介"], ["关键时间/内容", "评标结果公示媒介"]] - } - - # 提取并映射字段 - for new_key, paths in mapping.items(): - value = None - for path in paths: - value = get_nested(base_info, path) - if value: - break - extracted_info[new_key] = value if value else "" - - # 特殊处理 '招标项目地点' - # 在 '项目信息' 下查找包含 "地点" 的键 - project_info = base_info.get("项目信息", {}) - location_candidates = find_keys_containing(project_info, "地点") - if location_candidates: - # 选择第一个找到的地点 - extracted_info["招标项目地点"] = location_candidates[0] - else: - extracted_info["招标项目地点"] = "" - - # 特殊处理 '联系人' 和 '联系电话' - # 提取 '项目联系方式' - project_contact = get_nested(base_info, ["招标人/代理信息", "项目联系方式"], {}) - - # 提取 '招标人联系方式' - bidder_contact = get_nested(base_info, ["招标人/代理信息", "招标人联系方式"], {}) - - # 定义候选键列表,按优先级排序 - name_candidates = ["名称", "联系人", "招标"] - phone_candidates = ["电话", "手机", "联系方式"] - - # 提取 '联系人' - contact_names = [project_contact, bidder_contact] - contact_name = "" - for contact in contact_names: - extracted_name = extract_field(contact, name_candidates) - if extracted_name: - contact_name = extracted_name - break - extracted_info["联系人"] = contact_name - - # 提取 '联系电话' - contact_phones = [project_contact, bidder_contact] - contact_phone = "" - for contact in contact_phones: - extracted_phone = extract_field(contact, phone_candidates) - if extracted_phone: - contact_phone = extracted_phone - break - extracted_info["联系电话"] = contact_phone - - # 特殊处理 '投标保证金' - # 提取 '保证金相关' - guarantee_info = get_nested(base_info, ["保证金相关"], {}) - extracted_info["投标保证金"] = extract_bid_bond(guarantee_info) - - return extracted_info - -res=inner_post_processing(data["基础信息"]) -print(res) \ No newline at end of file +result = second_query(baseinfo_list) +print(result) # 输出: ['招标人联系方式', '供应商信息'] diff --git a/flask_app/main/基础信息整合快速版.py b/flask_app/main/基础信息整合快速版.py index 3bcb88e..3d44dde 100644 --- a/flask_app/main/基础信息整合快速版.py +++ b/flask_app/main/基础信息整合快速版.py @@ -1,8 +1,10 @@ import json +import threading +import time from flask_app.main.json_utils import clean_json_string, nest_json_under_key,rename_outer_key from flask_app.main.投标人须知正文提取指定内容 import extract_from_notice -from flask_app.main.判断是否分包等 import judge_whether_main, read_questions_from_judge +from flask_app.main.判断是否分包等 import judge_whether_main, read_questions_from_judge, merge_json_to_list from flask_app.main.多线程提问 import read_questions_from_file, multi_threading from flask_app.main.通义千问long import upload_file @@ -110,7 +112,70 @@ def judge_consortium_bidding(baseinfo_list): # 更新原始列表,如果你想保留修改 baseinfo_list[:] = updated_list return accept_bidding -def combine_basic_info(merged_baseinfo_path,truncate0, output_folder, clause_path): + +def generate_query(baseinfo_list): + questions_list = [] + for item in baseinfo_list: + # print(json.dumps(item, ensure_ascii=False, indent=4)) + for key, value in item.items(): + if value == "未知" or (isinstance(value, dict) and all(v == "未知" for v in value.values())): + question = ( + f"根据该招标文件中的信息,{key}的内容是怎样的?" + f"请按json格式给我提供信息,键名是'{key}'," + f"若存在未知信息,在对应的键值中填'未知'。" + ) + questions_list.append(question) + return questions_list + +def update_baseinfo_lists(baseinfo_list1, baseinfo_list2): + # 创建一个字典,用于存储 baseinfo_list1 中的所有键值对 + combined_dict = {} + for item in baseinfo_list1: + combined_dict.update(item) + + # 使用 baseinfo_list2 中的信息更新 combined_dict + for item in baseinfo_list2: + for key, value in item.items(): + if key in combined_dict: + combined_dict[key] = value + + # 重新构建 baseinfo_list1,保持原有的结构 + updated_list = [] + for item in baseinfo_list1: + updated_item = {} + for key in item: + updated_item[key] = combined_dict[key] + updated_list.append(updated_item) + + return updated_list + +def process_judge_questions(judge_file_path, chosen_numbers, truncate0, baseinfo_list1): + judge_questions = read_questions_from_judge(judge_file_path, chosen_numbers) + judge_consortium = judge_consortium_bidding(baseinfo_list1) + if judge_consortium: + judge_consortium_question = ( + "该招标文件对于联合体投标的要求是怎样的,请按json格式给我提供信息," + "外层键名为'联合体投标要求',其中有一个嵌套键值对为:\"是否接受联合体投标\":\"是\"" + ) + judge_questions.append(judge_consortium_question) + file_id3 = upload_file(truncate0) + res2 = multi_threading(judge_questions, "", file_id3, 2) + + if not res2: + print("基础信息整合: multi_threading error!") + else: + for question, response in res2: + baseinfo_list1.append(clean_json_string(response)) + +def process_questions_list(questions_list, truncate2): + if questions_list: + file_id = upload_file(truncate2) + baseinfo_results = multi_threading(questions_list, "", file_id, 2) + return [clean_json_string(res) for _, res in baseinfo_results] if baseinfo_results else [] + else: + return [] + +def combine_basic_info(merged_baseinfo_path,truncate0,truncate2, clause_path): """ 综合和处理基础信息,生成最终的基础信息字典。 @@ -124,54 +189,60 @@ def combine_basic_info(merged_baseinfo_path,truncate0, output_folder, clause_pat - dict: 综合后的基础信息。 """ # baseinfo_prompt_file_path='flask_app/static/提示词/基本信息工程标qianwen-long.txt' + file_id1 = upload_file(merged_baseinfo_path) baseinfo_prompt_file_path = 'D:\\flask_project\\flask_app\\static\\提示词\\基本信息工程标qianwen-long.txt' questions = read_questions_from_file(baseinfo_prompt_file_path) - file_id = upload_file(merged_baseinfo_path) - baseinfo_results = multi_threading(questions, "", file_id, 2) - # 清理 JSON 字符串 - baseinfo_list = [clean_json_string(res) for _, res in baseinfo_results] if baseinfo_results else [] - for i in baseinfo_list: - print(json.dumps(i,ensure_ascii=False,indent=4)) - # 判断是否分包、是否需要递交投标保证金等 - chosen_numbers, merged = judge_whether_main(truncate0, output_folder) - baseinfo_list.append(merged) + more_query = "请你根据招标文件信息,回答以下问题:是否组织踏勘现场?是否召开投标预备会?是否允许偏离?是否退还投标文件?是否允许分包? 是否需要递交投标保证金?是否需要提交履约保证金(履约担保)?是否有招标代理服务费?请按json格式给我提供信息,键名分别为'是否组织踏勘现场','是否召开投标预备会','是否允许偏离','是否退还投标文件',是否允许分包','是否递交投标保证金','是否提交履约保证金','是否有招标代理服务费',键值仅限于'是','否','未知',若存在矛盾信息,请回答'未知'。" + questions.append(more_query) + baseinfo_results = multi_threading(questions, "", file_id1, 2) + # 清理 JSON 字符串 + baseinfo_list1 = [clean_json_string(res) for _, res in baseinfo_results] if baseinfo_results else [] - # judge_file_path = 'flask_app/static/提示词/是否相关问题.txt' - judge_file_path = 'D:\\flask_project\\flask_app\\static\\提示词\\是否相关问题.txt' - judge_questions = read_questions_from_judge(judge_file_path, chosen_numbers) - judge_consortium = judge_consortium_bidding(baseinfo_list) # 通过招标公告判断是否接受联合体投标 + chosen_numbers, merged = merge_json_to_list(baseinfo_list1.pop()) + baseinfo_list1.append(merged) - if judge_consortium: - judge_consortium_question = ( - "该招标文件对于联合体投标的要求是怎样的,请按json格式给我提供信息," - "外层键名为'联合体投标要求',其中有一个嵌套键值对为:\"是否接受联合体投标\":\"是\"" - ) - judge_questions.append(judge_consortium_question) + questions_list=generate_query(baseinfo_list1) - file_id = upload_file(truncate0) - res2 = multi_threading(judge_questions, "", file_id, 2) # 调用千问-long + # judge_file_path = 'flask_app/static/提示词/是否相关问题qianwen-long.txt' + judge_file_path = 'D:\\flask_project\\flask_app\\static\\提示词\\是否相关问题qianwen-long.txt' + # 创建两个线程 + thread1 = threading.Thread(target=process_judge_questions, + args=(judge_file_path, chosen_numbers, truncate0, baseinfo_list1)) + thread2 = threading.Thread(target=process_questions_list, args=(questions_list, truncate2)) - if not res2: - print("基础信息整合: multi_threading error!") - else: - for question, response in res2: - baseinfo_list.append(clean_json_string(response)) + # 启动线程 + thread1.start() + thread2.start() + + # 等待两个线程完成 + thread1.join() + thread2.join() + + # 处理结果 + # baseinfo_list1 已经在 process_judge_questions 中被更新 + baseinfo_list2 = process_questions_list(questions_list, truncate2) + + updated_list=update_baseinfo_lists(baseinfo_list1,baseinfo_list2) rebidding_situation = extract_from_notice(clause_path, 3) # "重新招标, 不再招标和终止招标"需从投标人须知正文提取 update_json = rename_outer_key(rebidding_situation, "重新招标、不再招标和终止招标") - baseinfo_list.append(update_json) - aggregated_baseinfo = aggregate_basic_info_engineering(baseinfo_list) # 现在是一个字典 + updated_list.append(update_json) + aggregated_baseinfo = aggregate_basic_info_engineering(updated_list) # 现在是一个字典 return {"基础信息": aggregated_baseinfo} #TODO:先不带投标人须知正文,如果是未知,再直接问正文, if __name__ == "__main__": + start_time=time.time() merged_baseinfo_path="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output\\zbtest2_merged_baseinfo.pdf" - output_folder="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output" + # output_folder="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output" truncate0="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output\\zbtest2_tobidders_notice_table.pdf" + truncate2="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output\\zbtest2_tobidders_notice.pdf" clause_path="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output\\clause1.json" - res=combine_basic_info(merged_baseinfo_path,truncate0,output_folder,clause_path) + res=combine_basic_info(merged_baseinfo_path,truncate0,truncate2,clause_path) print(json.dumps(res,ensure_ascii=False,indent=4)) + end_time=time.time() + print("elapsed_time:"+str(end_time-start_time)) diff --git a/flask_app/main/截取pdf.py b/flask_app/main/截取pdf.py index f691c81..3ef77bf 100644 --- a/flask_app/main/截取pdf.py +++ b/flask_app/main/截取pdf.py @@ -290,13 +290,28 @@ def truncate_pdf_main(input_path, output_folder, selection): return process_input(input_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix) -def truncate_pdf_multiple(input_path, output_folder): +def truncate_pdf_multiple_old(input_path, output_folder): truncate_files = [] for selection in range(1, 5): files = truncate_pdf_main(input_path, output_folder, selection) truncate_files.extend(files) return truncate_files +def truncate_pdf_multiple(input_path, output_folder): + base_file_name = os.path.splitext(os.path.basename(input_path))[0] #纯文件名 + truncate_files = [] + for selection in range(1, 6): + files = truncate_pdf_main(input_path, output_folder, selection) + truncate_files.extend(files) + if truncate_files: + merged_output_path = os.path.join(output_folder, f"{base_file_name}_merged_baseinfo.pdf") + merge_selected_pdfs(output_folder, truncate_files, merged_output_path,base_file_name) + truncate_files.append(merged_output_path) + print(f"已生成合并文件: {merged_output_path}") + else: + print(f"没有文件需要合并 for {input_path}") + return truncate_files + def merge_selected_pdfs(output_folder, truncate_files, output_path, base_file_name): """ 合并 output_folder 中以 {base_file_name}_before.pdf 结尾的 PDF 文件, @@ -359,7 +374,7 @@ def merge_selected_pdfs(output_folder, truncate_files, output_path, base_file_na merge_pdfs(all_pdfs_to_merge, output_path) print(f"已成功合并 PDF 文件到 '{output_path}'。") -def truncate_pdf_specific_engineering(pdf_path, output_folder): +def truncate_pdf_specific_engineering(pdf_path, output_folder,selections): """ 处理 PDF 文件,选择 selection 为 5、1 和 3 的部分,并合并结果。 @@ -373,7 +388,6 @@ def truncate_pdf_specific_engineering(pdf_path, output_folder): try: base_file_name = os.path.splitext(os.path.basename(pdf_path))[0] truncate_files = [] - selections = [5, 1, 3] # 仅处理 selection 5、1 和 3 for selection in selections: files = truncate_pdf_main(pdf_path, output_folder, selection) @@ -402,10 +416,11 @@ def truncate_pdf_specific_engineering(pdf_path, output_folder): if __name__ == "__main__": # input_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\4bda9fde-89fc-4e5e-94a4-ce6c43010f74\\ztbfile.pdf" # output_folder = "C:\\Users\\Administrator\\Desktop\\fsdownload\\4bda9fde-89fc-4e5e-94a4-ce6c43010f74" - input_path="C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\zbtest16.pdf" + input_path="C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\zbtest2.pdf" output_folder="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output" - # files=truncate_pdf_multiple(input_path,output_folder) - files=truncate_pdf_specific_engineering(input_path,output_folder) + files=truncate_pdf_multiple(input_path,output_folder) + # selections = [5, 1] # 仅处理 selection 5、1 和 3 + # files=truncate_pdf_specific_engineering(input_path,output_folder,selections) print(files) # selection = 3 # 例如:1 - 投标人须知前附表, 2 - 评标办法, 3 - 投标人须知正文 4-资格审查条件 5-招标公告 6-无效标 # generated_files = truncate_pdf_main(input_path, output_folder, selection) diff --git a/flask_app/main/投标人须知正文提取指定内容.py b/flask_app/main/投标人须知正文提取指定内容.py index 5845a9d..24f6ecc 100644 --- a/flask_app/main/投标人须知正文提取指定内容.py +++ b/flask_app/main/投标人须知正文提取指定内容.py @@ -219,7 +219,12 @@ def post_process(value): return processed_blocks -# 递归地处理嵌套结构 +""" +递归处理嵌套的数据结构(字典和列表)。 +对最内层的字符串值应用 post_process 函数。 +post_process 函数尝试将长字符串按特定模式分割成块,每块至少包含50个中英文字符。 +如果字典中所有值都是 ""、"/" 或空列表,则返回'键'的列表。 +""" def process_nested_data(data): # 先检查是否所有值都是 ""、"/" 或空列表 if isinstance(data, dict) and all(v == "" or v == "/" or (isinstance(v, list) and not v) for v in data.values()): @@ -229,7 +234,12 @@ def process_nested_data(data): # 如果当前项是字典,继续递归遍历其键值对 result = {} for key, value in data.items(): - result[key] = process_nested_data(value) # 递归处理子项 + processed_value = process_nested_data(value) + # 如果处理后的值是只有一个元素的列表,就直接使用该元素 + if isinstance(processed_value, list) and len(processed_value) == 1: + result[key] = processed_value[0] + else: + result[key] = processed_value return result elif isinstance(data, list): # 如果是列表,直接返回列表,保持原样 @@ -239,6 +249,8 @@ def process_nested_data(data): return post_process(data) + + # 读取JSON数据,提取内容,转换结构,并打印结果 def extract_from_notice(clause_path, type): if type == 1: @@ -258,6 +270,7 @@ def extract_from_notice(clause_path, type): # print(json.dumps(extracted_data,ensure_ascii=False,indent=4)) sorted_data = sort_clean_data_keys(extracted_data) # 对输入的字典 data 的键进行预处理和排序 transformed_data = transform_json(sorted_data) + # print(json.dumps(transformed_data,ensure_ascii=False,indent=4)) final_result = process_nested_data(transformed_data) return final_result @@ -265,10 +278,9 @@ def extract_from_notice(clause_path, type): # TODO: extract_json新版本仍有问题,未知。 if __name__ == "__main__": # file_path = 'C:\\Users\\Administrator\\Desktop\\fsdownload\\3bffaa84-2434-4bd0-a8ee-5c234ccd7fa0\\clause1.json' - # file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\tmp1\\clause9.json' - file_path="C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\clause1.json" + file_path="C:\\Users\\Administrator\\Desktop\\招标文件\\special_output\\clause1.json" try: - res = extract_from_notice(file_path, 2) # 可以改变此处的 type 参数测试不同的场景 + res = extract_from_notice(file_path, 1) # 可以改变此处的 type 参数测试不同的场景 res2 = json.dumps(res, ensure_ascii=False, indent=4) print(res2) except ValueError as e: diff --git a/flask_app/static/提示词/是否相关问题qianwen-long.txt b/flask_app/static/提示词/是否相关问题qianwen-long.txt new file mode 100644 index 0000000..578b788 --- /dev/null +++ b/flask_app/static/提示词/是否相关问题qianwen-long.txt @@ -0,0 +1,18 @@ +1.该招标文件对于分包的要求是怎样的?请按json格式给我提供信息,键名为'分包'。 + +2.根据招标文件第二章投标人须知,该项目投标保证金的内容或要求是什么?请按json格式给我提供信息,外层键名为"投标保证金",若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 + +3.该招标文件对于投标保证金的退还相关的规章办法是怎样的?请按json格式给我提供信息,键名为'退还投标保证金',若存在嵌套信息,嵌套内容键名以文档中对应字段命名。示例格式如下: +{ + "退还投标保证金":"投标保证金的退还按《xxx》相关条款执行。" +} + +4.根据投标人须知前附表,该项目对于履约保证金(履约担保)的内容或要求是怎样的,请按json格式给我提供信息,外层键名为"履约保证金",若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 + +5.本项目的招标代理服务费(或中标服务费、成交服务费)的相关内容是怎样的,请按json格式给我提供信息,外层键名为'招标代理服务费',若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 + +6.该招标文件对于踏勘现场的内容或要求是怎样的,请按json格式给我提供信息,外层键名为"踏勘现场",若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 + +7.该招标文件对于投标预备会(或投标答疑会)内容是怎样的,请按json格式给我提供信息,外层键名为"投标预备会"(或"投标答疑会"),若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 + +8.本项目可偏离的项目和范围是怎样的?请以json格式给我提供信息,外层键名为'偏离',若需要以嵌套键值对返回结果,那么嵌套键名为你对相应要求的总结,而对应键值需要完全与原文保持一致。 \ No newline at end of file diff --git a/flask_app/货物标/投标人须知正文提取指定内容货物标版.py b/flask_app/货物标/投标人须知正文提取指定内容货物标版.py index 9ad7381..ffd0dcd 100644 --- a/flask_app/货物标/投标人须知正文提取指定内容货物标版.py +++ b/flask_app/货物标/投标人须知正文提取指定内容货物标版.py @@ -175,7 +175,12 @@ def post_process(value): # 如果所有的块都符合条件,返回分割后的列表 return processed_blocks -# 递归地处理嵌套结构 +""" +递归处理嵌套的数据结构(字典和列表)。 +对最内层的字符串值应用 post_process 函数。 +post_process 函数尝试将长字符串按特定模式分割成块,每块至少包含50个中英文字符。 +如果字典中所有值都是 ""、"/" 或空列表,则返回'键'的列表。 +""" def process_nested_data(data): # 先检查是否所有值都是 ""、"/" 或空列表 if isinstance(data, dict) and all(v == "" or v == "/" or (isinstance(v, list) and not v) for v in data.values()): @@ -185,7 +190,12 @@ def process_nested_data(data): # 如果当前项是字典,继续递归遍历其键值对 result = {} for key, value in data.items(): - result[key] = process_nested_data(value) # 递归处理子项 + processed_value = process_nested_data(value) + # 如果处理后的值是只有一个元素的列表,就直接使用该元素 + if isinstance(processed_value, list) and len(processed_value) == 1: + result[key] = processed_value[0] + else: + result[key] = processed_value return result elif isinstance(data, list): # 如果是列表,直接返回列表,保持原样 diff --git a/flask_app/货物标/货物标截取pdf.py b/flask_app/货物标/货物标截取pdf.py index 703e198..1db6b4d 100644 --- a/flask_app/货物标/货物标截取pdf.py +++ b/flask_app/货物标/货物标截取pdf.py @@ -576,7 +576,7 @@ def truncate_pdf_multiple(pdf_path, output_folder): return truncate_files #小解析,只需要前三章内容 -def truncate_pdf_specific_goods(pdf_path, output_folder): +def truncate_pdf_specific_goods(pdf_path, output_folder,selections): """ 处理 PDF 文件,选择 selection 为 4 和 5 的部分,并合并结果。 @@ -589,7 +589,6 @@ def truncate_pdf_specific_goods(pdf_path, output_folder): """ base_file_name = os.path.splitext(os.path.basename(pdf_path))[0] truncate_files = [] - selections = [4, 5] # 仅处理 selection 4 和 5 for selection in selections: files = truncate_pdf_main(pdf_path, output_folder, selection) @@ -615,7 +614,7 @@ if __name__ == "__main__": # input_path = "C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles\\交警支队机动车查验监管系统项目采购.pdf" input_path = "C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles" output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\截取test" - # files = truncate_pdf_multiple(input_path, output_folder) + files = truncate_pdf_multiple(input_path, output_folder) # files=truncate_pdf_specific_goods(input_path,output_folder) # print(files) selection = 1# 例如:1 - 商务技术服务要求, 2 - 评标办法, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-公告