11.8采购要求更加完整
This commit is contained in:
parent
3be755df51
commit
d6ab5f8f1b
@ -96,7 +96,7 @@ def extract_text_by_page(file_path):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
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='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\\货物标\\output4\\磋商文件_tobidders_notice_part2.pdf'
|
||||||
# file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\截取test\\交警支队机动车查验监管系统项目采购_tobidders_notice_part1.pdf'
|
# file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\截取test\\交警支队机动车查验监管系统项目采购_tobidders_notice_part1.pdf'
|
||||||
# file_path = "C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\zbtest8.pdf"
|
# file_path = "C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹\\zbtest8.pdf"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import random
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
# -*- encoding:utf-8 -*-
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from PyPDF2 import PdfReader
|
from PyPDF2 import PdfReader
|
||||||
@ -10,12 +11,13 @@ from flask_app.货物标.截取pdf货物标版 import extract_common_header, cle
|
|||||||
#正则表达式判断原文中是否有商务、服务、其他要求
|
#正则表达式判断原文中是否有商务、服务、其他要求
|
||||||
def find_exists(truncate_file, required_keys):
|
def find_exists(truncate_file, required_keys):
|
||||||
if not truncate_file:
|
if not truncate_file:
|
||||||
return ["商务要求", "服务要求", "其他要求"]
|
return ["技术要求","商务要求", "服务要求", "其他要求"]
|
||||||
common_header = extract_common_header(truncate_file)
|
common_header = extract_common_header(truncate_file)
|
||||||
pdf_document = PdfReader(truncate_file)
|
pdf_document = PdfReader(truncate_file)
|
||||||
text = ""
|
text = ""
|
||||||
|
|
||||||
begin_pattern = re.compile(
|
begin_pattern = re.compile(
|
||||||
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务).*?要求|'
|
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务|技术).*?要求|'
|
||||||
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:采购|技术标准).*|'
|
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:采购|技术标准).*|'
|
||||||
r'^[一二三四五六七八九十百千]+、\s*采购清单', re.MULTILINE)
|
r'^[一二三四五六七八九十百千]+、\s*采购清单', re.MULTILINE)
|
||||||
end_pattern = re.compile(
|
end_pattern = re.compile(
|
||||||
@ -62,7 +64,7 @@ def find_exists(truncate_file, required_keys):
|
|||||||
def generate_queries(truncate_file, required_keys):
|
def generate_queries(truncate_file, required_keys):
|
||||||
key_list = find_exists(truncate_file, required_keys)
|
key_list = find_exists(truncate_file, required_keys)
|
||||||
queries = []
|
queries = []
|
||||||
user_query_template = "这是一份货物标中采购要求部分的内容,请告诉我\"{}\"是什么,请以json格式返回结果,外层键名是\"{}\",内层键值对中的键是你对该要求的总结,而值需要完全与原文保持一致,不可擅自总结删减,注意你无需回答具体设备的技术要求。"
|
user_query_template = "这是一份货物标中采购要求部分的内容,请告诉我\"{}\"是什么,请以json格式返回结果,外层键名是\"{}\",内层键值对中的键名是原文中的标题或者是你对相关子要求的总结,而键值需要完全与原文保持一致,不可擅自总结删减,注意你无需回答采购清单中具体设备的技术参数要求,仅需从正文部分开始提取,"
|
||||||
for key in key_list:
|
for key in key_list:
|
||||||
query_base = user_query_template.format(key, key)
|
query_base = user_query_template.format(key, key)
|
||||||
other_keys = [k for k in key_list if k != 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):
|
def get_business_requirements(truncate_file,file_id):
|
||||||
required_keys = ["商务要求", "服务要求", "其他要求"]
|
# required_keys = ["技术要求","商务要求", "服务要求", "其他要求"]
|
||||||
queries = generate_queries(truncate_file, required_keys)
|
# queries = generate_queries(truncate_file, required_keys)
|
||||||
|
#一起问了,效率慢点,但内容准
|
||||||
|
queries=[
|
||||||
|
"""
|
||||||
|
请你根据该货物类招标文件中的采购要求部分内容,请告诉我文档中技术要求、服务要求、商务要求、其他要求分别是什么,请以json格式返回结果,可以用嵌套键值对的形式组织回答,默认情况下外层键名是'技术要求','服务要求','商务要求','其他要求',内层键名是原文中的相应子标题或者是你对相关子要求的总结,而键值需要完全与原文保持一致,不可擅自总结删减。注意你无需回答采购清单中具体设备的技术参数要求,仅需从正文部分开始提取。以下是你需要考虑的特殊情况:如果原文中技术要求与服务要求在一块,那么你应该用外键'技术、服务要求'替换默认外键'技术要求'和'服务要求',若相关要求不存在,对应的键值设为'未知'。以下为示例输出,仅供格式参考:
|
||||||
|
{
|
||||||
|
"技术、服务要求":"相关技术要求以及服务要求",
|
||||||
|
"商务要求":"相关商务要求",
|
||||||
|
"其他要求":"其他要求内容"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
]
|
||||||
results = multi_threading(queries, "", file_id, 2)
|
results = multi_threading(queries, "", file_id, 2)
|
||||||
business_requirements = [res for _, res in results] if results else []
|
business_requirements = [res for _, res in results] if results else []
|
||||||
|
|
||||||
# Combine and fill missing keys with default values
|
# Combine and fill missing keys with default values
|
||||||
final_res = combine_json_results(business_requirements)
|
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
|
return final_res
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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)
|
file_id = upload_file(truncate_file)
|
||||||
res=get_business_requirements(truncate_file,file_id)
|
res=get_business_requirements(truncate_file,file_id)
|
||||||
print(json.dumps(res, ensure_ascii=False, indent=4))
|
print(json.dumps(res, ensure_ascii=False, indent=4))
|
||||||
|
@ -27,7 +27,7 @@ def aggregate_basic_info_goods(baseinfo_list):
|
|||||||
key_groups = {
|
key_groups = {
|
||||||
"招标人/代理信息": ["招标人", "招标人联系方式", "招标代理机构", "招标代理机构联系方式","项目联系方式"],
|
"招标人/代理信息": ["招标人", "招标人联系方式", "招标代理机构", "招标代理机构联系方式","项目联系方式"],
|
||||||
"项目信息": ["项目名称", "项目编号", "项目概况", "项目基本情况", "招标控制价", "投标竞争下浮率"],
|
"项目信息": ["项目名称", "项目编号", "项目概况", "项目基本情况", "招标控制价", "投标竞争下浮率"],
|
||||||
"采购要求": ["技术要求","商务要求","服务要求","其他要求"],
|
"采购要求": ["采购需求","技术要求","服务要求","商务要求","其他要求"],
|
||||||
"关键时间/内容": [
|
"关键时间/内容": [
|
||||||
"投标文件递交截止日期",
|
"投标文件递交截止日期",
|
||||||
"开标时间",
|
"开标时间",
|
||||||
@ -81,6 +81,24 @@ def aggregate_basic_info_goods(baseinfo_list):
|
|||||||
def dynamic_key_handling(key_groups, detected_keys):
|
def dynamic_key_handling(key_groups, detected_keys):
|
||||||
# 检查和调整键组配置
|
# 检查和调整键组配置
|
||||||
for key in 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:
|
if "保证金" in key:
|
||||||
group = key_groups["保证金相关"]
|
group = key_groups["保证金相关"]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# -*- encoding:utf-8 -*-
|
# -*- encoding:utf-8 -*-
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
from flask_app.general.多线程提问 import multi_threading
|
from flask_app.general.多线程提问 import multi_threading
|
||||||
from flask_app.general.通义千问long import qianwen_long, upload_file
|
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=''):
|
def generate_key_paths(data, parent_key=''):
|
||||||
"""
|
"""
|
||||||
生成嵌套字典中的键路径,并提取最内层的键名。
|
生成嵌套字典中的键路径,并提取最内层的键名。
|
||||||
|
同时,提取特定模式的键(如 '交换机-1', '交换机-2')的父路径。
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
data (dict): 输入的字典数据
|
data (dict): 输入的字典数据
|
||||||
parent_key (str): 上级键路径,用于递归调用
|
parent_key (str): 上级键路径,用于递归调用
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
tuple: 包含键路径列表和最内层键名列表的元组
|
tuple: 包含键路径列表、最内层键名列表、分组路径列表以及 no_keys_added 的元组
|
||||||
(key_paths, good_list)
|
(key_paths, good_list, grouped_paths, no_keys_added)
|
||||||
"""
|
"""
|
||||||
key_paths = []
|
key_paths = []
|
||||||
good_list = []
|
good_list = []
|
||||||
|
grouped_paths = set() # 使用集合避免重复路径
|
||||||
no_keys_added = True # 默认假设没有添加任何键
|
no_keys_added = True # 默认假设没有添加任何键
|
||||||
|
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
@ -29,43 +32,98 @@ def generate_key_paths(data, parent_key=''):
|
|||||||
|
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
if value:
|
if value:
|
||||||
# 递归调用,并获取子路径和子 good_list
|
# 递归调用,并获取子路径、子 good_list、子分组路径以及子 no_keys_added
|
||||||
sub_key_paths, sub_good_list, sub_no_keys_added = generate_key_paths(value, current_key)
|
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)
|
key_paths.extend(sub_key_paths)
|
||||||
good_list.extend(sub_good_list)
|
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
|
no_keys_added = no_keys_added and sub_no_keys_added
|
||||||
else:
|
else:
|
||||||
# 空字典视为叶子节点
|
# 空字典视为叶子节点
|
||||||
key_paths.append(current_key.replace(" ",""))
|
clean_key = key.replace(" ", "")
|
||||||
good_list.append(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
|
no_keys_added = False
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
if value:
|
if value:
|
||||||
# 非空列表视为叶子节点
|
# 非空列表视为叶子节点
|
||||||
key_paths.append(current_key.replace(" ",""))
|
key_paths.append(current_key.replace(" ", ""))
|
||||||
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
||||||
|
# 更新 no_keys_added
|
||||||
no_keys_added = False
|
no_keys_added = False
|
||||||
else:
|
else:
|
||||||
# 空列表也视为叶子节点(根据需求可以调整)
|
# 空列表也视为叶子节点(根据需求可以调整)
|
||||||
key_paths.append(current_key.replace(" ",""))
|
key_paths.append(current_key.replace(" ", ""))
|
||||||
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
||||||
|
# 更新 no_keys_added
|
||||||
no_keys_added = False
|
no_keys_added = False
|
||||||
elif value in {"未知", "", "/"}:
|
elif value in {"未知", "", "/"}:
|
||||||
# 特定值视为叶子节点
|
# 特定值视为叶子节点
|
||||||
key_paths.append(current_key.replace(" ",""))
|
key_paths.append(current_key.replace(" ", ""))
|
||||||
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
||||||
|
# 更新 no_keys_added
|
||||||
no_keys_added = False
|
no_keys_added = False
|
||||||
else:
|
else:
|
||||||
# 其他情况不视为叶子节点
|
# 其他情况视为叶子节点
|
||||||
key_paths.append(current_key.replace(" ",""))
|
key_paths.append(current_key.replace(" ", ""))
|
||||||
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
good_list.append(key.replace(" ", "")) # 去掉空格后添加
|
||||||
|
# 更新 no_keys_added
|
||||||
no_keys_added = False
|
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 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):
|
def recursive_update(data, key, value):
|
||||||
# 处理点分隔的键,递归定位并更新嵌套字典
|
"""
|
||||||
|
递归更新嵌套字典。
|
||||||
|
"""
|
||||||
keys = key.split('.')
|
keys = key.split('.')
|
||||||
for k in keys[:-1]:
|
for k in keys[:-1]:
|
||||||
data = data.setdefault(k, {})
|
data = data.setdefault(k, {})
|
||||||
@ -73,8 +131,21 @@ def combine_and_update_results(original_data, updates):
|
|||||||
data[keys[-1]] = {**data.get(keys[-1], {}), **value}
|
data[keys[-1]] = {**data.get(keys[-1], {}), **value}
|
||||||
else:
|
else:
|
||||||
data[keys[-1]] = value
|
data[keys[-1]] = value
|
||||||
|
|
||||||
|
# 1. 规范化原始数据字典的键
|
||||||
|
original_data = normalize_original_data(original_data)
|
||||||
|
|
||||||
|
# 2. 规范化更新字典的键
|
||||||
|
normalized_updates = {}
|
||||||
for key, value in updates.items():
|
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)
|
recursive_update(original_data, key, value)
|
||||||
|
|
||||||
return original_data
|
return original_data
|
||||||
def postprocess(data):
|
def postprocess(data):
|
||||||
"""递归地转换字典中的值为列表,如果所有键对应的值都是'/', '{}' 或 '未知'"""
|
"""递归地转换字典中的值为列表,如果所有键对应的值都是'/', '{}' 或 '未知'"""
|
||||||
@ -92,37 +163,36 @@ def postprocess(data):
|
|||||||
def get_technical_requirements(file_id,invalid_path):
|
def get_technical_requirements(file_id,invalid_path):
|
||||||
first_query="该文档中是否说明了采购需求,即需要采购哪些货物?如果有,请回答'是',否则,回答'否'"
|
first_query="该文档中是否说明了采购需求,即需要采购哪些货物?如果有,请回答'是',否则,回答'否'"
|
||||||
judge_res=qianwen_long(file_id,first_query)
|
judge_res=qianwen_long(file_id,first_query)
|
||||||
# print(judge_res)
|
|
||||||
if '否' in judge_res:
|
if '否' in judge_res:
|
||||||
file_id=upload_file(invalid_path)
|
file_id=upload_file(invalid_path)
|
||||||
|
print("调用invalid_path")
|
||||||
user_query1 = """
|
user_query1 = """
|
||||||
请你首先定位该采购文件中的采购清单或采购需求部分,请告诉我需要采购的货物,如果有采购清单,请直接根据清单上的货物(或系统)名称给出结果,若没有采购清单,你要从表格中或文中摘取需要采购的系统(或货物),
|
请你首先定位该采购文件中的采购清单或采购需求部分,请告诉我需要采购的货物,如果有采购清单,请直接根据清单上的货物(或系统)名称给出结果,注意不要返回'说明'或'规格'或'技术参数'列中的内容;若没有采购清单,你要从表格中或文中摘取需要采购的系统(或货物),采购需求中可能包含层次关系,例如采购的某大系统中可能包含几种货物,那么你需要用嵌套键值对表示这种关系,且不要遗漏该系统中包含的货物,你的输出请以json格式返回,最外层键名为'采购需求',嵌套键名为对应的系统名称或货物名称,需与原文保持一致,无需给出采购数量和单位。以下为需要考虑的特殊情况:如果采购清单中同一层级(或同一系统)下存在同名货物且它们的采购要求有所不同,请你以'货物名-编号'区分多种型号,编号为从 1 开始的自然数,依次递增,例如若采购清单中有两种型号的'交换机',那么你应返回两个键名,'交换机-1'和'交换机-2';如有未知内容,在对应键值处填'未知'。以下为考虑了特殊情况的示例输出:
|
||||||
采购需求中可能包含层次关系,例如采购的某大系统中可能包含几种货物,那么你需要用嵌套键值对表示这种关系,且不要遗漏该系统中包含的货物,你的输出请以json格式返回,最外层键名为'采购需求',嵌套键名为对应的系统名称或货物名称,需与原文保持一致,无需给出采购数量和单位。以下为需要考虑的特殊情况:如果同一层级下存在同名货物且它们的技术参数要求有所不同,请在货物名后添加后缀'-n',n为自然数,依次递增;如有未知内容,在对应键值处填'未知'。以下为示例输出:
|
|
||||||
{
|
{
|
||||||
"采购需求": {
|
"采购需求": {
|
||||||
|
"交换机-1":{},
|
||||||
|
"交换机-2":{},
|
||||||
"门禁管理系统": {},
|
"门禁管理系统": {},
|
||||||
"交通监控视频子系统": {
|
"交通监控视频子系统": {
|
||||||
"高清视频抓拍像机":{},
|
"高清视频抓拍像机":{},
|
||||||
"补光灯":{}
|
"补光灯":{}
|
||||||
},
|
},
|
||||||
"LED全彩显示屏": {},
|
"LED全彩显示屏": {}
|
||||||
"交换机-1":{},
|
|
||||||
"交换机-2":{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
res = qianwen_long(file_id, user_query1)
|
res = qianwen_long(file_id, user_query1)
|
||||||
print(res)
|
print(res)
|
||||||
cleaned_res = clean_json_string(res) #转字典
|
cleaned_res = clean_json_string(res) #转字典
|
||||||
keys_list,good_list,no_keys_added= generate_key_paths(cleaned_res['采购需求']) # 提取需要采购的货物清单
|
keys_list,good_list,grouped_paths,no_keys_added= generate_key_paths(cleaned_res['采购需求']) # 提取需要采购的货物清单 key_list:交通监控视频子系统.高清视频抓拍像机 ...
|
||||||
if '采购需求' in cleaned_res:
|
# if '采购需求' in cleaned_res:
|
||||||
cleaned_res['技术要求'] = cleaned_res.pop('采购需求')
|
# cleaned_res['技术要求'] = cleaned_res.pop('采购需求')
|
||||||
if no_keys_added:
|
if no_keys_added:
|
||||||
final_res = postprocess(cleaned_res)
|
final_res = postprocess(cleaned_res)
|
||||||
else:
|
else:
|
||||||
# user_query_template = "请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,外层键名为\"{}\", 键值对中的键是你对该要求的总结,而值需要完全与原文保持一致,不可擅自总结删减。"
|
# user_query_template = "请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,外层键名为\"{}\", 键值对中的键是你对该要求的总结,而值需要完全与原文保持一致,不可擅自总结删减。"
|
||||||
user_query_template = """
|
user_query_template = """
|
||||||
请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,键名为\"{}\", 键值为一个列表,列表中包含若干描述\"{}\"的技术参数(或采购要求)的字符串,如果该货物没有相关要求,键值为空列表。示例输出格式如下:
|
请你根据该货物标中采购要求部分的内容,请你给出\"{}\"的技术参数(或采购要求),请以json格式返回结果,键名为\"{}\", 键值为一个列表,列表中包含若干描述\"{}\"的技术参数(或采购要求)的字符串。以下为需要考虑的特殊情况:如果该货物没有相关采购要求或技术参数要求,键值为空列表。示例输出格式如下:
|
||||||
{{
|
{{
|
||||||
"摄像机控制键盘": [
|
"摄像机控制键盘": [
|
||||||
"支持串行 RS232/RS422 和 IP 混合控制,允许在一个控制器上使用 RS232/RS422/IP 控制单个系统中的摄像机;",
|
"支持串行 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 = []
|
queries = []
|
||||||
for key in keys_list:
|
for key in keys_list:
|
||||||
# 将键中的 '.' 替换为 '下的'
|
# 将键中的 '.' 替换为 '下的'
|
||||||
modified_key = key.replace('.', '下的')
|
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)
|
queries.append(new_query)
|
||||||
results = multi_threading(queries, "", file_id, 2)
|
results = multi_threading(queries, "", file_id, 2)
|
||||||
technical_requirements = []
|
technical_requirements = []
|
||||||
@ -146,13 +237,15 @@ def get_technical_requirements(file_id,invalid_path):
|
|||||||
for question, response in results:
|
for question, response in results:
|
||||||
technical_requirements.append(response)
|
technical_requirements.append(response)
|
||||||
technical_requirements_combined_res = combine_json_results(technical_requirements)
|
technical_requirements_combined_res = combine_json_results(technical_requirements)
|
||||||
|
|
||||||
"""根据所有键是否已添加处理技术要求"""
|
"""根据所有键是否已添加处理技术要求"""
|
||||||
# 更新原始采购需求字典
|
# 更新原始采购需求字典
|
||||||
combine_and_update_results(cleaned_res['技术要求'], technical_requirements_combined_res)
|
update_res=combine_and_update_results(cleaned_res['采购需求'], technical_requirements_combined_res)
|
||||||
final_res = postprocess(cleaned_res)
|
# final_res = postprocess(cleaned_res)
|
||||||
final_res['技术要求']["货物列表"] = good_list #添加需要采购的货物
|
update_res["货物列表"] = good_list
|
||||||
|
|
||||||
# 输出最终的 JSON 字符串
|
# 输出最终的 JSON 字符串
|
||||||
return final_res
|
return {"采购需求": update_res}
|
||||||
|
|
||||||
def test_all_files_in_folder(input_folder, output_folder):
|
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}")
|
print(f"处理文件 {file_path} 时出错: {e}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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"
|
# # 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"
|
# 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"
|
# 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"
|
# output_folder="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\tmp"
|
||||||
# file_id = upload_file(truncate_file)
|
# file_id = upload_file(truncate_file)
|
||||||
invalid_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles\\包头市公安支队机动车查验监管系统招标文201907.pdf"
|
invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile.pdf"
|
||||||
file_id="file-fe-FcOjv4FiOGjHRG1pKaFrIBeG"
|
file_id=upload_file(truncate_file)
|
||||||
res=get_technical_requirements(file_id,invalid_path)
|
res=get_technical_requirements(file_id,invalid_path)
|
||||||
json_string = json.dumps(res, ensure_ascii=False, indent=4)
|
json_string = json.dumps(res, ensure_ascii=False, indent=4)
|
||||||
print(json_string)
|
print(json_string)
|
||||||
|
@ -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 字典
|
# 定义默认的 procurement_reqs 字典
|
||||||
DEFAULT_PROCUREMENT_REQS = {
|
DEFAULT_PROCUREMENT_REQS = {
|
||||||
|
"采购需求": "",
|
||||||
"技术要求": "",
|
"技术要求": "",
|
||||||
"商务要求": "",
|
"商务要求": "",
|
||||||
"服务要求": "",
|
"服务要求": "",
|
||||||
"其他要求": ""
|
"其他要求": ""
|
||||||
}
|
}
|
||||||
# 如果 truncate_file 是空字符串,直接返回包含空字符串的字典
|
|
||||||
|
# 如果 procurement_docpath 是空字符串,直接返回包含空字符串的字典
|
||||||
if not procurement_docpath:
|
if not procurement_docpath:
|
||||||
return DEFAULT_PROCUREMENT_REQS.copy()
|
return DEFAULT_PROCUREMENT_REQS.copy()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 上传文件并获取 file_id
|
# 上传文件并获取 file_id
|
||||||
file_id = upload_file(procurement_docpath)
|
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
|
# 使用 ThreadPoolExecutor 并行处理 get_technical_requirements 和 get_business_requirements
|
||||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||||
# 提交任务给线程池
|
# 提交任务给线程池
|
||||||
future_technical = executor.submit(get_technical_requirements, file_id,invalid_path)
|
future_technical = executor.submit(get_technical_requirements, file_id, invalid_path)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5) # 保持原有的延时
|
||||||
future_business = executor.submit(get_business_requirements, procurement_path, file_id)
|
future_business = executor.submit(get_business_requirements, procurement_path, file_id)
|
||||||
|
|
||||||
# 获取并行任务的结果
|
# 获取并行任务的结果
|
||||||
technical_requirements = future_technical.result()
|
technical_requirements = future_technical.result()
|
||||||
business_requirements = future_business.result()
|
business_requirements = future_business.result()
|
||||||
|
|
||||||
# 构建最终的嵌套结构,确保四个键平级
|
# 构建最终的采购需求字典
|
||||||
procurement_reqs = {
|
procurement_reqs = {
|
||||||
"技术要求": technical_requirements.get("技术要求", {}),
|
"采购需求": technical_requirements.get("采购需求", "")
|
||||||
"商务要求": business_requirements.get("商务要求", {}),
|
|
||||||
"服务要求": business_requirements.get("服务要求", {}),
|
|
||||||
"其他要求": business_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
|
return procurement_reqs
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -49,10 +57,13 @@ def fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path):
|
|||||||
return DEFAULT_PROCUREMENT_REQS.copy()
|
return DEFAULT_PROCUREMENT_REQS.copy()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
start_time=time.time()
|
||||||
output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\货物标output"
|
output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\货物标output"
|
||||||
# file_path="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\2-招标文件(2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目)_procurement.pdf"
|
# 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_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_procurement.pdf"
|
||||||
procurement_docpath="C:\\Users\\Administrator\\Desktop\\fsdownload\\a6168046-ad8c-43cb-8913-071ce7b248a1\\ztbfile_procurement.docx"
|
procurement_docpath="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile_procurement.docx"
|
||||||
invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a6168046-ad8c-43cb-8913-071ce7b248a1\\ztbfile.pdf"
|
invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a110ed59-00e8-47ec-873a-bd4579a6e628\\ztbfile.pdf"
|
||||||
res=fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path)
|
res=fetch_procurement_reqs(procurement_path,procurement_docpath,invalid_path)
|
||||||
print(json.dumps(res, ensure_ascii=False, indent=4))
|
print(json.dumps(res, ensure_ascii=False, indent=4))
|
||||||
|
end_time=time.time()
|
||||||
|
print("耗时:"+str(end_time-start_time))
|
||||||
|
@ -244,8 +244,8 @@ def goods_bid_main(output_folder, file_path, file_type, unique_id):
|
|||||||
|
|
||||||
#广水市 2022 年义务教育学校多媒体补充采购项目 资格审查有问题
|
#广水市 2022 年义务教育学校多媒体补充采购项目 资格审查有问题
|
||||||
|
|
||||||
#TODO:技术要求提取更全面一点 fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628 技术要求!
|
|
||||||
#TODO:工程标的资格审查也增加第一章的内容。
|
#TODO:工程标的资格审查也增加第一章的内容。
|
||||||
|
#TODO:工程标 资格审查
|
||||||
#good_list 金额 截取上下文
|
#good_list 金额 截取上下文
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 配置日志器
|
# 配置日志器
|
||||||
|
Loading…
x
Reference in New Issue
Block a user