1.7 商务要求标题带星保留+评分项手动计算总分

This commit is contained in:
zy123 2025-01-07 17:35:11 +08:00
parent 615c8d6898
commit 4d5dc9ea4e
13 changed files with 171 additions and 102 deletions

View File

@ -4,10 +4,10 @@ import re
import time
from collections import defaultdict
from flask_app.general.doubao import get_total_tokens, read_txt_to_string, doubao_model
from flask_app.general.doubao import read_txt_to_string
from flask_app.general.file2markdown import convert_file_to_markdown
from flask_app.general.format_change import get_pdf_page_count, pdf2docx
from flask_app.general.json_utils import clean_json_string, extract_content_from_json
from flask_app.general.json_utils import extract_content_from_json
from flask_app.general.model_continue_query import process_continue_answers
from flask_app.general.通义千问long import upload_file, qianwen_long, qianwen_plus
@ -23,51 +23,49 @@ def remove_unknown_scores(data):
return [remove_unknown_scores(item) for item in data]
else:
return data
def combine_technical_and_business(data, target_values):
# target_values = ['技术', '设计', '实施']
def combine_technical_and_business(data):
data = remove_unknown_scores(data)
extracted_data = {} # 根级别存储所有数据
technical_found = False
business_found = False
extracted_data = {
'技术评分': {
'技术评分': {} # 初始化技术评分
},
'商务评分': {
'商务评分': {}, # 初始化商务评分
'投标报价评分': {} # 初始化投标报价评分
# '其他评分' 将在需要时动态添加
}
}
def extract_nested(data, parent_key='', is_technical=False, is_business=False):
nonlocal technical_found, business_found
def extract_nested(data):
if isinstance(data, dict):
for key, value in data.items():
current_key = f"{parent_key}.{key}" if parent_key else key
# 区分 '技术评分'
if key == '技术评分':
total_score=compute_total_score({key:value})
extracted_data['技术评分']['技术评分'] = value
# 匹配到后,不再递归处理其子项
continue
# 检查是否为技术标的内容
if any(target in key for target in target_values):
if not is_technical:
if '技术评分' not in extracted_data:
extracted_data['技术评分'] = {} # 初始化 '技术评分' 字典
extracted_data['技术评分'][key] = value
technical_found = True
continue
# 区分 '商务评分'
elif key == '商务评分':
extracted_data['商务评分']['商务评分'] = value
# 匹配到后,不再递归处理其子项
continue
# 默认其他所有内容都归为商务标
# 区分 '投标报价评分'
elif key == '投标报价评分':
extracted_data['商务评分']['投标报价评分'] = value
# 匹配到后,不再递归处理其子项
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)
if '其他评分' not in extracted_data['商务评分']:
extracted_data['商务评分']['其他评分'] = {}
extracted_data['商务评分']['其他评分'][key] = value
continue
extract_nested(data)
if not technical_found:
extracted_data['技术评分'] = ''
if not business_found:
extracted_data['商务评分'] = ''
return extracted_data
# 防止外键只有一个'一包'的情况
@ -83,6 +81,72 @@ def process_data_based_on_key(data):
# 如果条件不满足,则返回原始字典
return data
def compute_total_score(data):
"""
计算传入字典的总分
规则
- 输入字典只有一个外层键
- 遍历该外层键的所有子键
- 如果子键名中包含 '(XX分)' 'XX分'提取 XX 并累加到总分中不再处理其子项
- 如果子键名中不包含这样的分数遍历其子项查找键名为 '评分' 的键提取分数并累加
- '评分' 的值可以是 'XX分' 或整数
- 如果没有找到 '评分' 则该项分数为 0
"""
total = 0
# 确保输入数据为字典且只有一个外层键
if not isinstance(data, dict) or len(data) != 1:
raise ValueError("输入数据必须是一个只有一个外层键的字典。")
# 获取唯一的外层键和值
outer_key, outer_value = next(iter(data.items()))
# 更新后的正则表达式,匹配中英文括号中的分数,如 '(24分)' 或 '24分'
score_pattern = re.compile(r'[(](\d+)分[)]')
def process_node(node):
nonlocal total
if isinstance(node, dict):
for key, value in node.items():
# 检查键名中是否包含 '(XX分)' 或 'XX分'
match = score_pattern.search(key)
if match:
score = int(match.group(1))
total += score
# 匹配到后,不再递归处理其子项
continue
elif key == '评分':
if isinstance(value, str):
# 提取 '评分' 键的值中的数字,如 '20分'
match_score = re.match(r'(\d+)分', value)
if match_score:
score = int(match_score.group(1))
total += score
else:
# 如果 '评分' 值不符合格式,默认加 0
total += 0
elif isinstance(value, int):
# 如果 '评分' 键的值是整数,直接累加
total += value
else:
# 如果 '评分' 键的值既不是字符串也不是整数,默认加 0
total += 0
else:
# 如果键名不包含分数,递归处理其子项
process_node(value)
elif isinstance(node, list):
for item in node:
process_node(item)
else:
# 如果是其他类型的数据,忽略
pass
# 开始递归处理外层键的值
process_node(outer_value)
return total
def reorganize_data(input_dict, include=None):
"""
重组输入字典技术评分商务评分提升为最外层键
@ -167,7 +231,6 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
格式要求
1.总体结构
-JSON 的最外层包含三个键技术评分商务评分 投标报价评分
-最外层三个键名后需附加括号括号中注明该大项评分的总分'技术评分(18分)'若无具体评分则无需添加该括号
-每个大项如技术评分商务评分下包含具体的评分项评分项按以下规则表示
2.评分项表示规则
-层级嵌套规则
@ -179,7 +242,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
-字典个数
默认为1个字典若某评分因素包括多个评分标准多个表格单元格可以用多个并列字典表示
-字典结构如下
评分该评分标准的总分 8不能是一个范围数字如0-8若为定性指标合格制可标明相应的定性指标无评分时可删去'评分'键值对
评分该评分标准的总分 8字符串类型不能是一个范围数字如0-8若为定性指标合格制可标明相应的定性指标无评分时可删去'评分'键值对
要求说明评分标准或要求
-禁止情况
禁止将同个单元格内的内容拆分至多个字典中禁止遗漏单元格内任何信息包括注的内容
@ -208,7 +271,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
以下为示例输出仅供格式参考
{
"一包": {
"技术评分(26分)": {
"技术评分": {
"实施方案(16分)":{
"总体实施方案":[
{
@ -231,7 +294,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
],
"备注": "技术标采用暗标形式,暗标不得出现投标人名称、人员姓名。"
},
"商务评分(9分)": {
"商务评分": {
"主要监理岗位的职责": [
{
"评分": "4分",
@ -267,7 +330,6 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
格式要求
1.总体结构
-JSON 的最外层包含三个键'技术评分''商务评分' '投标报价评分'
-最外层三个键名后需附加括号括号中注明该大项评分的总分'技术评分(18分)'若无具体评分则无需添加该括号
-每个大项如技术评分商务评分下包含具体的评分项评分项按以下规则表示
2.评分项表示规则
-层级嵌套规则
@ -279,7 +341,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
-字典个数
默认为1个字典若某评分因素包括多个评分标准多个表格单元格可以用多个并列字典表示
-字典结构如下
评分该评分标准的总分 8不能是一个范围数字如0-8若为定性指标合格制可标明相应的定性指标无评分时可删去'评分'键值对
评分该评分标准的总分 8字符串类型不能是一个范围数字如0-8若为定性指标合格制可标明相应的定性指标无评分时可删去'评分'键值对
要求说明评分标准或要求
-禁止情况
禁止将同个单元格内的内容拆分至多个字典中禁止遗漏单元格内任何信息包括注的内容
@ -308,7 +370,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
以下为示例输出仅供格式参考
{
"一包": {
"技术评分(18分)": {
"技术评分": {
"产品技术响应(8分)":{
"常规参数符合":[
{
@ -331,7 +393,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
],
"备注": "注:若不满足“与公安部、省公安厅、随州市公安局高清视频会议系统无缝对接互联互通”的要求,则本项技术部分不得分。"
},
"商务评分(9分)": {
"商务评分": {
"主要监理岗位的职责": [
{
"评分": "4分",
@ -390,9 +452,7 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
temp_final.update(continued_results)
result_data = process_data_based_on_key(temp_final) # 处理不知名外键的情况
include = ['一包', '二包', '三包', '四包', '五包']
target_values = ['技术', '设计', '实施']
updated_jsons = {}
# 检查是否有外层键匹配 include 列表
if any(key for key in result_data if
any(included in key for included in include)): # 检查result_data中的任何键是否包含include列表中的任意一个项。
@ -400,11 +460,10 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
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) # 对于分包,单独对分包内的'技术评分''商务评分'作处理
else:
# 没有匹配的项,对整个字典运行
updated_jsons = combine_technical_and_business(result_data, target_values)
updated_jsons = combine_technical_and_business(result_data)
final_res = reorganize_data(updated_jsons, include) # 重新组织字典,尤其是分包的情况
return final_res
@ -450,16 +509,19 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
#目前评分这块如果表格过长会有问题可以考虑textin+doubao小于20页用text>20页转word->qianwen-long
#TODO:代码计算总分,商务评分修改
#TODO:废标项,增加对表格的提取+排除重复项
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\招标文件\招标04_evaluation_method.pdf'
invalid_path=r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\1414cb9c-7bf4-401c-8761-2acde151b9c2\ztbfile.docx'
evaluation_method_path = r'D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\invalid_del.docx'
invalid_path=r'D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\invalid_del.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,1)
res = combine_evaluation_standards(evaluation_method_path,invalid_path,2)
print(json.dumps(res, ensure_ascii=False, indent=4))
end_time=time.time()
print("elapsed time:"+str(end_time-start_time))

View File

@ -151,11 +151,11 @@ def get_invalid_file(file_path, output_folder, common_header,begin_page):
regex.MULTILINE
),
regex.compile(
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:响应|投标).*?格式.*',
r'^第[一二三四五六七八九十百千]+(?:章|部分).*?(?:响应|投标|应答).*?格式.*',
regex.MULTILINE
),
regex.compile(
r"\s*(投标文件|响应文件|响应性文件)(?:的)?格式\s*",
r"\s*(投标文件|响应文件|响应性文件|应答文件)(?:的)?格式\s*",
regex.MULTILINE
)
]

View File

@ -4,7 +4,8 @@ import re
import regex
import time
from concurrent.futures import ThreadPoolExecutor
from flask_app.general.doubao import doubao_model, generate_full_user_query
from flask_app.general.doubao import generate_full_user_query
from flask_app.general.通义千问long import qianwen_plus
from flask_app.general.通用功能函数 import process_string_list
from collections import OrderedDict
from docx import Document
@ -206,9 +207,6 @@ def preprocess_paragraphs(paragraphs):
continue
else:
if flag:
# 当前段落不以数字序号开头,且 flag 为 True
if "供应商公章" in current_text:
print("yes")
if not list_item_pattern.match(current_text):
if processed:
# **新增逻辑开始**
@ -220,8 +218,8 @@ def preprocess_paragraphs(paragraphs):
pattern_numeric_header_fallback.match(next_non_empty_text)
)
if is_next_numbered:
# 只有在下一个段落以数字序号开头时,才将当前段落追加到上一个段落
if is_next_numbered and len(processed[-1]) > 30:
# 只有在下一个段落以数字序号开头且上一个段落长度大于30时,才将当前段落追加到上一个段落
processed[-1] = processed[-1] + ' ' + current_text
else:
# 否则,不追加,而是作为新的段落添加
@ -747,7 +745,7 @@ def handle_query(file_path, user_query, output_file, result_key, keywords):
# 生成用户查询
user_query = generate_full_user_query(output_file, user_query)
model_ans = doubao_model(user_query) # 豆包模型返回结果
model_ans = qianwen_plus(user_query) # 豆包模型返回结果
# file_id = upload_file(output_file)
# model_ans = qianwen_long(file_id, user_query)
num_list = process_string_list(model_ans) # 处理模型返回的序号
@ -806,7 +804,7 @@ def combine_find_invalid(invalid_docpath, output_dir):
要求与指南
文本中可能存在无关的信息请准确筛选符合条件的信息并将符合条件的信息的序号返回
输出格式
[x, x, x] 的形式返回x 为符合条件的信息的序号
[x, x, x] 的形式返回x 为符合条件的信息的序号为自然数
如果文本中没有符合条件的信息请返回 []
特殊情况
如果某序号的内容明显分为几部分且一部分内容符合筛选条件但其他部分明显是无关内容请返回符合部分的字符串内容代替序号
@ -825,7 +823,7 @@ def combine_find_invalid(invalid_docpath, output_dir):
要求与指南
文本中可能存在无关的信息请准确筛选符合条件的信息并将符合条件的信息的序号返回
输出格式
返回结果以 [x, x, x] 的形式其中 x 为符合条件的信息的序号
返回结果以 [x, x, x] 的形式其中 x 为符合条件的信息的序号为自然数
如果文本中没有任何符合条件的废标情况请返回 []
示例输出,仅供格式参考
[1,3,4,6]
@ -835,16 +833,21 @@ def combine_find_invalid(invalid_docpath, output_dir):
"废标项"
),
(
r'\s*得(?!\s*分)|禁\s*止\s*投\s*标',
"""以下是从招标文件中摘取的内容,文本中序号分明,文本内的条款以'...............'分割。每条条款规定了各方不得存在的情形。请根据以下要求进行筛选:
r'\s*得(?!\s*(分|力))|禁\s*止\s*投\s*标',
"""以下是从招标文件中摘取的内容,文本中序号分明,文本内的条款以'...............'分割。条款规定了各方不得存在的情形。请根据以下要求进行筛选:
**投标相关主体与非投标相关主体的定义**
投标相关主体包括但不限于投标人中标人供应商联合体投标各方响应人应答人或其他描述投标方的词语
非投标相关主体包括但不限于招标人采购人评标委员会或其他描述非投标方的词语
**筛选要求**
1. **仅包含**明确描述投标主体禁止情形的条款不包含笼统或未具体说明情形的条款若条款内容诸如'投标人不得存在的其他关联情形'这样笼统的内容而未说明具体的情形则无需添加这条条款
2. **仅筛选**出主语为投标人中标人供应商联合体投标各方或其他投标相关主体的条款****描述的情形针对投标相关主体的条款
3. **排除**主语为招标人采购人评标委员会或其他非投标相关主体的条款
4. **特殊情况**如果条款中包含磋商小组且在语境中磋商小组指代或包含投标方则应将其考虑在内否则排除该条款
1. **仅筛选**明确描述投标相关主体禁止情形或不得存在的情形的条款不包含笼统或未具体说明情形的条款例如
若条款内容包含'投标人不得存在的其他关联情形'这样的笼统描述而未说明具体的情形则无需添加该条款
2. **排除**仅描述非投标相关主体行为限制或禁止情形的条款例如招标人不得泄露信息评标委员会不得收受贿赂则无需返回
3. 若条款同时描述了对投标相关主体与非投标相关主体的行为限制禁止情形也需返回
4. **特殊情况**如果条款中包含磋商小组各方等既能指代投标相关主体又能指代非投标相关主体的词汇
若在语境中其指代或包含投标相关主体则应将其考虑在内否则排除该条款
**输出格式**
返回结果以 [x, x, x] 的形式其中 x 为符合条件的条款的序号
返回结果以 [x, x, x] 的形式其中 x 为符合条件的条款的序号为自然数
如果没有符合条件的条款返回 `[]`
**示例**
- **符合条件**
@ -903,10 +906,10 @@ if __name__ == '__main__':
# doc_path = r'C:\Users\Administrator\Desktop\new招标文件\tmp\2024-贵州-贵州省罗甸县 2024 年度广州市协作资金龙坪镇、边阳镇产业路硬化建设项目.docx'
pdf_path = r'C:\Users\Administrator\Desktop\货物\test\磋商采购文件-恩施市森林火灾风险普查样品检测服务_invalid.pdf'
output_dir = r"C:\Users\Administrator\Desktop\货物\test"
output_dir = r"D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\tmp"
# invalid_added = insert_mark(pdf_path)
# invalid_added_docx = pdf2docx(invalid_added)
invalid_added_docx=r'C:\Users\Administrator\Desktop\货物\test\invalid_added.docx'
invalid_added_docx=r'D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\invalid_added.docx'
results = combine_find_invalid(invalid_added_docx, output_dir)
end_time = time.time()
print("Results:", json.dumps(results, ensure_ascii=False, indent=4))

View File

@ -86,8 +86,7 @@ def combine_evaluation_standards(evaluation_method):
evaluation_res = qianwen_long(file_id, user_query_2)
# print(evaluation_res)
target_values1 = ['技术标','技术部分','设计', '实施',"技术评分"]
update_json = combine_technical_and_business(clean_json_string(evaluation_res), target_values1)
update_json = combine_technical_and_business(clean_json_string(evaluation_res))
return update_json #商务标技术标整合
if __name__ == "__main__":
# evaluation_method="C:\\Users\\Administrator\\Desktop\\招标文件\\output2\\zbtest3_evaluation_method.pdf"

View File

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

View File

@ -12,7 +12,7 @@ from flask_app.工程标.投标人须知正文提取指定内容工程标 import
import concurrent.futures
from flask_app.工程标.基础信息整合工程标 import combine_basic_info
from flask_app.工程标.资格审查模块 import combine_review_standards
from flask_app.old_version.商务评分技术评分整合 import combine_evaluation_standards
from flask_app.old_version.商务评分技术评分整合old_version 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

@ -1,10 +1,8 @@
# -*- encoding:utf-8 -*-
import json
import re
import time
from collections import defaultdict
from flask_app.general.商务技术评分提取 import combine_technical_and_business, parse_json_with_duplicates, \
from flask_app.general.json_utils import clean_json_string
from flask_app.general.商务技术评分提取 import combine_technical_and_business, \
process_data_based_on_key, reorganize_data
from flask_app.general.通义千问long import upload_file, qianwen_long
@ -98,10 +96,9 @@ def combine_evaluation_standards(truncate_file):
evaluation_res = qianwen_long(file_id, user_query) #有些重复的键名只有qianwen_long_text能保留
# print(evaluation_res)
# 清理和处理响应
cleaned_evaluation_res = parse_json_with_duplicates(evaluation_res) #处理重复键名的情况
cleaned_evaluation_res = clean_json_string(evaluation_res) #处理重复键名的情况
result_data = process_data_based_on_key(cleaned_evaluation_res) #处理不知名外键的情况
include = ['一包', '二包', '三包', '四包', '五包']
target_values = ['技术', '设计', '实施']
updated_jsons = {}
# 检查是否有外层键匹配 include 列表
@ -110,10 +107,10 @@ def combine_evaluation_standards(truncate_file):
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) #对于分包,单独对分包内的'技术评分''商务评分'作处理
else:
# 没有匹配的项,对整个字典运行
updated_jsons = combine_technical_and_business(result_data, target_values)
updated_jsons = combine_technical_and_business(result_data)
final_res=reorganize_data(updated_jsons,include) #重新组织字典,尤其是分包的情况
return final_res
else:

View File

@ -275,7 +275,7 @@ def extract_business_deviation(busi_requirements_dict):
print("商务要求已更新!")
renamed_requirements = rename_outer_keys(updated_requirements)
business_requirements_string = json.dumps(renamed_requirements, ensure_ascii=False, indent=4)
print(business_requirements_string)
# print(business_requirements_string)
prompt_template1 = """以下文本是项目采购需求的商务要求部分,请帮我将信息重新组织,键名为'商务要求',键值为字符串列表,其中每个字符串为一条商务要求,保留三角▲、五角星★(若有),但是去除开头的序号(若有)。
**角色**
你是一个专业的招投标业务专家擅长从招标文件中总结商务要求的部分并逐条列出作为编写商务要求偏离表的前置准备
@ -283,7 +283,7 @@ def extract_business_deviation(busi_requirements_dict):
**要求与指南**
1. 每条内容需要有实际的含义要求不能光有标题性质的表述如'售后服务期限(质保期)及要求'
2. 你的回答内容需从所给文本中整理尽量不改变原文的表达除非以下要求与指南3.的特殊情况请勿擅自添加三角五角星
3. 若输入文本中存在嵌套键值对格式且键值本身语义完整且符合'商务要求'可直接将其添加至'商务要求'的键值中若键值字符串本身语义表达不完整可将键值对用冒号''拼接之后作为一条商务要求若键值字符串以或其他特殊符号开头将符号移至拼接后的开头例如'"★交货地点:采购人指定地点"'
3. 若输入文本中存在嵌套键值对格式且键值本身语义完整且符合'商务要求'可直接将其添加至'商务要求'的键值中若键值字符串本身语义表达不完整不明确可将键值对用冒号''拼接之后作为一条商务要求若键值字符串以或其他特殊符号开头将符号移至拼接后的开头例如'"★交货地点:采购人指定地点"'
4. 对于以三角或五角星或其他特殊符号开头的字符串
a. 如果该字符串仅为标题性质的表述且不具备实际商务要求的含义请根据语义关联性将其开头的三角或五角星添加到紧随其后的若干可为一内容之后形成完整的商务要求并确保整个内容连贯
默认在该字符串后面的一个字符串开头添加三角或五角星若有明确的序号或者语义表示了其后若干字符串之间的相关性那么可在这些字符串开头都添加三角或五角星作为若干商务要求

