11.7 资格审查货物标修改

This commit is contained in:
zy123 2024-11-07 15:46:24 +08:00
parent ef064b9fc7
commit 6e6400ce34
6 changed files with 363 additions and 120 deletions

View File

@ -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\\54d7aa40-8b36-4803-b6f7-278356ff1381\\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\\货物标\\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"

View File

@ -24,27 +24,6 @@ def contains_number_or_index(key, value):
return False return False
# 如果值是数字或包含数字,且不包含中文字符,或者键包含 "序号",返回 True # 如果值是数字或包含数字,且不包含中文字符,或者键包含 "序号",返回 True
return is_number or contains_index or contains_digit return is_number or contains_index or contains_digit
def preprocess_dict(data):
if isinstance(data, dict):
if len(data) > 1:
# 检查是否所有值都是 "" 或 "/"
if all(v == "" or v == "/" or (isinstance(v, list) and not v) for v in data.values()):
return list(data.keys())
else:
processed = {}
for k, v in data.items():
if not contains_number_or_index(k, v):
processed_v = preprocess_dict(v)
if processed_v != "": # 只添加非空值
processed[k] = processed_v
return processed
else:
return {k: preprocess_dict(v) for k, v in data.items()}
elif isinstance(data, list):
return [preprocess_dict(item) for item in data]
else:
return data
def process_dict(data): def process_dict(data):
""" """
递归处理字典将符合条件的键值对进行转换 递归处理字典将符合条件的键值对进行转换
@ -81,7 +60,11 @@ def process_dict(data):
elif re.match(r'^\d+\.\d+$', key): # 单层小数点 elif re.match(r'^\d+\.\d+$', key): # 单层小数点
return (float(key),) return (float(key),)
else: # 多层序号,按字符串处理 else: # 多层序号,按字符串处理
return tuple(map(int, key.split('.'))) try:
return tuple(int(part) for part in key.split('.') if part.isdigit())
except ValueError:
# 处理无法转换的部分,例如返回一个默认值或记录错误
return ()
# 按键排序,确保顺序一致 # 按键排序,确保顺序一致
numeric_keys_sorted = sorted(numeric_keys, key=sort_key) numeric_keys_sorted = sorted(numeric_keys, key=sort_key)
result['items'] = [process_dict(item[1]) for item in numeric_keys_sorted] result['items'] = [process_dict(item[1]) for item in numeric_keys_sorted]
@ -124,21 +107,133 @@ def process_dict(data):
return list(result.keys()) return list(result.keys())
return result return result
def preprocess_dict(data):
if isinstance(data, dict):
if len(data) > 1:
# 检查是否所有值都是 "" 或 "/"
if all(v == "" or v == "/" or (isinstance(v, list) and not v) for v in data.values()):
return list(data.keys())
else:
processed = {}
for k, v in data.items():
if not contains_number_or_index(k, v):
processed_v = preprocess_dict(v)
if processed_v != "": # 只添加非空值
processed[k] = processed_v
return processed
else:
return {k: preprocess_dict(v) for k, v in data.items()}
elif isinstance(data, list):
return [preprocess_dict(item) for item in data]
else:
return data
data={ data={
"符合性审查": {
"1": {
"投标报价": {
"审查内容": "1投标报价没有超过项目采购包预算金额或最高限价\n2投标报价不存在缺项、漏项。"
}
},
"2": {
"投标文件签署": {
"审查内容": "按照招标文件要求签署、盖章。"
}
},
"3": {
"强制采购节能产品": {
"审查内容": "依据财库[2019]9号文的规定如属于强制节能产品须提供国家确定的认证机构出具的、处于有效期内的节能产品认证证书或中国政府采购网节能产品查询截图未提供的视为无效响应认证证书或查询截图的产品型号与所投产品不一致的视为未提供"
}
},
"4": {
"进口产品": {
"审查内容": "招标文件不接受进口产品投标时,投标人所投产品不是通过中国海关报关验放进入中国境内且产自关境外的。"
}
},
"5": {
"实质性要求": {
"审查内容": "1满足招标文件第三章“项目采购需求”中要求的实质性条款\n2投标有效期满足招标文件要求\n3没有采购人不能接受的附加条件。"
}
},
"6": {
"围标串标情形": {
"审查内容": "投标人不存在下列任一情形:\n1不同投标人的投标文件由同一单位或者个人编制\n2不同投标人委托同一单位或者个人办理投标事宜\n3不同投标人的投标文件载明的项目管理成员或者联系人员为同一人\n4不同投标人的投标文件异常一致或者投标报价呈规律性差异\n5不同投标人的投标文件相互混装\n6不同投标人使用同一电脑机器特征值一致如 MAC地址等或使用同一电子密钥编制或上传电子投标文件。"
}
},
"7": {
"其他无效情形": {
"审查内容": "不存在法律、法规和招标文件规定的其他无效投标情形。"
}
}
},
"资格性审查": { "资格性审查": {
"1": "供应商应具备《政府采购法》第二十二条规定的条件,提供相关材料。", "1": {
"2": "法人或者其他组织的营业执照等证明文件,自然人的身份证明;", "资格要求": "具有独立承担民事责任的能力",
"3": "财务状况报告,依法缴纳税收和社会保障资金的声明函;", "审查内容": "法人或者其他组织的营业执照等证明文件自然人的身份证明。1企业应提供“营业执照” 2事业单位应提供“事业单位法人证书” 3非企业专业服务机构应提供执业许可证等证明文件 4个体工商户应提供“个体工商户营业执照” 5自然人应提供自然人身份证明。"
"4": "具备履行合同所必需的设备和专业技术能力的证明材料;", },
"5": "未被列入信用记录名单声明函;", "2": {
"6": "参加政府采购活动前 3年内在经营活动中没有重大违法记录的书面声明", "资格要求": "具有良好的商业信誉和健全的财务会计制度",
"7": "具备法律、行政法规规定的其他条件的证明材料;", "审查内容": "由投标人对以下内容提供书面承诺或声明或提供相应证明材料。1投标人是法人的应具有上一年度__ 年度或_____年度经审计的财务报告或其基本开户银行出具的资信证明。其他组织和自然人没有经审计的财务报告应具有银行出具的资信证明。2有专业担保机构对投标人进行资信审查后出具投标担保函的可以不用具备经审计的财务报告和银行资信证明文件。"
"8": "招标文件第一章“投标人资格要求”中有特殊要求的,投标人应提供其符合特殊要求的证明材料或者情况说明;", },
"9.1.1": "未被列入信用记录名单声明函;", "3": {
"10.1.1": "参加政府采购活动前 3年内在经营活动中没有重大违法记录的书面声明", "资格要求": "具有履行合同所必需的设备和专业技术能力",
"11": "具备法律、行政法规规定的其他条件的证明材料;", "审查内容": "由投标人提供书面承诺或声明,或提供相应证明材料。"
"12": "招标文件第一章“投标人资格要求”中有特殊要求的,投标人应提供其符合特殊要求的证明材料或者情况说明;" },
"4": {
"资格要求": "有依法缴纳税收和社会保障资金的良好记录",
"审查内容": "由投标人对以下内容提供书面承诺或声明或提供相应证明材料。1投标人依法缴纳税收本项目公告发布时间前 12个月内至少有 1个月缴纳税收的凭据完税证、缴款书、印花税票、银行代扣代缴转账凭证等均可 2投标人依法缴纳社会保障资金本项目公告发布时间前 12个月内至少有 1个月缴纳社会保险的凭据专用收据或社会保险交纳清单 3投标人为其他组织或自然人的也应满足以上要求 4递交投标文件截止时间的当月成立但因税务机关原因导致其尚未依法缴纳税收的投标人提供将依法缴纳税收承诺书原件格式自拟该承诺书视同税收缴纳凭据 5递交投标文件截止时间的当月成立但因社会保障资金管理机关原因导致其尚未依法缴纳社会保障资金的投标人提供将依法缴纳社会保障资金承诺书原件格式自拟该承诺书视同社会保险凭据 6依法免税或不需要缴纳社会保障资金的投标人具有相应文件证明其依法免税或不需要交纳社会保障资金。"
},
"5": {
"资格要求": "参加政府采购活动前三年内,在经营活动中没有重大违法记录",
"审查内容": "由投标人提供书面承诺或声明,或提供相应证明材料。"
},
"6": {
"资格要求": "法律、行政法规规定的其他条件",
"审查内容": "由投标人提供书面承诺或声明,或提供相应证明材料。"
},
"7": {
"资格要求": "单位负责人为同一人或者存在直接控股、管理关系的不同投标人,不得参加本项目同一合同项下的政府采购活动",
"审查内容": "由投标人在《投标函》中声明"
},
"8": {
"资格要求": "为本采购项目提供整体设计、规范编制或者项目管理、监理、检测等服务的,不得再参加本项目的其他招标采购活动。",
"审查内容": "由投标人在《投标函》中声明"
},
"9": {
"资格要求": "未被列入失信被执行人、“重大税收违法失信主体”,未被列入政府采购严重违法失信行为记录名单。",
"审查内容": "以采购人和采购代理机构在投标截止日在 “信用中国”网站www.creditchina.gov.cn 及中国政府采购网(www.ccgp.gov.cn)查询的投标人参加政府采购活动前三年内的结果为准 (采购人和采购代理机构对信用信息查询记录和证据截图或下载存档)。"
},
"10": {
"资格要求": "落实政府采购政策需满足的资格要求",
"审查内容": "☐支持中小企业发展资格要求:提供《中小企业声明函》,本项目投标人属于监狱企业或者残疾人福利性单位的,同时提供监狱企业证明材料或者《残疾人福利性单位声明函》; ☑其他政府采购政策需满足的资格要求:/"
},
"11": {
"资格要求": "本项目的特定资格要求",
"审查内容": "详见第一章“投标邀请”投标人特定资格要求。"
} }
},
"申请人资格要求": [
"1.满足《中华人民共和国政府采购法》第二十二条规定,即:",
"1具有独立承担民事责任的能力",
"2具有良好的商业信誉和健全的财务会计制度",
"3具有履行合同所必需的设备和专业技术能力",
"4有依法缴纳税收和社会保障资金的良好记录",
"5参加政府采购活动前三年内在经营活动中没有重大违法记录",
"2.未被列入失信被执行人、“重大税收违法失信主体”,未被列入政府采购严重违法失信行为记录名单。",
"3.落实政府采购政策需满足的资格要求:无",
"4.投标人特定资格要求:",
"1投标人须在中国工商行政管理机关注册登记并取得营业执照具有独立承担民事责任的能力。",
"2投标人须提供近三年完整的财务审计报告成立未满三年的提供自成立之日起至今的财务审计报告成立未满一年的提供银行资信证明以及近 6个月由税务部门出具的纳税证明材料零申报提供零申报证明如有减、免、缓交的须提供相应证明材料和社保缴纳证明",
"3投标人须出具在参加本项目投标活动前三年内在经营活动中无重大违法记录且遵守有关的国家法律、法令、条例和政府采购有关制度一旦参加投标则应承担相关法律责任的承诺函",
"4投标截止时间前有相关任何一条以下不良记录及重大违法记录政府采购法第二十二条第一款第五项所称重大违法记录是指供应商因违法经营受到刑事处罚或责令停产停业、吊销许可证或执照、较大数额罚款等行政处罚。的供应商将被拒绝",
"①在信用中国网站http://www.creditchina.gov.cn )查询“失信被执行人”和“重大税收违法失信主体”和“政府采购严重违法失信行为记录名单”的加盖公司公章的证明材料;",
"②中国政府采购网http://www.ccgp.gov.cn/cr/list查询“政府采购严重违法失信行为信息记录”的加盖公司公章的截图证明材料",
"③国家企业信用信息公示系统 http://www.gsxt.gov.cn/corp-query-homepage.html )查询“行政处罚信息”、“列入经营异常名录信息”、“列入严重违法失信企业名单(黑名单)信息”的加盖公司公章的证明材料;",
"5提供“中国裁判文书网”近三年内参与投标的供应商企业、法定代表人在经营活动中没有行贿犯罪记录查询函公告发布起查询网上自查加盖公章"
]
} }
res1=process_dict(preprocess_dict(data)) # print(json.dumps(data,ensure_ascii=False,indent=4))
print(json.dumps(res1,ensure_ascii=False,indent=4)) res1=preprocess_dict(data)
# print(json.dumps(res1,ensure_ascii=False,indent=4))
res2=process_dict(res1)
print(json.dumps(res2,ensure_ascii=False,indent=4))

