9.23测试分段

This commit is contained in:
zy123 2024-09-23 17:44:34 +08:00
parent 696319056e
commit 4359885099
5 changed files with 373 additions and 309 deletions

View File

@ -56,76 +56,99 @@ def create_logger():
g.logger = logger
@app.route('/upload', methods=['POST'])
def zbparse():
logger=g.logger
file_url = validate_request()
if isinstance(file_url, tuple): # Check if the returned value is an error response
return file_url
try:
logger.info("starting parsing url:" + file_url)
final_json_path, output_folder= download_and_process_file(file_url)
if not final_json_path:
return jsonify({'error': 'File processing failed'}), 500
response = generate_response(final_json_path) # 先获取响应内容
# remove_directory(output_folder) # 然后删除文件夹
return response # 最后返回获取的响应
except Exception as e:
logger.error('Exception occurred: ' + str(e)) # 使用全局 logger 记录
return jsonify({'error': str(e)}), 500
# 流式
# @app.route('/upload', methods=['POST'])
# def zbparse():
# logger = g.logger
# logger=g.logger
# file_url = validate_request()
# if isinstance(file_url, tuple): # Check if the returned value is an error response
# return file_url
# try:
# logger.info("starting parsing url:" + file_url)
# return Response(stream_with_context(process_and_stream(file_url)), content_type='text/event-stream')
# final_json_path, output_folder= download_and_process_file(file_url)
# if not final_json_path:
# return jsonify({'error': 'File processing failed'}), 500
# response = generate_response(final_json_path) # 先获取响应内容
# # remove_directory(output_folder) # 然后删除文件夹
# return response # 最后返回获取的响应
# except Exception as e:
# logger.error('Exception occurred: ' + str(e))
# logger.error('Exception occurred: ' + str(e)) # 使用全局 logger 记录
# return jsonify({'error': str(e)}), 500
#分段返回
# def process_and_stream(file_url):
# logger = g.logger
# unique_id = g.unique_id
# output_folder = f"flask_app/static/output/{unique_id}" # 直接使用全局 unique_id 构建路径
# filename = "ztbfile"
# downloaded_filename = os.path.join(output_folder, filename)
#
# downloaded_filepath, file_type = download_file(file_url, downloaded_filename)
#
# if downloaded_filepath is None or file_type == 3:
# logger.error("Unsupported file type or failed to download file")
# error_response = {
# 'message': 'File processing failed',
# 'filename': None,
# 'data': json.dumps({'error': 'File processing failed'})
# }
# yield f"data: {json.dumps(error_response)}\n\n"
# return
#
# logger.info("Local file path: " + downloaded_filepath)
#
# for data in main_processing(output_folder, downloaded_filepath, file_type, unique_id):
# response = {
# 'message': 'Processing',
# 'filename': os.path.basename(downloaded_filepath),
# 'data': data
# }
# yield f"data: {json.dumps(response)}\n\n"
#
# final_response = {
# 'message': 'File uploaded and processed successfully',
# 'filename': os.path.basename(downloaded_filepath),
# 'data': 'END'
# }
# yield f"data: {json.dumps(final_response)}\n\n"
# 流式
@app.route('/upload', methods=['POST'])
def zbparse():
logger = g.logger
file_url = validate_request()
if isinstance(file_url, tuple): # Check if the returned value is an error response
return file_url
try:
logger.info("starting parsing url:" + file_url)
return Response(stream_with_context(process_and_stream(file_url)), content_type='text/event-stream')
except Exception as e:
logger.error('Exception occurred: ' + str(e))
return jsonify({'error': str(e)}), 500
# 分段返回
def process_and_stream(file_url):
logger = g.logger
unique_id = g.unique_id
output_folder = f"flask_app/static/output/{unique_id}"
filename = "ztbfile"
downloaded_filename = os.path.join(output_folder, filename)
downloaded_filepath, file_type = download_file(file_url, downloaded_filename)
if downloaded_filepath is None or file_type == 3:
logger.error("Unsupported file type or failed to download file")
error_response = {
'message': 'File processing failed',
'filename': None,
'data': json.dumps({'error': 'File processing failed'})
}
yield f"data: {json.dumps(error_response)}\n\n"
return
logger.info("Local file path: " + downloaded_filepath)
combined_data = {}
for data in main_processing(output_folder, downloaded_filepath, file_type, unique_id):
response = {
'message': 'Processing',
'filename': os.path.basename(downloaded_filepath),
'data': data
}
yield f"data: {json.dumps(response)}\n\n"
# 解析数据并添加到 combined_data
parsed_data = json.loads(data.split('data: ')[1])
for outer_key, inner_dict in parsed_data.items():
if isinstance(inner_dict, dict):
# 获取内层字典的第一个(也是唯一的)键值对
inner_key, inner_value = next(iter(inner_dict.items()))
if outer_key not in combined_data:
combined_data[outer_key] = {}
combined_data[outer_key][inner_key] = inner_value
else:
# 处理 evaluation_standards 的特殊情况
combined_data[outer_key] = inner_dict
# 发送整合后的完整数据
complete_response = {
'message': 'Combined data',
'filename': os.path.basename(downloaded_filepath),
'data': combined_data
}
yield f"data: {json.dumps(complete_response, ensure_ascii=False)}\n\n"
# 发送最终响应
final_response = {
'message': 'File uploaded and processed successfully',
'filename': os.path.basename(downloaded_filepath),
'data': 'END'
}
yield f"data: {json.dumps(final_response)}\n\n"
def validate_request():

