10.27分包情况商务、技术评分处理 日期、金额处理

This commit is contained in:
zy123 2024-10-27 15:26:51 +08:00
parent ae5c77bd25
commit aaebd47a04
6 changed files with 270 additions and 84 deletions

View File

@ -5,7 +5,7 @@ from flask_app.general.多线程提问 import multi_threading,read_questions_fro
from flask_app.general.通义千问long import upload_file,qianwen_long
# 从json文件中读取数据
with open('test.json', 'r', encoding='utf-8') as f:
with open('../testdir/test.json', 'r', encoding='utf-8') as f:
data_dict = json.load(f)
# 定义目标名称列表
@ -27,7 +27,7 @@ target_names = [
# 定义user_query模板
def generate_user_query(target, chapters, keywords):
#章节名格式通常是如'三、联合体协议书'这样的序号+标题。现在我需要将{target}贴在该章节的最后面,但是在下一章之前,目前我需要定位到插入的位置,
template = f"""这是投标文件格式要求的部分,作为投标方,我需要把不同的资格证明材料填充到指定区域,请你根据该文件回答:{target}应该附在该文件哪个地方?以下是可能匹配的章节名称:{', '.join([f"'{chapter}'" for chapter in chapters])};或者可能匹配的关键字:{', '.join([f"'{kw}'" for kw in keywords])},你需要根据以上规则确定{target}需要插入的位置,请你返回给我插入位置的上下文,以便于我定位原文,上文是插入章节或小节末尾的内容,下文应该是下一章节或小节开头的内容上下文合在一起应该是连续的字数都限制在20字以内。你的回答以json格式返回键名分别是'上文','下文',上下文内容应完全与原文保持一致,不得擅自删减总结,输出格式示例如下:
template = f"""这是投标文件格式要求的部分,作为投标方,我需要把不同的资格证明材料填充到指定区域,请你根据该文件回答:{target}应该附在该文件哪个地方?以下是可能匹配的章节名称:{', '.join([f"'{chapter}'" for chapter in chapters])};或者可能匹配的关键字:{', '.join([f"'{kw}'" for kw in keywords])},你需要根据以上规则确定{target}需要插入的位置,请你返回给我插入位置的上下文,以便于我定位原文,上文是插入章节或小节末尾的内容,下文应该是下一章节或下一小节开头的内容上下文合在一起应该是连续的字数都限制在20字以内。你的回答以json格式返回键名分别是'上文','下文',上下文内容应完全与原文保持一致,不得擅自删减总结,输出格式示例如下:
{{
"上文":"上文测试投标人: (盖单位章)
",

View File

@ -12,7 +12,7 @@ from flask_app.main.投标人须知正文提取指定内容 import extract_from_
import concurrent.futures
from flask_app.main.基础信息整合快速版 import combine_basic_info
from flask_app.main.资格审查模块 import combine_review_standards
from flask_app.main.商务标技术标整合 import combine_evaluation_standards
from flask_app.main.商务评分技术评分整合 import combine_evaluation_standards
from flask_app.general.format_change import pdf2docx, docx2pdf,doc2docx
from flask_app.general.docx截取docx import copy_docx

View File

@ -13,7 +13,7 @@ from flask_app.main.投标人须知正文提取指定内容 import extract_from_
import concurrent.futures
from flask_app.old_version.基础信息整合 import combine_basic_info
from flask_app.old_version.资格审查模块old import combine_review_standards
from flask_app.main.商务标技术标整合 import combine_evaluation_standards
from flask_app.main.商务评分技术评分整合 import combine_evaluation_standards
from flask_app.general.format_change import pdf2docx, docx2pdf
from flask_app.general.docx截取docx import copy_docx

View File

@ -1,84 +1,228 @@
def extract_matching_keys(data_dict, good_list):
import json
import re
from collections import defaultdict
def process_data_based_on_key(data):
exclude_word = ["", "未知", "评分因素"]
# 获取字典的键列表
keys = list(data.keys())
# 检查键的数量是否为1并且 exclude_word 中的任何词包含在 keys[0] 中
if len(keys) == 1 and any(word in keys[0] for word in exclude_word):
# 返回内层的字典
return data[keys[0]]
# 如果条件不满足,则返回原始字典
return data
def parse_json_with_duplicates(raw_string):
"""
递归遍历data_dict查找good_list中存在的键并将匹配的键及其值添加到结果字典中
解析具有重复键的 JSON 字符串将所有重复的键值对存储为列表
参数:
- data_dict (dict): 要遍历的嵌套字典
- good_list (list): 包含要查找的键的列表
Args:
json_string (str): 需要解析的 JSON 字符串
返回:
- dict: 包含所有匹配键及其值的字典
Returns:
dict: 解析后的字典重复的键对应的值为列表
eg:输入"综合实力": {
"评分": "2分",
"要求": "投标人具备电子与智能化工程专业承包二级资质及以上证书得 2分不能够提供不得分开标时需提供原件"
},
"综合实力": {
"评分": "2分",
"要求": "投标人具有建筑机电安装工程专业承包三级资质或以上资质得 2分否则不得分。证书开标原件备查"
}
输出"综合实力": [
{
"评分": "2分",
"要求": "投标人具备电子与智能化工程专业承包二级资质及以上证书得 2分不能够提供不得分开标时需提供原件"
},
{
"评分": "2分",
"要求": "投标人具有建筑机电安装工程专业承包三级资质或以上资质得 2分否则不得分。证书开标原件备查"
}]
"""
result = {}
def recurse(current_dict):
if isinstance(current_dict, dict):
for key, value in current_dict.items():
if key in good_list:
result[key] = value
# 递归遍历子字典
recurse(value)
elif isinstance(current_dict, list):
for item in current_dict:
recurse(item)
# 如果current_dict不是dict或list则无需进一步处理
def custom_object_pairs_hook(pairs):
d = defaultdict(list)
for key, value in pairs:
# 如果值是字典或列表,递归处理
if isinstance(value, dict):
value = process_dict(value)
elif isinstance(value, list):
value = process_list(value)
d[key].append(value)
# 将有多个值的键转换为列表,单个值的键保持原样
return {key: (values if len(values) > 1 else values[0]) for key, values in d.items()}
recurse(data_dict)
return result
def process_dict(d):
"""
递归处理字典确保所有重复键的值为列表
# 示例数据
data_dict = {
"门禁管理系统": {
"门禁控制器": {
"系统架构": "1.系统采用 CS架构支持 Web端登录支持远程软硬件重启升级、维护、管理。",
"联网方式": "2.★支持 TCP/IP、4G、RS485联网方式、有线与无线WIFI可自动切换 ,控制器支持百台到上千台设备组网,需满足大楼多门点的管理数量要求。",
"安装方式": "3.★安装方式支持壁挂安装。",
"开门方式": "4.★支持卡、密码、首卡、双卡、主卡/副卡、胁迫码、多卡分组、指纹识别+中心确认等开门方式。全面支持读卡器、指纹、人脸、指静脉、RS485识读设备的混合接入。"
},
"出门按钮": {
"安装方式": "标准 86底盒安装方式支持常开常闭方式",
"结构": "塑料面板",
"性能": "最大耐电流 1.25A电压 250V",
"服务要求": "产品 需全 国联 保,享 受三 包服 务,保 修期: 3年。"
},
"单门电磁锁": {
"1通电上锁断电开锁开门时间可调节。": "1通电上锁断电开锁开门时间可调节。",
"2稳定性强连续工作锁体无故障使用更安全。": "2稳定性强连续工作锁体无故障使用更安全。"
},
"指纹仪": {
"传感器类型": "1.先进半导体传感器,全面领先于普通光学识别技术,更好的判别假指纹、湿指、污损破皮手指。",
"显示及提示": "2.直观的 LCD液晶显示及语音验证提示配针孔摄像机实现视频联动抓拍手动布撤防实现与监控中心门禁系统实现对讲外置语音盒",
"验证方式": "3.支持 IC卡、指纹、卡加密码、编号多种组合验证方式。"
},
"门禁服务器": {
"CPU": "1颗 intel至强系列处理器核数≥12核主频≥2.2GHz",
"内存": "32G*2 DDR416根内存插槽最大支持扩展至 2TB内存",
"硬盘": "4块 600G 10K 2.5寸 SAS硬盘"
Args:
d (dict): 需要处理的字典
Returns:
dict: 处理后的字典
"""
return custom_object_pairs_hook(d.items())
def process_list(l):
"""
递归处理列表确保列表中的所有字典也被处理
Args:
l (list): 需要处理的列表
Returns:
list: 处理后的列表
"""
return [process_dict(item) if isinstance(item, dict) else item for item in l]
"""输入字符串,提取 { 和 } 之间的内容,并将其解析为字典"""
if not raw_string.strip():
return {}
match = re.search(r'\{[\s\S]*\}', raw_string)
if match:
try:
json_string = match.group(0)
return json.loads(json_string, object_pairs_hook=custom_object_pairs_hook)
except json.JSONDecodeError as e:
print(f"json_utils: extract_content_from_json: JSON decode error: {e}")
return {}
else:
print("json_utils: extract_content_from_json: No valid JSON content found.")
return {}
def combine_technical_and_business(data, target_values):
extracted_data = {} # 根级别存储所有数据
technical_found = False
business_found = False
def extract_nested(data, parent_key='', is_technical=False, is_business=False):
nonlocal technical_found, business_found
if isinstance(data, dict):
for key, value in data.items():
current_key = f"{parent_key}.{key}" if parent_key else key
# 检查是否为技术标的内容
if any(target in key for target in target_values):
if not is_technical:
extracted_data[key] = value
technical_found = True
continue
# 默认其他所有内容都归为商务标
else:
if not is_business:
if '商务评分' not in extracted_data:
extracted_data['商务评分'] = {}
extracted_data['商务评分'][key] = value
business_found = True
continue
if isinstance(value, dict) or isinstance(value, list):
extract_nested(value, current_key, is_technical, is_business)
elif isinstance(data, list):
for index, item in enumerate(data):
extract_nested(item, f"{parent_key}[{index}]", is_technical, is_business)
extract_nested(data)
if not technical_found:
extracted_data['技术评分'] = ''
if not business_found:
extracted_data['商务评分'] = ''
return extracted_data
raw_data="""
{
"一包": {
"技术评分": {
"主要监理岗位的职责": {
"评分": "4分",
"要求": "1、总监理工程师的职责全面、清晰、合理得 1.2-2分一般的1.2分。2、其他主要监理人员及岗位的职责全面、清晰、合理得 1.2-2分一般的 1.2分。"
},
"备注": "若不满足“与公安部、省公安厅、随州市公安局高清视频会议系统无缝对接互联互通”的要求则本项技术部分50分不得分。"
},
"商务评分": {
"控制系统内主板": {
"评分": "10分",
"要求": "所投电梯控制系统内主板为制造商原厂原品牌制造生产且为进口部件得 10分。提供进口部件报关单及原产地证明扫描件加盖公章否则不得分"
},
"制造商技术实力": [
{
"评分": "3分",
"要求": "一级证书得3分二级证书得1分其他不得分"
},
{
"评分": "2分",
"要求": "行业销量排名连续前 2 名,得 2 分,第 4-6 名得 0.5 分,其他不得分"
}
]
},
"投标报价评审": {
"投标报价是否出现违反计价规范": {
"评分": "合格/不合格",
"要求": "A:投标报价未违反计价规范的评审意见为“合格”B投标报价违反计价规范的评审意见为“不合格”"
}
}
}
},
"摄像系统": {
"佳能摄像机": {
"清晰度": "1k"
},
"尼康录影机": {
"画质": "2k"
}
}
}
"""
def reorganize_data(input_dict, include=None):
"""
重组输入字典技术评分商务评分提升为最外层键
并将包含在 include 列表中的包名的数据嵌套在相应的评分类别下
good_list = [
"门禁控制器",
"出门按钮",
"单门电磁锁",
"指纹仪",
"门禁服务器",
"佳能摄像机",
"尼康录影机"
]
如果 input_dict 的顶层键不包含任何 include 列表中的项则返回原始字典
# 使用函数提取匹配的键
filtered_dict = extract_matching_keys(data_dict, good_list)
:param input_dict: 原始输入字典
:param include: 包名列表例如 ['一包', '二包', '三包']
:return: 重组后的字典
"""
if include is None:
include = []
# 打印结果
import pprint
pprint.pprint(filtered_dict)
# 检查是否有任何顶层键包含在 include 列表中
has_include = any(key in include for key in input_dict.keys())
if not has_include:
# 没有包含任何指定的包名,直接返回原始字典
return input_dict
# 初始化新的字典结构
reorganized = {
"技术评分": {},
"商务评分": {}
}
# 遍历每一个包(如 "一包", "二包"
for package, categories in input_dict.items():
# 处理技术评分
if "技术评分" in categories:
reorganized["技术评分"][package] = categories["技术评分"]
# 处理商务评分
if "商务评分" in categories:
reorganized["商务评分"][package] = categories["商务评分"]
return reorganized
include = ['一包', '二包', '三包', '四包', '五包']
target_values = ['技术', '设计', '实施']
cleaned_evaluation_res = parse_json_with_duplicates(raw_data) #处理重复键名的情况
result_data = process_data_based_on_key(cleaned_evaluation_res)
updated_jsons = {}
if any(key for key in result_data if any(included in key for included in include)):
# 有匹配的项,处理这些项
for key in result_data:
if any(item in key for item in include):
inner_dict = result_data[key]
updated_jsons[key] = combine_technical_and_business(inner_dict, target_values)
else:
# 没有匹配的项,对整个字典运行
updated_jsons = combine_technical_and_business(result_data, target_values)
res=reorganize_data(updated_jsons,include)
print(json.dumps(res, ensure_ascii=False, indent=4))

View File

@ -1,6 +1,7 @@
# -*- encoding:utf-8 -*-
import json
import re
import time
from collections import defaultdict
from flask_app.general.通义千问long import upload_file, qianwen_long
@ -143,6 +144,44 @@ def parse_json_with_duplicates(raw_string):
print("json_utils: extract_content_from_json: No valid JSON content found.")
return {}
def reorganize_data(input_dict, include=None):
"""
重组输入字典技术评分商务评分提升为最外层键
并将包含在 include 列表中的包名的数据嵌套在相应的评分类别下
如果 input_dict 的顶层键不包含任何 include 列表中的项则返回原始字典
:param input_dict: 原始输入字典
:param include: 包名列表例如 ['一包', '二包', '三包']
:return: 重组后的字典
"""
if include is None:
include = []
# 检查是否有任何顶层键包含在 include 列表中
has_include = any(key in include for key in input_dict.keys())
if not has_include:
# 没有包含任何指定的包名,直接返回原始字典
return input_dict
# 初始化新的字典结构
reorganized = {
"技术评分": {},
"商务评分": {}
}
# 遍历每一个包(如 "一包", "二包"
for package, categories in input_dict.items():
# 处理技术评分
if "技术评分" in categories:
reorganized["技术评分"][package] = categories["技术评分"]
# 处理商务评分
if "商务评分" in categories:
reorganized["商务评分"][package] = categories["商务评分"]
return reorganized
def combine_evaluation_standards(truncate_file):
# 定义默认的评审结果字典
@ -218,24 +257,24 @@ def combine_evaluation_standards(truncate_file):
evaluation_res = qianwen_long(file_id, user_query)
# 清理和处理响应
cleaned_evaluation_res = parse_json_with_duplicates(evaluation_res)
result_data = process_data_based_on_key(cleaned_evaluation_res)
cleaned_evaluation_res = parse_json_with_duplicates(evaluation_res) #处理重复键名的情况
result_data = process_data_based_on_key(cleaned_evaluation_res) #处理不知名外键的情况
include = ['一包', '二包', '三包', '四包', '五包']
target_values = ['技术', '设计', '实施']
updated_jsons = {}
# 检查是否有外层键匹配 include 列表
if any(key for key in result_data if any(included in key for included in include)):
if any(key for key in result_data if any(included in key for included in include)): #检查result_data中的任何键是否包含include列表中的任意一个项。
# 有匹配的项,处理这些项
for key in result_data:
if any(item in key for item in include):
inner_dict = result_data[key]
updated_jsons[key] = combine_technical_and_business(inner_dict, target_values)
updated_jsons[key] = combine_technical_and_business(inner_dict, target_values) #对于分包,单独对分包内的'技术评分''商务评分'作处理
else:
# 没有匹配的项,对整个字典运行
updated_jsons = combine_technical_and_business(result_data, target_values)
return updated_jsons
final_res=reorganize_data(updated_jsons,include) #重新组织字典,尤其是分包的情况
return final_res
else:
# 如果 judge 是 False直接返回默认的技术标和商务标的结构
result_data = {}
@ -250,10 +289,13 @@ def combine_evaluation_standards(truncate_file):
if __name__ == "__main__":
# truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output2\\2-招标文件_evaluation_method.pdf"
start_time=time.time()
truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output2\\招标文件(107国道)_evaluation_method.pdf"
# truncate_file = "C:\\Users\\Administrator\\Desktop\\货物标\\output2\\2-招标文件统计局智能终端二次招标_evaluation_method.pdf"
# truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output2\\广水市妇幼招标文件最新W改_evaluation_method.pdf"
# truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\2d481945-1f82-45a5-8e56-7fafea4a7793\\ztbfile_evaluation_method.pdf"
truncate_file="C:\\Users\\Administrator\\Desktop\\fsdownload\\ztbfile_evaluation_method.pdf"
# truncate_file="C:\\Users\\Administrator\\Desktop\\fsdownload\\ztbfile_evaluation_method.pdf"
res = combine_evaluation_standards(truncate_file)
print(json.dumps(res, ensure_ascii=False, indent=4))
end_time=time.time()
print("elapsed time:"+str(end_time-start_time))