264 lines
12 KiB
Python
Raw Normal View History

2024-10-16 20:18:55 +08:00
import json
2024-10-15 20:57:58 +08:00
import re
2024-10-16 20:18:55 +08:00
combined_data = {
"基础信息": {
"招标人/代理信息": {
"招标人": "广水市公安局",
"招标人联系方式": {
"名称": "广水市公安局",
"地址": "广水市应山办事处应十大道 189号",
"联系电话": "未知"
},
"招标代理机构": "湖北楚振捷工程项目管理有限公司",
"招标代理机构联系方式": {
"名称": "湖北楚振捷工程项目管理有限公司",
"地址": "广水市永阳一路 41号",
"联系方式": "0722-6256088"
},
"项目联系方式":{
"名称":"张三",
"联系电话":"11"
}
},
"项目信息": {
"项目名称": "广水市公安局视频会议高清化改造项目",
"项目编号": "HBCZJ-2021-CS12",
"项目概况": "广水市公安局视频会议高清化改造项目",
"项目基本情况": {
"项目编号": "HBCZJ-2021-CS12",
"采购计划备案号": "2021-04-000399",
"项目名称": "广水市公安局视频会议高清化改造项目",
"采购方式": "竞争性磋商",
"预算金额": "192万元",
"最高限价": "192万元",
"采购需求": {
"项目概况及内容": "广水市公安局视频会议高清化改造项目。",
"招标范围": "广水市公安局视频会议高清化改造项目,具体内容见磋商文件第三章。",
"项目地点": "具体以合同约定为准。"
},
"合同履行期限": "以合同签订为准。",
"本项目(是/否)接受联合体投标": "",
"是否可采购进口产品": ""
},
"招标控制价": "192万元",
"投标竞争下浮率": "未知",
"是否允许分包": "未知",
"是否接受联合体投标": ""
},
"采购要求": {
"技术要求": "未提供",
"商务要求": "未提供",
"服务要求": "未提供",
"其他要求": "未提供"
},
"关键时间/内容": {
"投标文件递交截止日期": "2021年 6月 18日 15点 00分",
"开标时间":"111",
"开标地点":"哈哈",
"澄清招标文件的截止时间": "未知",
"投标有效期": "90日历天",
"信息公示媒介": "中国湖北政府采购网http://www.ccgp-hubei.gov.cn, 中国广水网http://www.zggsw.gov.cn/",
"投标文件递交地点": "广水市公共资源交易中心五楼 501号开标室"
},
"保证金相关": {
"质量保证金": "未知",
"履约保证金": "不提交",
"退还投标保证金": "/",
"投标保证金": {
"价格":"100000000.00 元"
}
},
"其他信息": {
"是否退还投标文件": "",
"投标费用承担": "供应商应承担所有与准备和参加磋商有关的费用,不论磋商的结果如何,采购人和采购代理机构均无义务和责任承担这些费用。",
"招标代理服务费": {
"支付人": "成交供应商",
"支付标准": "根据国家发展与改革委员会办公厅发改办价格【2003】857 号文的规定经协商由成交供应商按国家发展和改革委员发改价格【2011】534号文规定货物类取费标准向采购代理机构支付招标代理服务费包含“招标代理费、评标会务费、评标费”如本项目各包服务费不足叁仟元则供应商按叁仟元支付服务费。",
"支付方式": "成交服务费由成交供应商在领取成交通知书的同时向代理机构支付,可使用现金或电汇办理",
"支付时间": "领取成交通知书的同时"
},
"偏离": {
"偏离项要求": "供应商需在响应文件中提供《采购需求响应、偏离说明表/导读表》具体格式见第六章响应文件格式中的49页。供应商需对采购需求中的各项技术参数和服务要求进行逐项响应明确表明无偏离、正偏离或负偏离的情况。对于负偏离项需详细说明偏离的具体内容及原因。",
"偏离项内容": "未知"
},
"投标预备会": "不召开",
"踏勘现场": "不组织"
}
},
"资格审查": { },
"商务评分": { },
"技术评分": { },
"zhes":"11111"
# 其他键值对
}
includes = ["基础信息", "资格审查", "商务评分", "技术评分", "无效标与废标项", "投标文件要求", "开评定标流程"]
def post_processing(combined_data, includes):
# 初始化结果字典,预设'其他'分类为空字典
processed_data = {"其他": {}}
# 初始化提取的信息字典
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忽略
2024-10-15 20:57:58 +08:00
continue
2024-10-16 20:18:55 +08:00
# 第二步:如果没有找到包含 "金额" 的键,尝试在所有键值中查找符合模式的值
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 ""
# 如果 '基础信息' 在 includes 中,则进行字段提取
if "基础信息" in includes:
base_info = combined_data.get("基础信息", {})
# 定义所需字段的映射关系,暂时不包含'联系人'和'联系电话'以及'招标项目地点'
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]
2024-10-15 20:57:58 +08:00
else:
2024-10-16 20:18:55 +08:00
extracted_info["招标项目地点"] = ""
# 特殊处理 '联系人' 和 '联系电话'
# 提取 '项目联系方式'
project_contact = get_nested(base_info, ["招标人/代理信息", "项目联系方式"], {})
# 提取 '招标人联系方式'
bidder_contact = get_nested(base_info, ["招标人/代理信息", "招标人联系方式"], {})
2024-10-15 20:57:58 +08:00
2024-10-16 20:18:55 +08:00
# 定义候选键列表,按优先级排序
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)
# 遍历原始字典的每一个键值对
for key, value in combined_data.items():
if key in includes:
if key == "基础信息":
# 已经处理 '基础信息',保留在处理后的数据中
processed_data[key] = value
else:
# 直接保留包含在 includes 列表中的键值对
processed_data[key] = value
else:
# 将不在 includes 列表中的键值对加入到 '其他' 分类中
processed_data["其他"][key] = value
2024-10-15 20:57:58 +08:00
2024-10-16 20:18:55 +08:00
# 如果 '其他' 分类没有任何内容,可以选择删除这个键
if not processed_data["其他"]:
del processed_data["其他"]
2024-10-15 20:57:58 +08:00
2024-10-16 20:18:55 +08:00
return processed_data, extracted_info
2024-10-10 21:03:02 +08:00
2024-10-16 20:18:55 +08:00
res1,res2=post_processing(combined_data,includes)
print(json.dumps(res2,ensure_ascii=False,indent=4))