View File

@ -360,9 +360,9 @@ def truncate_pdf_main_engineering(input_path, output_folder, selection, logger,
is_secondary_match = (idx == 2)
begin_page = last_begin_index if last_begin_index != 0 else {
1: 0, # 公告
2: 10, # 评标
2: 5, # 评标
3: 5, # 资格
4: 3, # 前附表
4: 1, # 前附表
5: 0 # 无效标
}.get(selection, 0)
@ -443,12 +443,12 @@ if __name__ == "__main__":
logger = get_global_logger("123")
start_time = time.time()
# input_path = r"C:\Users\Administrator\Desktop\new招标文件\工程标"
pdf_path = r"C:\Users\Administrator\Desktop\工程\test\2022-广东-鹏华基金管理有限公司深圳深业上城办公室装修项目.pdf"
pdf_path=r"D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\ztbfile.pdf"
# pdf_path = r"C:\Users\Administrator\Desktop\招标文件\招标02.pdf"
# input_path=r"C:\Users\Administrator\Desktop\招标文件\招标test文件夹\zbtest8.pdf"
output_folder = r"C:\Users\Administrator\Desktop\fsdownload\305c1fea-e0bd-4135-955f-38fb46388166\tmp"
selection = 5 # 例如1 - 招标公告, 2 - 评标办法, 3 -资格审查条件 4-投标人须知前附表+正文 5-无效标
output_folder = r"D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\tmp"
selection = 4 # 例如1 - 招标公告, 2 - 评标办法, 3 -资格审查条件 4-投标人须知前附表+正文 5-无效标
generated_files = truncate_pdf_main_engineering(pdf_path, output_folder, selection, logger)
print(generated_files)
# print("生成的文件:", generated_files)

View File

@ -294,7 +294,7 @@ def generate_prompt(judge_res, full_text=None):
base_prompt = '''
任务你负责解析采购文件提取采购需求并以JSON格式返回不要遗漏该项目需要采购的货物设备或系统
输出格式
**输出格式**
1.JSON格式外层键名为需要采购的货物设备或系统名称(一级键)
2.层次关系用嵌套键值对表示:
-采购活动可能将目标划分为多个系统或货物若文档通过大标题或表格层次或序号标明这种归属关系请在JSON中以嵌套形式表示
@ -310,14 +310,17 @@ def generate_prompt(judge_res, full_text=None):
-若同一层级下存在名称相同但采购要求如型号参数功能不同的货物请在名称后添加编号以作区分防止出现重复键名默认情况下无需在名称后添加编号只有在名称相同时才需要添加编号编号规则'名称-编号'编号从1递增例子若同层级下存在两种名称相同但不同型号或参数的'交换机'那么键名分别是'交换机-1''交换机-2'如果名称不同如路由器和交换机则无需编号
4.最内层键值应为空列表[]
要求与指南
**特殊情况**
-如果文件中未明确说明需要采购的货物设备或系统请直接返回空字典 {{}}不要生成任何无关内容
**要求与指南**
1. 精准定位请运用文档理解能力定位文件中的采购需求部分
-若有采购清单请直接根据采购清单上的货物或系统名称给出结果若没有采购清单则从表格或文本中摘取采购信息
-注意采购目标通常在诸如'名称'且每个目标占据一个单元格你无需提取诸如'说明''规格''参数''描述'等其他列的内容即你不需要给出详细的采购要求更不要将这些单元格内的描述拆分作为其的子键你仅返回采购的货物或系统或模块名称
2. 采购目标采购种类通常有硬件如设备货物和软件如系统软件应用APP一次采购活动可以同时包含这两种类型
3. 软件类采购对于软件系统或应用采购若有多个系统且序号分明请不要遗漏若明确列出系统模块提取模块名称并作为系统的子键无需在模块下再细分功能
4. 完整性
-若采购的货物或系统或模块名称前存在三角,五角,注意是名称前而非具体的技术参数或采购要求前在返回名称时请保留前面的,,符号'★高清摄像机'
-若采购的货物或系统或模块名称前存在三角,五角,或其他特殊符号注意是名称前而非具体的技术参数或采购要求前在返回名称时请保留前面的,,符号'★高清摄像机'
-确保系统内的所有货物设备均被按层次提取对于有明确清单且按序号划分的采购需求,请勿遗漏每一个序号所代表的货物或设备或系统也不要添加未提及的内容
-若某货物或系统模块主要设备功能指标或类似标题下有详细参数说明但未在前面清单或表格中诸如'名称'的列中列出也需将该货物名添加到结果中
@ -350,6 +353,8 @@ def generate_prompt(judge_res, full_text=None):
"XX管理系统":[],
//其他系统
}}
示例输出3无明确的采购需求
{{}}
'''
if '' not in judge_res and full_text:
# 添加文件内容部分
@ -486,7 +491,7 @@ def get_technical_requirements(invalid_path,processed_filepath,model_type=1):
judge_res = doubao_model(judge_query)
if '' in judge_res or model_type == 2:
model_type = 2 # 使用qianwen-long+invalid_path
print("no!调用invalid_path")
print("processed_filepath中无采购需求!调用invalid_path")
if invalid_path.lower().endswith('.pdf'): # 确保上传的是docx upload中一定是docx但是get_deviation中可能上传的是pdf
invalid_path = pdf2docx(invalid_path)
file_id = upload_file(invalid_path)
@ -499,11 +504,14 @@ def get_technical_requirements(invalid_path,processed_filepath,model_type=1):
print(model_res)
cleaned_res = clean_json_string(model_res) #转字典
if not cleaned_res:
print("本项目没有采购需求!!!")
return {"采购需求": {}}
preprocessed_data=preprocess_data(cleaned_res) #确保最内层为[]
processed_data=truncate_system_keys(preprocessed_data) #限制深度
key_paths, grouped_paths, good_list, data_copy= generate_key_paths(processed_data) # 提取需要采购的货物清单 key_list交通监控视频子系统.高清视频抓拍像机 ... grouped_paths是同一系统下同时有'交换机-1'和'交换机-2',提取'交换机' 输出eg:{'交通标志.标志牌铝板', '交通信号灯.交换机'}
modified_data=rename_keys(data_copy)
user_query_template = """请根据货物标中采购要求部分的内容,告诉我\"{}\"的技术参数或采购要求是什么。请以 JSON 格式返回结果,键名为\"{}\",键值为一个列表,列表中包含若干描述\"{}\"的技术参数或采购要求或功能说明的字符串,请按原文内容回答,保留三角▲、五角★和序号,不可擅自增删内容,尤其是不可擅自添加序号。
user_query_template = """请根据货物标中采购要求部分的内容,告诉我\"{}\"的技术参数或采购要求是什么。请以 JSON 格式返回结果,键名为\"{}\",键值为一个列表,列表中包含若干描述\"{}\"的技术参数或采购要求或功能说明的字符串,请按原文内容回答,保留三角▲、五角★或其他特殊符号(若有)和序号(若有),不可擅自增删内容,尤其是不可擅自添加序号。
**重要限制**
- **仅提取技术参数或采购要求不包括任何商务要求**商务要求通常涉及供应商资格报价条款交货时间质保等内容是整体的要求而技术参数或采购要求则具体描述产品的技术规格功能性能指标等
- **商务要求的关键词示例**仅供参考不限于此报价交货合同资质认证服务保修期等如果内容包含上述关键词请仔细甄别是否属于商务要求
@ -538,7 +546,7 @@ def get_technical_requirements(invalid_path,processed_filepath,model_type=1):
{}
"""
user_query_template_two="""请根据货物标中采购要求部分的内容,告诉我\"{}\"的技术参数或采购要求是什么。由于该货物存在 {} 种不同的采购要求或技术参数,请逐一列出,并以 JSON 格式返回结果。请以'货物名-编号'区分多种型号,编号为从 1 开始的自然数,依次递增,即第一个键名为\"{}-1\";键值为一个列表,列表中包含若干描述\"{}\"的技术参数或采购要求或功能说明的字符串,请按原文内容回答,保留三角▲、五角★和序号(若有),不可擅自增删内容,尤其是不可擅自添加序号。
user_query_template_two="""请根据货物标中采购要求部分的内容,告诉我\"{}\"的技术参数或采购要求是什么。由于该货物存在 {} 种不同的采购要求或技术参数,请逐一列出,并以 JSON 格式返回结果。请以'货物名-编号'区分多种型号,编号为从 1 开始的自然数,依次递增,即第一个键名为\"{}-1\";键值为一个列表,列表中包含若干描述\"{}\"的技术参数或采购要求或功能说明的字符串,请按原文内容回答,保留三角▲、五角★或其他特殊符号(若有)和序号(若有),不可擅自增删内容,尤其是不可擅自添加序号。
要求与指南
1. 你的键值应该全面不要遗漏
@ -660,11 +668,11 @@ if __name__ == "__main__":
# invalid_path="D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89\\ztbfile.pdf"
# file_id = upload_file(truncate_file)
truncate_file=r'C:\Users\Administrator\Desktop\new招标文件\output5\广水市公安局音视频监控系统设备采购项目_procurement.pdf'
invalid_path=r"D:\flask_project\flask_app\static\output\output1\000aac0d-4aa4-4bc3-a9f9-76ff82ec2470\invalid_added.docx"
invalid_path=r"D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\invalid_del.docx"
# file_id=upload_file(truncate_file)
# processed_filepath = convert_file_to_markdown(truncate_file)
processed_filepath=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\baada43d-24f6-459d-8a81-219d130f20da\extract1.txt"
res=get_technical_requirements(invalid_path,processed_filepath)
processed_filepath=r"D:\flask_project\flask_app\static\output\output1\f91db70d-8d96-44a5-b840-27d2f1ecbe95\extract1.txt"
res=get_technical_requirements(invalid_path,processed_filepath,1)
json_string = json.dumps(res, ensure_ascii=False, indent=4)
print(json_string)
# # input_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\output1"