12.25 解析优化

This commit is contained in:
zy123 2024-12-25 14:35:52 +08:00
parent e4bce38ad9
commit a26393d586
9 changed files with 120 additions and 70 deletions

View File

@ -75,6 +75,6 @@ def convert_file_to_markdown(file_path):
if __name__ == "__main__":
# file_path=r"C:\Users\Administrator\Desktop\fsdownload\e702f1e6-095d-443d-bb7d-ef2e42037cb1\ztbfile_procurement.pdf"
file_path=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\ztbfile_procurement.pdf"
file_path=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\3496bb36-c476-42f0-947e-3e39c295f8bc\ztbfile_evaluation_method.pdf"
res=convert_file_to_markdown(file_path)
print(res)

View File

@ -1,4 +1,5 @@
import json
import os
import re
import time
from collections import defaultdict
@ -115,7 +116,16 @@ def reorganize_data(input_dict, include=None):
reorganized["商务评分"][package] = categories["商务评分"]
return reorganized
# 格式要求:
# 请以 JSON 格式返回结果,最外层键名为 '技术评分'、'商务评分' 和 '投标报价评分'。在每大项下,用键值对表示具体评分项,键为具体的评审因素,若评审因素存在嵌套(表格中存在层级),请使用嵌套键值对表示,具体规则如下:
# 1. 如果评审因素存在嵌套,使用嵌套键值对表示:
# -主评审因素的键名后需附加括号表示该主因素下所有子因素总分例如产品技术响应8分
# -子评审因素作为主评审因素的内层键名
# 2. 如果评审因素不存在嵌套,那么键名就是该评审因素
# 3. 每个评审因素的最内层键值都是列表,列表中包含描述评分及要求的字典,字典需包含以下键:
# '评分':具体得分或定性指标(如 '合格制'),无评分时可删去'评分'键值对。
# '要求':说明评分标准。
# 4.若这三大项评分中存在额外信息(不属于某个评审因素,即该大项评分的整体要求),在该评分项内部新增键名为'备注',值为该要求。
def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
# 定义默认的评审结果字典
DEFAULT_EVALUATION_REVIEW = {
@ -144,15 +154,26 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
# 执行查询
return qianwen_long(file_id, query),file_id
def run_second_qeury(file_id):
print("获取评分项...")
# 执行 user_query 相关的逻辑
user_query_1 = (
"""
你是一个对招投标业务非常熟悉的专家根据该文档中的评标办法表格请你列出该文件的技术评分商务评分投标报价评分以及它们对应的具体评分要求请以JSON格式返回结果
格式要求
请以 JSON 格式返回结果最外层键名为 '技术评分''商务评分' '投标报价评分'在每大项下用键值对表示具体评分项键为具体的评审因素若评审因素存在嵌套表格中存在层级请使用嵌套键值对表示外层键名为主评审因素嵌套的子评审因素作为内层键名最内键值为列表列表中包含描述评分及要求的字典每个字典的键包括
'评分'具体得分或定性指标 '合格制'无评分时可删去'评分'键值对
'要求'说明评分标准
若这三大项评分中存在额外信息不属于某个评审因素即该大项评分的整体要求在该评分项内部新增键名为'备注'
1.总体结构
-JSON 的最外层包含三个键技术评分商务评分 投标报价评分
-每个大项如技术评分商务评分下包含具体的评分项评分项按以下规则表示
2.评分项表示规则
-层级嵌套规则
若评分因素存在嵌套关系主评分因素需附加括号括号中注明该主评分项的总分例如产品技术响应8子评分因素作为嵌套键列在主评分因素之下无需再附加括号表示评分
若评分因素不存在嵌套关系键名直接为评分因素无需附加括号表示总分
-评分项内容
-每个评分项最内层值都是一个列表列表中包含一个或多个描述评分标准的字典
-字典结构如下
评分可选具体得分 8若为定性指标合格制可标明合格制
要求详细描述评分标准及要求
3.备注信息
-若评分部分包含附加信息如大项评分的整体要求未直接归属于具体评分项需添加一个 备注 值为该附加信息
要求与指南
1. 请首先定位评分细则的表格不要回答有关资格审查的内容也不要从评标办法正文中提取回答
@ -171,7 +192,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
{
"一包": {
"技术评分": {
"实施方案":{
"实施方案(16分)":{
"总体实施方案":[
{
"评分":8,
@ -185,29 +206,29 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
}
]
},
"设计创意": [
{
"评分": "10分",
"要求": "主题突出形式多样内容与形式完美统一得10分其他酌情打分"
}
],
"备注": "技术标采用暗标形式,暗标不得出现投标人名称、人员姓名。"
},
"商务评分": {
"主要监理岗位的职责": [
{
"评分": "4分",
"要求": "1、总监理工程师的职责全面、清晰、合理得 1.2-2分一般的1.2分。2、其他主要监理人员及岗位的职责全面、清晰、合理得 1.2-2分一般的 1.2分。"
"要求": "1、总监理工程师的职责全面、清晰、合理得 2 分;一般的 1 分。2、其他主要监理人员及岗位的职责全面、清晰、合理得 2 分;一般的 1 分。"
}
],
"备注": "技术标采用定性方式评审的, “不合格”仅限于投标文件出现违反国家强制性条文标准的情况,否则技术标评审结论为“合格” 。"
},
"商务评分": {
"控制系统内主板": [
{
"评分": "10分",
"要求": "所投电梯控制系统内主板为制造商原厂原品牌制造生产且为进口部件得 10分。提供进口部件报关单及原产地证明扫描件加盖公章否则不得分"
}
],
"制造商技术实力": [
"制造商实力": [
{
"评分": "3分",
"要求": "一级证书得3分二级证书得1分其他不得分"
},
{
"评分": "2分",
"要求": "行业销量排名连续前 2 名,得 2 分,第 4-6 名得 0.5 分,其他不得分"
"要求": "行业销量排名连续前 2 名,得 2 分,第 3-6 名得 0.5 分,其他不得分"
}
]
},
@ -227,10 +248,20 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
"""
你是一个对招投标业务非常熟悉的专家根据该文档中的评标办法表格请你列出该文件的技术评分商务评分投标报价评分以及它们对应的具体评分要求请以JSON格式返回结果
格式要求
请以 JSON 格式返回结果最外层键名为 '技术评分''商务评分' '投标报价评分'在每大项下用键值对表示具体评分项键为具体的评审因素若评审因素存在嵌套表格中存在层级请使用嵌套键值对表示外层键名为主评审因素嵌套的子评审因素作为内层键名最内键值为列表列表中包含描述评分及要求的字典每个字典的键包括
'评分'具体得分或定性指标 '合格制'无评分时可删去'评分'键值对
'要求'说明评分标准
若这三大项评分中存在额外信息不属于某个评审因素即该大项评分的整体要求在该评分项内部新增键名为'备注'值为该要求
1.总体结构
-JSON 的最外层包含三个键技术评分商务评分 投标报价评分
-每个大项如技术评分商务评分下包含具体的评分项评分项按以下规则表示
2.评分项表示规则
-层级嵌套规则
若评分因素存在嵌套关系主评分因素需附加括号括号中注明该主评分项的总分例如产品技术响应8子评分因素作为嵌套键列在主评分因素之下无需再附加括号表示评分
若评分因素不存在嵌套关系键名直接为评分因素无需附加括号表示总分
-评分项内容
-每个评分项最内层值都是一个列表列表中包含一个或多个描述评分标准的字典
-字典结构如下
评分可选具体得分 8若为定性指标合格制可标明合格制
要求详细描述评分标准及要求
3.备注信息
-若评分部分包含附加信息如大项评分的整体要求未直接归属于具体评分项需添加一个 备注 值为该附加信息
要求与指南
1. 请首先定位评分细则的表格不要回答有关资格审查的内容也不要从评标办法正文中提取回答
@ -250,29 +281,43 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
{
"一包": {
"技术评分": {
"产品技术响应8分":{
"常规参数符合":[
{
"评分":"4分",
"要求":"未标★项为常规参数每条负偏离扣1分本项满分4分。"
}
],
"摄影机":[
{
"评分":"4分",
"要求":"支持1路H.265编码、25fps、32MP分辨率的拼接摄像机视频实时预览功能满分4分"
}
]
},
"实施方案": [
{
"评分": "10分",
"要求": "实施方案清晰、完整、合理、可行的得 10 分。"
}
],
"备注": "注:若不满足“与公安部、省公安厅、随州市公安局高清视频会议系统无缝对接互联互通”的要求,则本项技术部分不得分。"
},
"商务评分": {
"主要监理岗位的职责": [
{
"评分": "4分",
"要求": "1、总监理工程师的职责全面、清晰、合理得 1.2-2分一般的1.2分。2、其他主要监理人员及岗位的职责全面、清晰、合理得 1.2-2分一般的 1.2分。"
"要求": "1、总监理工程师的职责全面、清晰、合理得 2 分;一般的 1 分。2、其他主要监理人员及岗位的职责全面、清晰、合理得 2 分;一般的 1 分。"
}
],
"备注": "若不满足“与公安部、省公安厅、随州市公安局高清视频会议系统无缝对接互联互通”的要求则本项技术部分50分不得分。"
},
"商务评分": {
"控制系统内主板": [
{
"评分": "10分",
"要求": "所投电梯控制系统内主板为制造商原厂原品牌制造生产且为进口部件得 10分。提供进口部件报关单及原产地证明扫描件加盖公章否则不得分"
}
],
"制造商技术实力": [
"制造商实力": [
{
"评分": "3分",
"要求": "一级证书得3分二级证书得1分其他不得分"
},
{
"评分": "2分",
"要求": "行业销量排名连续前 2 名,得 2 分,第 4-6 名得 0.5 分,其他不得分"
"要求": "行业销量排名连续前 2 名,得 2 分,第 3-6 名得 0.5 分,其他不得分"
}
]
},
@ -325,23 +370,32 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
updated_jsons = combine_technical_and_business(result_data, target_values)
final_res = reorganize_data(updated_jsons, include) # 重新组织字典,尤其是分包的情况
return final_res
try:
judge_res,file_id = run_first_query(evaluation_method_path)
# 检查 judge_res 的内容
def get_default_result():
return {
'技术评分': '本招标文件没有技术评分!',
'商务评分': '本招标文件没有商务评分!'
}
# 如果 judge_res 包含 '是',直接运行第二步查询
if '' in judge_res:
# 执行 user_query 相关的逻辑
return run_second_qeury(file_id)
else:
judge_res,file_id=run_first_query(invalid_path) #调用invalid_path看看有没有评分项
# 标准化路径,避免多种表示形式造成的误判
eval_path = os.path.abspath(evaluation_method_path)
invalid_eval_path = os.path.abspath(invalid_path)
# 判断路径是否一致
if eval_path == invalid_eval_path:
# 如果路径一致,直接返回默认结果
return get_default_result()
# 路径不一致,尝试运行第一次查询
judge_res, file_id = run_first_query(invalid_path)
# 如果 judge_res 包含 '是',运行第二步查询
if '' in judge_res:
# 执行 user_query 相关的逻辑
return run_second_qeury(file_id)
else:
# 如果 judge 是 False直接返回默认的技术标和商务标的结构
result_data = {}
result_data['技术评分'] = '本招标文件没有技术评分!'
result_data['商务评分'] = '本招标文件没有商务评分!'
return result_data
# 默认返回结果
return get_default_result()
except Exception as e:
print(f"Error in combine_evaluation_standards: {e}")
# 在出错时返回默认的包含空字符串的字典
@ -350,13 +404,13 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
if __name__ == "__main__":
start_time=time.time()
# truncate_file=r"C:\Users\Administrator\Desktop\招标文件-采购类\tmp2\2024-新疆-塔城地区公安局食药环分局快检实验室项目_evaluation_method.pdf"
evaluation_method_path = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\be901ea0-adc9-47b8-9ada-5c3bc0dd9434\ztbfile_evaluation_method.pdf'
evaluation_method_path = r'C:\Users\Administrator\Desktop\招标文件\招标test文件夹\招标04.pdf'
invalid_path=r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\be901ea0-adc9-47b8-9ada-5c3bc0dd9434\ztbfile.docx'
# 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"
res = combine_evaluation_standards(evaluation_method_path,invalid_path,2)
res = combine_evaluation_standards(evaluation_method_path,invalid_path,1)
print(json.dumps(res, ensure_ascii=False, indent=4))
end_time=time.time()
print("elapsed time:"+str(end_time-start_time))

View File

@ -147,7 +147,7 @@ def get_invalid_file(file_path, output_folder, common_header,begin_page):
# 定义结束模式
end_patterns = [
regex.compile(
r'第[一二三四五六七八九十]+\s*合同|[:]清标报告',
r'第[一二三四五六七八九十]+(?:章|部分).*?合同|[:]清标报告',
regex.MULTILINE
),
regex.compile(

View File

@ -299,6 +299,7 @@ def extract_between_sections(data, target_values):
section_pattern = re.compile(r'^[一二三四五六七八九十]+$') # 匹配 "一", "二", "三" 等大标题
current_block = {}
file_pattern = re.compile(r'\s*件')
# 遍历所有键值对
for key, value in data.items():
# 只匹配形如 "一": "竞争性磋商响应文件" 的章节标题
@ -312,7 +313,7 @@ def extract_between_sections(data, target_values):
target_found = False
# 检查当前标题是否包含 target_values 中的任意关键词
if any(tv in value for tv in target_values):
if any(tv in value for tv in target_values) and not file_pattern.search(value):
target_found = True # 找到了目标章节,开始捕获后续内容
current_section_title = value # 保存章节标题内容

View File

@ -1,6 +1,4 @@
import concurrent.futures
import os
from flask_app.general.通义千问long import qianwen_long, upload_file

View File

@ -90,7 +90,7 @@ def extract_from_notice(merged_baseinfo_path, clause_path, type):
# 映射 type 到 target_values
type_target_map = {
1: ["投标", "投标文件", "响应文件"],
2: ["开标", "评标", "定标", "评审", "成交", "合同", "磋商程序", "中标", "程序", "步骤"],
2: ["开标", "评标", "定标", "评审", "成交", "合同", "磋商","谈判","中标", "程序", "步骤"],
3: ["重新招标、不再招标和终止招标", "重新招标", "重新采购", "不再招标", "不再采购", "终止招标", "终止采购"],
4: ["评标"] # 测试
}

View File

@ -94,15 +94,12 @@ def extract_pages(pdf_path, output_folder, begin_pattern, begin_page, end_patter
def get_patterns_for_procurement():
# begin_pattern = regex.compile(
# r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务|技术).*?要求|^第[一二三四五六七八九十1-9]+(?:章|部分).*(?:采购|需求).*',
# regex.MULTILINE)
begin_pattern = regex.compile(
r'(?<!见\s*)(?<!与\s*)(?<!"\s*)(?<!“\s*)(?<!”\s*)'
r'第[一二三四五六七八九十1-9]+(?:章|部分)\s*' # 匹配“第X章”或“第X部分”
r'[\u4e00-\u9fff、()]*?' # 匹配允许的字符
r'(?:(?:服务|项目|商务|技术)[\u4e00-\u9fff、()]*?要求[\u4e00-\u9fff、()]*?\s*$|' # 匹配“服务”、“项目”、“商务”或“技术”后跟“要求”
r'(?:采购|需求)[\u4e00-\u9fff、()]*?)\s*$', # 或者匹配“采购”或“需求”
r'(?:(?:服务|项目|商务|技术|供货)[\u4e00-\u9fff、()]*?要求[\u4e00-\u9fff、()]*?\s*$|' # 匹配“服务”、“项目”、“商务”或“技术”后跟“要求”
r'(?:采购(?:内容|要求|需求))[\u4e00-\u9fff、()]*?)\s*$', # 或者匹配“采购”或“需求”
regex.MULTILINE
)
end_pattern = regex.compile(r'(?<!见\s*)(?<!与\s*)(?<!"\s*)(?<!“\s*)(?<!”\s*)第[一二三四五六七八九1-9]+(?:章|部分)\s*[\u4e00-\u9fff、()]+\s*$', regex.MULTILINE)
@ -522,8 +519,8 @@ def truncate_pdf_main_goods(input_path, output_folder, selection,logger, output_
local_output_suffix = "tobidders_notice"
elif selection == 5:
begin_pattern = regex.compile(
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务|技术).*?要求|'
r'^第[一二三四五六七八九十百千]+(?:章|部分)(?!.*说明).*(?:采购内容|采购要求|需求).*'
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:服务|项目|商务|技术|供货).*?要求|'
r'^第[一二三四五六七八九十百千]+(?:章|部分)(?!.*说明).*(?:采购(?:内容|要求|需求)).*'
)
end_pattern = regex.compile(
r'^第[一二三四五六七八九十百千]+(?:章|部分)\s*[\u4e00-\u9fff]+'
@ -611,9 +608,9 @@ if __name__ == "__main__":
# pdf_path = r"C:\Users\Administrator\Desktop\招标文件-采购类\2024-贵州-贵州医科大学附属医院导视系统零星制作安装项目.pdf"
# pdf_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles"
# input_path = r"C:\Users\Administrator\Desktop\货物标\zbfiles\2-招标文件(广水市教育局封闭管理).pdf"
pdf_path=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\ztbfile.pdf"
output_folder = r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\tmp"
pdf_path=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\1414cb9c-7bf4-401c-8761-2acde151b9c2\ztbfile.pdf"
output_folder = r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\1414cb9c-7bf4-401c-8761-2acde151b9c2\tmp"
# output_folder = r"C:\Users\Administrator\Desktop\new招标文件\output2"
selection = 4 # 例如1 - 公告, 2 - 评标办法, 3 - 资格审查后缀有qualification1或qualification2与评标办法一致 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求
selection = 6 # 例如1 - 公告, 2 - 评标办法, 3 - 资格审查后缀有qualification1或qualification2与评标办法一致 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求
generated_files = truncate_pdf_main_goods(pdf_path, output_folder, selection,logger)
print(generated_files)

View File

@ -48,7 +48,7 @@ def extract_from_notice(merged_baseinfo_path, clause_path, type):
# 映射 type 到 target_values
type_target_map = {
1: ["投标文件", "响应文件", "响应性文件"],
2: ["开标", "评标", "定标","评审","成交","合同","磋商程序", "中标", "程序", "步骤"],
2: ["开标", "评标", "定标","评审","成交","合同","磋商","谈判", "中标", "程序", "步骤"],
3: ["重新招标、不再招标和终止招标", "重新招标", "重新采购", "不再招标", "不再采购", "终止招标", "终止采购"],
4: ["评标"] # 测试
}
@ -88,11 +88,11 @@ def extract_from_notice(merged_baseinfo_path, clause_path, type):
#TODO:可以通过判断格式来看是否需要调用GPT 1.1 2.1....
if __name__ == "__main__":
clause_path = r'D:\flask_project\flask_app\static\output\output1\ce279982-aeeb-4f08-ab39-df6ee2732eae\clause1.json'
clause_path = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\tmp\clause1.json'
merged_baseinfo_path=r"D:\flask_project\flask_app\static\output\output1\ce279982-aeeb-4f08-ab39-df6ee2732eae\ztbfile.pdf"
# file_path = 'D:\\flask_project\\flask_app\\static\\output\\fee18877-0c60-4c28-911f-9a5f7d1325a7\\clause1.json'
try:
res = extract_from_notice(merged_baseinfo_path,clause_path, 3) # 可以改变此处的 type 参数测试不同的场景
res = extract_from_notice(merged_baseinfo_path,clause_path, 2) # 可以改变此处的 type 参数测试不同的场景
res2=json.dumps(res,ensure_ascii=False,indent=4)
print(res2)
except ValueError as e:

View File

@ -178,11 +178,11 @@ def process_folder(input_folder, output_folder):
#TODO:招标文件111_tobidders_notice_part2.pdf 陕西省公安厅交通警察总队高速公路交通安全智能感知巡查系统项目(1)_tobidders_notice_part2.pdf 唐山市公安交通警察支队机动车查验机构视频存储回放系统竞争性谈判-招标文件正文(1)_tobidders_notice_part1.pdf
#TODO:2024-陕西-陕西省某单位2024年执勤化妆服采购项目.pdf
if __name__ == "__main__":
file_path = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\3496bb36-c476-42f0-947e-3e39c295f8bc\ztbfile_tobidders_notice_part2.pdf'
file_path = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\tmp\ztbfile_tobidders_notice_part2.pdf'
# file_path=r'C:\Users\Administrator\Desktop\招标文件-采购类\all\2024-陕西-陕西省某单位2024年执勤化妆服采购项目_tobidders_notice_part2.pdf'
# file_path=r'C:\Users\Administrator\Desktop\货物标\output4\磋商文件_tobidders_notice_part2.pdf'
# file_path = 'C:\\Users\\Administrator\\Desktop\\货物标\\output4\\6.2定版视频会议磋商文件_tobidders_notice_part2.pdf'
output_folder = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\3496bb36-c476-42f0-947e-3e39c295f8bc\tmp'
output_folder = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\tmp'
try:
output_path = convert_clause_to_json(file_path,output_folder,1)
print(f"Final JSON result saved to: {output_path}")