View File

@ -109,7 +109,7 @@ def extract_from_notice(merged_baseinfo_path,clause_path, type):
# print(json.dumps(extracted_data,ensure_ascii=False,indent=4)) # print(json.dumps(extracted_data,ensure_ascii=False,indent=4))
extracted_data_concatenated = {section: concatenate_keys_values(content) #启用结构化就注释这三行 extracted_data_concatenated = {section: concatenate_keys_values(content) #启用结构化就注释这三行
for section, content in extracted_data.items()} for section, content in extracted_data.items()}
extracted_data_concatenated[data]=1
return extracted_data_concatenated return extracted_data_concatenated
# transformed_data = process_with_outer_key(extracted_data) #取消注释这三行 # transformed_data = process_with_outer_key(extracted_data) #取消注释这三行
# final_result = process_nested_data(transformed_data) # final_result = process_nested_data(transformed_data)
@ -121,8 +121,8 @@ def extract_from_notice(merged_baseinfo_path,clause_path, type):
return DEFAULT_RESULT return DEFAULT_RESULT
if __name__ == "__main__": if __name__ == "__main__":
clause_path = r'C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\\clause1.json' clause_path = r'C:\Users\Administrator\Desktop\fsdownload\6b251074-bd29-4bd5-a776-3a11c20e6b11\\clause1.json'
merged_baseinfo_path=r"C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\ztbfile_merged_baseinfo.pdf" merged_baseinfo_path=r"C:\Users\Administrator\Desktop\fsdownload\6b251074-bd29-4bd5-a776-3a11c20e6b11\ztbfile_merged_baseinfo.pdf"
# file_path = 'D:\\flask_project\\flask_app\\static\\output\\fee18877-0c60-4c28-911f-9a5f7d1325a7\\clause1.json' # file_path = 'D:\\flask_project\\flask_app\\static\\output\\fee18877-0c60-4c28-911f-9a5f7d1325a7\\clause1.json'
try: try:
res = extract_from_notice(merged_baseinfo_path,clause_path, 1) # 可以改变此处的 type 参数测试不同的场景 res = extract_from_notice(merged_baseinfo_path,clause_path, 1) # 可以改变此处的 type 参数测试不同的场景