View File

@ -1,104 +1,7 @@
import json
import re
dict1 = {"a": {}}
dict2 = {"b": {}}
def transform_json(data):
result = {}
temp = {0: result} # 初始化根字典
# 使用 update() 方法
dict1.update(dict2)
# 首先,创建一个临时字典用于检查是否存在三级标题
has_subkey = {}
for key in data.keys():
parts = key.split('.')
if len(parts) > 2 and parts[1]:
parent_key = parts[0] + '.' + parts[1]
has_subkey[parent_key] = True
for key, value in data.items():
match = re.match(r'(\d+)(?:\.(\d+))?(?:\.(\d+))?', key)
if match:
levels = [int(l) for l in match.groups() if l is not None]
if (len(levels) - 1) in temp:
parent = temp[len(levels) - 1]
else:
print(f"No parent found at level {len(levels) - 1} for key '{key}'. Check the data structure.")
continue
if len(levels) == len(match.groups()):
if isinstance(parent, list):
parent.append(value)
else:
# 对于根级别,使用完整的值作为键
if len(levels) == 1:
parent[value] = {}
temp[len(levels)] = parent[value]
else:
parent[value.split()[0]] = value
else:
new_key = value
if '\n' in value and len(levels) == 2 and f"{levels[0]}.{levels[1]}" not in has_subkey:
new_key, new_value = value.split('\n', 1)
new_key = new_key.strip()
new_value = new_value.strip()
if isinstance(parent, list):
if len(parent) == 0 or not isinstance(parent[-1], dict):
parent.append({})
parent[-1][new_key] = new_value
else:
parent[new_key] = new_value
else:
if isinstance(parent, list):
if len(parent) == 0 or not isinstance(parent[-1], dict):
parent.append({})
parent = parent[-1]
if new_key not in parent:
parent[new_key] = []
temp[len(levels)] = parent[new_key]
def remove_single_item_lists(node):
if isinstance(node, dict):
for key in list(node.keys()):
node[key] = remove_single_item_lists(node[key])
if isinstance(node[key], list) and not node[key]:
node[key] = ""
elif isinstance(node, list) and len(node) == 1:
return remove_single_item_lists(node[0])
return node
return remove_single_item_lists(result)
# 示例 JSON 数据
data = {
"3.1": "投标文件的组成",
"3.1.1": "投标文件应包括下列内容:(1)投标函及投标函附录;(2)法定代表人身份证明;(3)联合体协议书(如有)(4)投标保证金;(5)监理服务费投标报价表;(6)监理大纲;(7)监理机构;(8)资格审查资料;(9)投标人须知前附表规定的其他材料。",
"3.1.2": "招标公告规定不接受联合体投标的或投标人没有组成联合体的投标文件不包括本章第3.1.1项第(3)目所指的联合体协议书。",
"3.1.3": "投标人须知前附表规定不允许分包的投标文件不包括本章第3.1.1项第(8)目所指的拟分包项目情况表。",
"3.6": "投标文件的编制",
"3.6.1": "投标文件应按“投标文件格式”进行编写,如有必要,可以增加附页,作为投标文件的组成部分。其中,投标函附录在满足招标文件实质性要求的基础上,可以提出比招标文件要求更有利于招标人的承诺。",
"4.": "投标",
"4.1": "投标文件的密封与标记",
"4.1.1": "投标文件的加密加密的电子投标文件应按照本章第3.6.3项要求制作并加密,未按要求加密的电子投标文件,招标人(“市电子交易平台”)将拒收并提示。",
"4.1.2": "不加密的电子投标文件的密封和标识1不加密的电子投标文件U盘备份应单独密封包装并在封套的封口处加贴封条。2不加密的电子投标文件U盘备份封套上应写明的其他内容见投标人须知前附表。3未按本章第4.1.2项要求密封和加写标记的投标文件,招标人将拒收。",
"4.2": "投标文件的递交",
"4.2.1": "在招标公告规定的投标截止时间前,投标人可以修改或撤回已递交的投标文件。",
"4.2.2": "投标人对加密的电子投标文件进行撤回的在“市电子交易平台”直接进行撤回操作投标人对不加密的电子投标文件U盘备份进行撤回的应以书面形式通知招标人撤回的书面通知应加盖投标人的单位章或由法定代表人或其委托代理人签字指亲笔签名招标人收到书面通知后向投标人出具签收凭证。",
"4.3": "投标文件的修改与撤回",
"4.3.1": "在送交投标文件截止期以前,投标人可以更改或撤回投标文件,并按本章第项的规定操作。",
"4.3.2": "送交投标文件截止期以后投标文件不得更改。需对投标文件做出澄清时必须按照本须知第23条的规定办理。",
"4.3.4": "如果在送交投标文件截止期以后且投标文件有效期内撤回投标文件则按本须知第3.4.4款的规定不予退还其投标担保。",
}
def sort_data_keys(data):
# 将键转换成由整数构成的元组,作为排序依据
def key_func(key):
return tuple(int(part) for part in re.split(r'\D+', key) if part)
# 对字典键进行排序
sorted_keys = sorted(data.keys(), key=key_func)
# 创建一个新的字典,按照排序后的键添加键值对
sorted_data = {key: data[key] for key in sorted_keys}
return sorted_data
sorted_data=sort_data_keys(data)
# 调用 transform_json 函数
transformed_data = transform_json(sorted_data)
# 打印结果
print(json.dumps(transformed_data, indent=4, ensure_ascii=False))
print(dict1)