View File

@ -139,7 +139,7 @@ def parse_text_by_heading(text):
pattern_numbered = re.compile(r'^\s*([一二三四五六七八九十]{1,2})\s*、\s*') pattern_numbered = re.compile(r'^\s*([一二三四五六七八九十]{1,2})\s*、\s*')
pattern_parentheses = re.compile(r'^\s*[(]\s*([一二三四五六七八九十]{1,2})\s*[)]\s*') pattern_parentheses = re.compile(r'^\s*[(]\s*([一二三四五六七八九十]{1,2})\s*[)]\s*')
initial_heading_pattern = None initial_heading_pattern = None
special_section_keywords = ['文件的组成', '文件的构成'] # 定义特殊章节关键词 special_section_keywords = ['文件的组成', '文件的构成','文件包括:','文件包括:'] # 定义特殊章节关键词
in_special_section = False # 标志是否在特殊章节中 in_special_section = False # 标志是否在特殊章节中
lines = text.split('\n') lines = text.split('\n')
@ -148,6 +148,19 @@ def parse_text_by_heading(text):
line_no_spaces = line.replace(' ', '') line_no_spaces = line.replace(' ', '')
return re.match(r'^\d{4}\s*年', line_no_spaces) is not None return re.match(r'^\d{4}\s*年', line_no_spaces) is not None
def is_heading(line):
# 检查是否匹配任何标题模式
patterns = [
r'^(?<![a-zA-Z(])(\d+(?:\.\d+)+)\s*(.*)', # 匹配 '12.1 内容'
r'^(\d+\.)\s*(.+)$', # 匹配 '12. 内容'
r'^[.](\d+(?:[.]\d+)*)\s*(.+)$', # 匹配 '.12.1 内容'
r'^(\d+)([^.\d].*)' # 匹配 '27 内容'
]
for pattern in patterns:
if re.match(pattern, line):
return True
return False
for i, line in enumerate(lines): for i, line in enumerate(lines):
line_stripped = line.strip().replace('', '.') line_stripped = line.strip().replace('', '.')
@ -156,19 +169,16 @@ def parse_text_by_heading(text):
current_content.append(line_stripped) current_content.append(line_stripped)
continue continue
# **首先检查是否进入特殊章节**
if any(keyword in line_stripped for keyword in special_section_keywords):
in_special_section = True
# 匹配带数字的标题,例如 '12.1 内容' # 匹配带数字的标题,例如 '12.1 内容'
match = re.match(r'^(?<![a-zA-Z(])(\d+(?:\.\d+)+)\s*(.*)', line_stripped) match = re.match(r'^(?<![a-zA-Z(])(\d+(?:\.\d+)+)\s*(.*)', line_stripped)
if not match: if not match:
match = re.match(r'^(\d+\.)\s*(.+)$', line_stripped) match = re.match(r'^(\d+\.)\s*(.+)$', line_stripped)
# 检查是否退出特殊章节 # 检查是否进入或退出特殊章节
if in_special_section: if is_heading(line_stripped):
# 如果匹配到了主要标题,且不包含特殊关键词,则退出特殊章节 if any(keyword in line_stripped for keyword in special_section_keywords):
if match and not any(keyword in line_stripped for keyword in special_section_keywords): in_special_section = True
elif in_special_section:
in_special_section = False in_special_section = False
# 以下是原有的匹配逻辑 # 以下是原有的匹配逻辑
@ -179,7 +189,8 @@ def parse_text_by_heading(text):
dot_text_match = re.match(r'^[.]\s*(\D.+)$', line_stripped) dot_text_match = re.match(r'^[.]\s*(\D.+)$', line_stripped)
# 匹配不带点号的纯数字开头的情况,例如 '27xxxxx' # 匹配不带点号的纯数字开头的情况,例如 '27xxxxx'
pure_number_match = re.match(r'^(\d+)([^.\d].*)', line_stripped) # pure_number_match = re.match(r'^(\d+)([^.\d].*)', line_stripped)
pure_number_match = re.match(r'^(\d+)([^.\d)(].*)', line_stripped) #不允许出现右括号
if match: if match:
new_key, line_content = match.groups() new_key, line_content = match.groups()
@ -483,12 +494,12 @@ def process_folder(input_folder, output_folder):
#TODO:'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\广水农商行门禁控制主机及基础验证设备采购项目——磋商文件定稿三次_tobidders_notice_part2.pdf' PYPDF2库读取有遗漏 #TODO:'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\广水农商行门禁控制主机及基础验证设备采购项目——磋商文件定稿三次_tobidders_notice_part2.pdf' PYPDF2库读取有遗漏
#TODO: 投标人须知正文这块,序号可能是乱序的,或许可以删除判断序号大小的逻辑,只要出现在开头的序号就作为新的键 eg:2-招标文件。目前将这种情况当特殊处理 #TODO: 投标人须知正文这块,序号可能是乱序的,或许可以删除判断序号大小的逻辑,只要出现在开头的序号就作为新的键 eg:2-招标文件。目前将这种情况当特殊处理
#TODO:11.6 目前 '文件的组成' 是匹配任意行,可以考虑只匹配'11.文件的组成' 前面有序号的行 a110ed59-00e8-47ec-873a-bd4579a6e628\ztbfile_tobidders_notice_part2.pdf还有问题
if __name__ == "__main__": if __name__ == "__main__":
# file_path = 'D:\\flask_project\\flask_app\\static\\output\\cfd4959d-5ea9-4112-8b50-9e543803f029\\ztbfile_tobidders_notice.pdf' # file_path = 'D:\\flask_project\\flask_app\\static\\output\\cfd4959d-5ea9-4112-8b50-9e543803f029\\ztbfile_tobidders_notice.pdf'
file_path=r'C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\ztbfile_tobidders_notice_part2.pdf' file_path=r'C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\ztbfile_tobidders_notice_part2.pdf'
# file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\2-招标文件2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目_tobidders_notice_part2.pdf' # file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\2-招标文件2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目_tobidders_notice_part2.pdf'
output_folder = r'C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\\tmp' output_folder = r'C:\Users\Administrator\Desktop\fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628\tmp'
try: try:
output_path = convert_clause_to_json(file_path,output_folder,1) output_path = convert_clause_to_json(file_path,output_folder,1)
print(f"Final JSON result saved to: {output_path}") print(f"Final JSON result saved to: {output_path}")

View File

@ -244,7 +244,7 @@ def goods_bid_main(output_folder, file_path, file_type, unique_id):
#TODO: 目前跳转可能有个问题,资格审查那边:既有原来的内容又有跳转后的内容;符合本采购文件第一章第二款要求,并提供合格有效的证明材料<br>1、满足《中华人民共和国政府采购法》第二十二条规定<br>1具有独立承担 #TODO: 目前跳转可能有个问题,资格审查那边:既有原来的内容又有跳转后的内容;符合本采购文件第一章第二款要求,并提供合格有效的证明材料<br>1、满足《中华人民共和国政府采购法》第二十二条规定<br>1具有独立承担
#TODO:资格审查默认加上第一章的内容, 资格审查章节不做跳转逻辑. #TODO:资格审查默认加上第一章的内容, 资格审查章节不做跳转逻辑.
#TODO:开评定标那块,不做层次遍历 ing
#TODO:技术要求提取更全面一点 fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628 #TODO:技术要求提取更全面一点 fsdownload\a110ed59-00e8-47ec-873a-bd4579a6e628
#good_list 金额 截取上下文 #good_list 金额 截取上下文
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,6 +2,9 @@
import json import json
import os import os
import re import re
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from flask_app.general.通义千问long import upload_file, qianwen_long from flask_app.general.通义千问long import upload_file, qianwen_long
from flask_app.general.多线程提问 import multi_threading from flask_app.general.多线程提问 import multi_threading
from flask_app.general.json_utils import clean_json_string from flask_app.general.json_utils import clean_json_string
@ -371,17 +374,17 @@ def process_additional_queries(combined_res, match_keys, output_folder, notice_p
return final_result return final_result
def combine_qualification_review(invalid_path, output_folder, qualification_path, notice_path): def combine_qualification_review(invalid_path, qualification_path, notice_path):
DEFAULT_QUALIFICATION_REVIEW = { detailed_res = {}
"资格审查": {
"资格审查": "",
"符合性审查": ""
}
}
def process_file(file_path, invalid_path): # 初始化无效文件ID
file_id = upload_file(file_path) invalid_file_id = None
first_res = {}
if qualification_path:
# 上传资格文件并获取文件ID
qualification_file_id = upload_file(qualification_path)
# 定义第一个查询,用于检查资格性审查和符合性审查是否存在
first_query = """ first_query = """
该文档中是否有关于资格性审查标准的具体内容,是否有关于符合性审查标准的具体内容?请以json格式给出回答,外键分别为'资格性审查''符合性审查',键值仅限于'','',输出格式示例如下: 该文档中是否有关于资格性审查标准的具体内容,是否有关于符合性审查标准的具体内容?请以json格式给出回答,外键分别为'资格性审查''符合性审查',键值仅限于'','',输出格式示例如下:
{ {
@ -389,77 +392,211 @@ def combine_qualification_review(invalid_path, output_folder, qualification_path
"符合性审查":"" "符合性审查":""
} }
""" """
qianwen_ans = clean_json_string(qianwen_long(file_id, first_query))
user_queries = [ # 执行第一个查询并清洗返回的JSON字符串
print("call first_query")
first_res = clean_json_string(qianwen_long(qualification_file_id, first_query))
# 判断是否存在资格性和符合性审查
zige_file_id = qualification_file_id if first_res.get("资格性审查") == "" else None
fuhe_file_id = qualification_file_id if first_res.get("符合性审查") == "" else None
# 如果需要,上传无效文件
if zige_file_id is None or fuhe_file_id is None:
if invalid_file_id is None:
invalid_file_id = upload_file(invalid_path)
if zige_file_id is None:
zige_file_id = invalid_file_id
if fuhe_file_id is None:
fuhe_file_id = invalid_file_id
else:
# 如果 qualification_path 为空,直接使用无效文件
zige_file_id = fuhe_file_id = upload_file(invalid_path)
# 定义第二组查询
second_query = [
{ {
"key": "资格性审查", "key": "资格性审查",
"query": "该招标文件中规定的资格性审查标准是怎样的请以json格式给出外层为'资格性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关符合性性审查的内容。" "query": "该招标文件中规定的资格性审查标准是怎样的请以json格式给出外层为'资格性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关符合性审查的内容。"
}, },
{ {
"key": "符合性审查", "key": "符合性审查",
"query": "该招标文件中规定的符合性审查标准是怎样的请以json格式给出外层为'符合性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关资格性审查的内容。" "query": "该招标文件中规定的符合性审查标准是怎样的请以json格式给出外层为'符合性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关资格性审查的内容。"
} }
] ]
combined_res = {}
file_id2 = None # 延迟上传 invalid_path # 定义任务函数
def process_single_query(query_info): def process_second_query(key, query, file_id):
nonlocal file_id2 print("call second_query")
try:
res = qianwen_long(file_id, query)
cleaned_res = clean_json_string(res)
return key, cleaned_res.get(key, "未找到相关内容")
except Exception as e:
print(f"执行查询 '{key}' 时出错: {e}")
return key, "查询失败"
def process_notice(notice_path):
print("call notice_path")
try:
# 上传通知文件并获取文件ID
file_id1 = upload_file(notice_path)
# 定义用户查询,提取申请人资格要求
user_query1 = """
该文档中说明的申请人资格要求是怎样的请以json格式给出回答外键为'申请人资格要求'键值为字符串列表其中每个字符串对应原文中的一条要求你的回答与原文内容一致不要擅自总结删减输出格式示例如下
{
"申请人资格要求":[
"1.满足《中华人民共和国政府采购法》第二十二条规定;",
"1.1 法人或者其他组织的营业执照等证明文件,如供应商是自然人的提供身份证明材料;",
"2.未被列入“信用中国”网站(www.creditchina.gov.cn)信用服务栏失信被执行人、重大税收违法案件当事人名单;"
]
}
"""
# 执行查询并清洗结果
res1 = clean_json_string(qianwen_long(file_id1, user_query1))
# 提取申请人资格要求
requirements = res1.get("申请人资格要求", "未找到相关内容")
return "申请人资格要求", requirements
except Exception as e:
print(f"处理申请人资格要求时出错: {e}")
return "申请人资格要求", "处理失败"
# 初始化 ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=3) as executor:
future_to_key = {}
# 提交第二组查询
for query_info in second_query:
key = query_info["key"] key = query_info["key"]
query = query_info["query"] query = query_info["query"]
# 根据键值决定使用哪个 file_id current_file_id = zige_file_id if key == "资格性审查" else fuhe_file_id
if qianwen_ans.get(key) == "": future = executor.submit(process_second_query, key, query, current_file_id)
print("no") future_to_key[future] = key
if not file_id2:
file_id2 = upload_file(invalid_path)
current_file_id = file_id2
else:
current_file_id = file_id
# 调用大模型获取回答 # 有条件地提交通知处理
ans = qianwen_long(current_file_id, query) if qualification_path and notice_path and first_res.get("资格性审查") == "":
cleaned_data = clean_json_string(ans) future = executor.submit(process_notice, notice_path)
processed = process_dict(preprocess_dict(cleaned_data)) future_to_key[future] = "申请人资格要求"
return processed
# 使用线程池并行处理查询 # 收集结果(按完成顺序)
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: for future in as_completed(future_to_key):
futures = [executor.submit(process_single_query, q) for q in user_queries] key, result = future.result()
for future in concurrent.futures.as_completed(futures): detailed_res[key] = result
result = future.result()
combined_res.update(result)
return combined_res
try: # 定义所需的顺序
if not qualification_path: desired_order = ["申请人资格要求", "资格性审查", "符合性审查"]
file_to_process = invalid_path # print(json.dumps(detailed_res,ensure_ascii=False,indent=4))
else: # 创建一个新的有序字典
file_to_process = qualification_path ordered_res = {}
for key in desired_order:
if key in detailed_res:
ordered_res[key] = detailed_res[key]
combined_res = process_file(file_to_process,invalid_path) # 将重新排序后的字典传递给处理函数
match_keys = find_chapter_clause_references(combined_res) processed_data = process_dict(preprocess_dict(ordered_res))
if not match_keys: # 最终处理结果,例如打印或保存
return {"资格审查": combined_res} return processed_data
return process_additional_queries(combined_res, match_keys, output_folder, notice_path,invalid_path) #还要跳转到第一章
except Exception as e: # def combine_qualification_review(invalid_path, output_folder, qualification_path, notice_path):
print(f"Error in combine_qualification_review: {e}") # DEFAULT_QUALIFICATION_REVIEW = {
return DEFAULT_QUALIFICATION_REVIEW.copy() # "资格审查": {
# "资格审查": "",
# "符合性审查": ""
# }
# }
#
# def process_file(file_path, invalid_path):
# file_id = upload_file(file_path)
# first_query = """
# 该文档中是否有关于资格性审查标准的具体内容,是否有关于符合性审查标准的具体内容?请以json格式给出回答,外键分别为'资格性审查'和'符合性审查',键值仅限于'是','否',输出格式示例如下:
# {
# "资格性审查":"是",
# "符合性审查":"是"
# }
# """
# qianwen_ans = clean_json_string(qianwen_long(file_id, first_query))
# user_queries = [
# {
# "key": "资格性审查",
# "query": "该招标文件中规定的资格性审查标准是怎样的请以json格式给出外层为'资格性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关符合性性审查的内容。"
# },
# {
# "key": "符合性审查",
# "query": "该招标文件中规定的符合性审查标准是怎样的请以json格式给出外层为'符合性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关资格性审查的内容。"
# }
# ]
# combined_res = {}
# file_id2 = None # 延迟上传 invalid_path
# def process_single_query(query_info):
# nonlocal file_id2
# key = query_info["key"]
# query = query_info["query"]
# # 根据键值决定使用哪个 file_id
# if qianwen_ans.get(key) == "否":
# print("no")
# if not file_id2:
# file_id2 = upload_file(invalid_path)
# current_file_id = file_id2
# else:
# current_file_id = file_id
#
# # 调用大模型获取回答
# ans = qianwen_long(current_file_id, query)
# cleaned_data = clean_json_string(ans)
# processed = process_dict(preprocess_dict(cleaned_data))
# return processed
#
# # 使用线程池并行处理查询
# with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
# futures = [executor.submit(process_single_query, q) for q in user_queries]
# for future in concurrent.futures.as_completed(futures):
# result = future.result()
# combined_res.update(result)
# return combined_res
#
# try:
# if not qualification_path:
# file_to_process = invalid_path
# else:
# file_to_process = qualification_path
#
# combined_res = process_file(file_to_process,invalid_path)
# match_keys = find_chapter_clause_references(combined_res)
#
# if not match_keys:
# return {"资格审查": combined_res}
#
# return process_additional_queries(combined_res, match_keys, output_folder, notice_path,invalid_path) #还要跳转到第一章
#
# except Exception as e:
# print(f"Error in combine_qualification_review: {e}")
# return DEFAULT_QUALIFICATION_REVIEW.copy()
# 整合基础信息核心代码 # 整合基础信息核心代码
# [{'资格性审查.资格要求': '符合本采购文件第一章第二款要求,并提供合格有效的证明材料'}, {'资格性审查.没有重大违法记录的书面声明': '是否提交参加政府采购活动前三年内在经营活动中没有重大违法记录的书面承诺或声明(格式要求详见本项目采购文件第六章相关格式要求)'}] # [{'资格性审查.资格要求': '符合本采购文件第一章第二款要求,并提供合格有效的证明材料'}, {'资格性审查.没有重大违法记录的书面声明': '是否提交参加政府采购活动前三年内在经营活动中没有重大违法记录的书面承诺或声明(格式要求详见本项目采购文件第六章相关格式要求)'}]
if __name__ == "__main__": if __name__ == "__main__":
start_time=time.time()
# qualification_path="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\6.2定版视频会议磋商文件_qualification2.pdf" # qualification_path="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\6.2定版视频会议磋商文件_qualification2.pdf"
# output_folder = "D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89" # output_folder = "D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89"
output_folder="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5" output_folder="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5"
qualification_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile_qualification1.pdf" # qualification_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile_qualification1.pdf"
# qualification_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_qualification2.pdf" # qualification_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_qualification2.pdf"
qualification_path="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\6.2定版视频会议磋商文件_qualification2.pdf"
# notice_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_notice.pdf" # notice_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_notice.pdf"
notice_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile_notice.pdf" # notice_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile_notice.pdf"
notice_path="C:\\Users\\Administrator\\Desktop\\货物标\\output5\\6.2定版视频会议磋商文件_notice.pdf"
# knowledge_name = "6.2视频会议docx" # knowledge_name = "6.2视频会议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"
invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile.pdf" # invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\52e54b20-c975-4cf3-a06b-6f146aaa93f5\\ztbfile.pdf"
res = combine_qualification_review(invalid_path,output_folder, qualification_path, notice_path) invalid_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles\\6.2定版视频会议磋商文件.pdf"
res = combine_qualification_review(invalid_path, qualification_path, notice_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))