File diff suppressed because one or more lines are too long

View File

@ -83,26 +83,72 @@ def process_dict(data):
# 测试代码
input_data = {
"符合性审查": {
"说明": "评标委员会应当对符合资格的投标人的投标文件进行符合性审查,以确定其是否满足招标文件的实质性要求。",
"审查标准": [
{
"序号": 9,
"内容": "未按要求提供加盖公章及签字(签章)的;"
"资格性审查": {
"资格证明文件审查": [
"应具备《政府采购法》第二十二条第一款规定的条件,提供下列材料:",
{
"法人或者其他组织的营业执照等证明文件,自然人的身份证明(投标人根据自身情况提供对应的证明材料)": {
"法人": {
"企业法人(包括合伙企业)": "提供工商部门注册的有效“企业法人营业执照” 或“营业执照”;",
"事业单位法人": "提供有效的“事业单位法人证书”。"
},
"其他组织": {
"非企业专业服务机构": "提供执业许可证等证明文件;",
"个体工商户": "提供有效的“个体工商户营业执照”。"
},
"自然人": "提供有效的自然人身份证明。(仅限中国公民)"
}
},
{
"财务状况报告,依法缴纳税收和社会保障资金的相关材料(投标人根据自身情况提供对应的证明材料)": {
"法人": {
"财务状况报告": {
"(1)": "提供经第三方审计的财务报告(完整的财务报告,包括“四表一注”, 即资产负债表、利润表、现金流量表、所有者权益变动表及其附注),或其基 本开户银行出具的资信证明;",
"(2)": "部分其他组织和自然人:没有经第三方审计的财务报告的,可以提供银行出具 的资信证明;",
"(3)": "投标人没有经第三方审计的财务报告和资信证明时,也可以提供财政部门认可 的政府采购专业担保机构出具的投标担保函。"
},
{
"序号": 1,
"内容": "a39"
},
{
"序号": 2,
"内容": "依据财库[2019]9号文的规定招标文件采购清单中为“节能产品”的货物未提供国家确定的认证机构出具的节能产品认证证书的"
},
]
}
"依法缴纳税收和社会保障资金的证明材料": {
"(1)": {
"税务登记证(国税、地税或多证合一);": "",
"参加政府采购活动前一段时间内缴纳增值税、营业税和企业所得税的凭据;": "",
"社会保险登记证(或多证合一);": "",
"参加政府采购活动前一段时间内缴纳社会保险的凭据(专用收据或社会保险 缴纳清单)。": ""
},
"(2)": {
"参加政府采购活动前一段时间内缴纳税收的凭据;": "",
"参加政府采购活动前一段时间内缴纳社会保险的凭据(专用收据或社会保险 缴纳清单)。": ""
},
"(3)": "依法免税或不需要缴纳社会保险资金的投标人 提供其依法免税或不需要缴纳社会保险资金的相关证明文件。"
}
}
}
},
{
"具备履行合同所必需的设备和专业技术能力的证明材料": {
"提供具备足够数量的设施设备的证明材料;": "",
"提供具备足够数量的技术人员的证明材料。": ""
}
},
{
"参加政府采购活动前 3年内在经营活动中没有重大违法记录的书面声明": {
"应严格按照附件格式提交“参加政府采购活动前三年内在经营活动中没有重大 违法记录的书面声明函”;": "",
"政府采购法第二十二条第一款第五项所称重大违法记录,是指供应商因违法经 营受到刑事处罚或者责令停产停业、吊销许可证或者执照、较大数额罚款等行政处罚;": "",
"按照财政部《关于规范政府采购行政处罚有关问题的通知》的规定,各级人民 政府财政部门依法对参加政府采购活动的供应商作出的禁止参加政府采购活动等行政 处罚决定在全国范围内生效。": ""
}
},
"具备法律、行政法规规定的其他条件的证明材料:",
{
"1": "国家对生产和销售相关产品或提供相关服务有专门法律、行政法规规定的,则 必须提供取得国家有关主管部门行政许可的证明材料。",
"2": "未被列入“信用中国”网站(www.creditchina.gov.cn)信用服务栏失信被执行人、重 大税收违法案件当事人名单、政府采购严重违法失信行为记录名单和“中国政 府采购”网站www.ccgp.gov.cn政府采购严重违法失信行为记录名单并提供 网页截图以证明;",
"3": "招标文件第一章“投标人资格要求”中有特殊要求的,投标人应提供其符合特 殊要求的证明材料或者情况说明;",
"4": "不符合联合体投标相关规定和要求的;",
"5": "投标人认为需提供的其它相关资格证明材料;",
"6": "资格证明文件正本应为清晰彩色影印件且加盖单位公章。"
}
]
}
}
pred=preprocess_dict(input_data)
print(json.dumps(pred, ensure_ascii=False, indent=4))
# processed_data = process_dict(pred)
# print(json.dumps(processed_data, ensure_ascii=False, indent=4))
processed_data = process_dict(pred)
print(json.dumps(processed_data, ensure_ascii=False, indent=4))

View File

@ -1,24 +1,106 @@
# -*- encoding:utf-8 -*-
import json
import re
from flask_app.main.基础信息整合 import combine_basic_info
from flask_app.main.通义千问long import qianwen_long,upload_file
from flask_app.main.多线程提问 import multi_threading
from flask_app.main.json_utils import combine_json_results
from flask_app.main.json_utils import combine_json_results,clean_json_string
#这个字典可能有嵌套,你需要遍历里面的键名,对键名作判断,而不是键值,具体是这样的:如果处于同一层级的键的数量>1并且键名全由数字或点号组成。那么就将这些序号键名全部删除重新组织成一个字典格式的数据你可以考虑用字符串列表来保持部分平级的数据
#对于同级的键,如果数量>1且键名都统一那么将键名去掉用列表保持它们的键值
#对于同一个字典中,可能存在若干键值对,若它们的键值都是""或者"/" 你就将它们的键值删去,它们的键名用字符串列表保存
def is_numeric_key(key):
# 这个正则表达式匹配由数字、点、括号中的数字或单个字母(小写或大写)组成的字符串,
# 字母后跟数字,或数字后跟字母,单个字母后跟点,但不能是字母-数字-字母的组合
pattern = r'^[\d.]+$|^\(\d+\)$|^\d+$|^[a-zA-Z]$|^[a-zA-Z]\d+$|^\d+[a-zA-Z]$|^[a-zA-Z]\.$'
return re.match(pattern, key) is not None
#TODO:如果键值中存在数字就不行
#zbtest20也有问题
def contains_number_or_index(key, value):
# 判断值是否是数字或数字字符串
is_number = isinstance(value, (int, float)) or (isinstance(value, str) and value.isdigit())
# 判断键是否包含 "序号"
contains_index = '序号' in key
# 判断值中是否包含数字
contains_digit = isinstance(value, str) and re.search(r'\d+', value)
# 判断值中是否包含中文字符
contains_chinese = isinstance(value, str) and re.search(r'[\u4e00-\u9fff]', value)
# 如果值中包含数字但也有中文字符,则保留(返回 False
if contains_digit and contains_chinese:
return False
# 如果值是数字或包含数字,且不包含中文字符,或者键包含 "序号",返回 True
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 == "/" 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):
if not isinstance(data, dict):
return data
result = {}
numeric_keys = []
non_numeric_keys = {}
for key, value in data.items():
if is_numeric_key(key):
numeric_keys.append((key, value))
else:
non_numeric_keys[key] = value
# 处理数字键,不再要求数量>1
if numeric_keys:
result['items'] = [process_dict(item[1]) for item in sorted(numeric_keys)]
# 处理非数字键
for key, value in non_numeric_keys.items():
if isinstance(value, list) and len(value) > 1 and all(isinstance(item, dict) and len(item) == 1 for item in value):
common_key = next(iter(value[0].keys()))
if all(common_key in item and len(item) == 1 for item in value):
result[key] = [process_dict(item[common_key]) for item in value]
else:
result[key] = [process_dict(item) for item in value]
else:
result[key] = process_dict(value)
# 如果结果只包含'items'键,直接返回其值
if len(result) == 1 and 'items' in result:
return result['items']
return result
def qualification_review(truncate_file):
file_id=upload_file(truncate_file)
user_query1="该招标文件中规定的资格性审查标准是怎样的请以json格式给出外层为'资格性审查',对于原文中的序号,你仅需要捕获它们之间的层级关系并根据序号后的内容生成嵌套键值对,若多个内容位于同一层级,你应用字符串列表作为键值保存这些内容,你的回答需删去这些序号,但其余内容要与原文一致,不可擅自总结删减,也不要回答符合性审查的内容。"
user_query2="该招标文件中规定的符合性审查标准是怎样的请以json格式给出外层为'符合性审查',你的回答要与原文一致,不可擅自总结删减,也不要回答资格性审查的内容。"
user_query=[]
user_query.append(user_query1)
user_query.append(user_query2)
user_query=["该招标文件中规定的资格性审查标准是怎样的请以json格式给出外层为'资格性审查',对于原文中的序号,你仅需要捕获它们之间的层级关系并根据序号后的内容生成嵌套键值对,若多个内容位于同一层级,你应用字符串列表作为键值保存这些内容,你的回答需删去这些序号,但其余内容要与原文一致,不可擅自总结删减,也不要回答符合性审查的内容。","该招标文件中规定的符合性审查标准是怎样的请以json格式给出外层为'符合性审查',你的回答要与原文一致,不可擅自总结删减,也不要回答资格性审查的内容。"]
results=multi_threading(user_query,"",file_id,2)
result_list=[]
combined_res = {}
for question, response in results:
result_list.append(response)
combined_res = combine_json_results(result_list) # 整合基础信息核心代码
print(response)
cleaned_data = clean_json_string(response)
processed1 = preprocess_dict(cleaned_data)
processed2 = process_dict(processed1)
combined_res.update(processed2)
# 整合基础信息核心代码
return combined_res
if __name__ == "__main__":
truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\2-招标文件2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目_qualification1.pdf"
truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\2-招标文件(广水市教育局封闭管理_qualification1.pdf"
res=qualification_review(truncate_file)
print(json.dumps(res,ensure_ascii=False, indent=4))