1.22 解决了无效标废标txt和all_text1由于去重而不一致的bug

解决了process_string_list可能返回字符串列表的bug
This commit is contained in:
zy123 2025-01-22 14:18:28 +08:00
parent 6e20f853f5
commit 800326d827
2 changed files with 93 additions and 81 deletions

View File

@ -401,7 +401,8 @@ def split_cell_text(text):
r'(?<![+\-×÷*/.\A-Za-z]\s*|\d)(?=\d+[、.](?!\d|(?:\s*[号条款节章项例页段部步点年月日时分秒个元千万台份家])))|' # 数字后直接跟顿号、点号时分割,且点号后不跟数字 eg:'1.' r'(?<![+\-×÷*/.\A-Za-z]\s*|\d)(?=\d+[、.](?!\d|(?:\s*[号条款节章项例页段部步点年月日时分秒个元千万台份家])))|' # 数字后直接跟顿号、点号时分割,且点号后不跟数字 eg:'1.'
r'(?<![A-Za-z])(?=[A-Za-z][.]\s*(?![A-Za-z]))|' # 单个字母+点号或单个字母+数字排除www.baidu.com 网址情况 r'(?<![A-Za-z])(?=[A-Za-z][.]\s*(?![A-Za-z]))|' # 单个字母+点号或单个字母+数字排除www.baidu.com 网址情况
r'(?=[A-Za-z]+\s*\d+\s*(?:[.]\s*\d+)*)|' # 在字母加数字或多级编号前分割 r'(?=[A-Za-z]+\s*\d+\s*(?:[.]\s*\d+)*)|' # 在字母加数字或多级编号前分割
r'(?<=^|\n)(?=[一二三四五六七八九十]+、)', # 在中文数字加顿号(如一、二、)前分割,(?<=^|\n)增加了行首限制 r'(?<=^|\n)(?=[一二三四五六七八九十]+、)|' # 在中文数字加顿号(如一、二、)前分割,(?<=^|\n)增加了行首限制
r'(?<=^|\n)(?=[①②③④⑤⑥⑦⑧⑨]+)',
item_with_placeholders item_with_placeholders
) )
@ -431,49 +432,62 @@ def extract_file_elements(file_path):
for element in doc_elements: for element in doc_elements:
# 如果是段落 # 如果是段落
if element.tag.endswith('}p'): if element.tag.endswith('}p'):
if pre_table_head: try:
# Ensure we only process paragraphs if paragraph_index is within range
if paragraph_index < len(doc_paragraphs):
# print(f"Processing paragraph {paragraph_index}/{len(doc_paragraphs)}")
text = doc_paragraphs[paragraph_index].text text = doc_paragraphs[paragraph_index].text
# 如果上一个是表格,并且之后没有文本或为跨页标记,则不提取 if pre_table_head:
# If we are still processing a table, check conditions
if (text == '' or pattern_marker.search(text)): if (text == '' or pattern_marker.search(text)):
paragraph_index += 1 paragraph_index += 1
continue continue
# 如果遇到有效文本,则说明表格提取完毕
else: else:
doc_contents.append('[$$table_over$$]') doc_contents.append('[$$table_over$$]')
table_combine = False table_combine = False
pre_table_head = None pre_table_head = None
doc_contents.append(doc_paragraphs[paragraph_index]) doc_contents.append(doc_paragraphs[paragraph_index])
paragraph_index += 1 paragraph_index += 1
else:
raise IndexError(f"Paragraph index {paragraph_index} is out of range. Total paragraphs: {len(doc_paragraphs)}")
except IndexError as e:
print(f"Error processing paragraph: {e}")
continue # Skip to the next element if an error occurs
# 如果是表格 # 如果是表格
elif element.tag.endswith('}tbl'): elif element.tag.endswith('}tbl'):
try:
if tables_index < len(doc_tables):
# print(f"Processing table {tables_index}/{len(doc_tables)}")
table = doc_tables[tables_index] table = doc_tables[tables_index]
table_content = [] table_content = []
for row_idx, row in enumerate(table.rows): for row_idx, row in enumerate(table.rows):
if row_idx == 0: if row_idx == 0:
# 跳过表头
if pre_table_head: if pre_table_head:
table_combine = True table_combine = True
if pre_table_head == row.cells[0].text: if pre_table_head == row.cells[0].text:
continue continue
# 记录初始表头
else: else:
pre_table_head = row.cells[0].text pre_table_head = row.cells[0].text
doc_contents.append('[$$table_start$$]') doc_contents.append('[$$table_start$$]')
continue continue
# 遍历每一行中的单元格
for cell in row.cells: for cell in row.cells:
cell_text = cell.text.strip() # 去除单元格内容前后空白 cell_text = cell.text.strip()
if len(cell_text) > 8: # 检查文字数量是否大于8 if len(cell_text) > 8:
cell_text = split_cell_text(cell_text) cell_text = split_cell_text(cell_text)
table_content += cell_text table_content += cell_text
# 合并跨页表格
if table_combine: if table_combine:
if not doc_contents[-1].endswith(('', '!', '?', ';')): if doc_contents and table_content and not doc_contents[-1].endswith(('', '!', '?', ';')):
doc_contents[-1] += ' ' + table_content[0] doc_contents[-1] += ' ' + table_content[0]
table_content.pop(0) table_content.pop(0)
doc_contents.extend(table_content) doc_contents.extend(table_content)
# doc_contents.append('[$$table_over$$]')
tables_index += 1 tables_index += 1
else:
raise IndexError(f"Table index {tables_index} is out of range. Total tables: {len(doc_tables)}")
except IndexError as e:
print(f"Error processing table: {e}")
continue # Skip to the next element if an error occurs
return doc_contents return doc_contents
def handle_query(file_path, user_query, output_file, result_key, keywords): def handle_query(file_path, user_query, output_file, result_key, keywords):
@ -493,25 +507,26 @@ def handle_query(file_path, user_query, output_file, result_key, keywords):
extracted_contents = extract_text_with_keywords(processed_paragraphs, [keywords], follow_up_keywords) extracted_contents = extract_text_with_keywords(processed_paragraphs, [keywords], follow_up_keywords)
all_texts1,all_texts2 = clean_dict_datas(extracted_contents, keywords, excludes) # 列表 all_texts1,all_texts2 = clean_dict_datas(extracted_contents, keywords, excludes) # 列表
# print(all_texts2) # print(all_texts2)
seen_contents = set() # 使用集合来跟踪已出现的内容
unique_all_texts1 = {} # 存储去重后的内容
for key, content in all_texts1.items():
content_key = content[:25] # 提取前25个字符作为去重依据
if content_key not in seen_contents:
unique_all_texts1[key] = content # 保留第一次出现的内容
seen_contents.add(content_key)
# 1. 得到有序的 all_text1_items # 1. 得到有序的 all_text1_items
all_text1_items = sorted(all_texts1.items(), key=lambda x: x[0]) all_text1_items = sorted(unique_all_texts1.items(), key=lambda x: x[0])
# 2. 得到纯内容列表 # 2. 得到纯内容列表
all_texts1_list = [content for (_, content) in all_text1_items] all_texts1_list = [content for (_, content) in all_text1_items]
# Proceed only if there is content to write # Proceed only if there is content to write
selected_contents = {} selected_contents = {}
final_list=[f"未解析到'{result_key}'"] final_list=[f"未解析到'{result_key}'"]
seen_contents = set() # 使用集合跟踪已添加的内容以去重
if all_texts1_list or all_texts2: if all_texts1_list or all_texts2:
with open(output_file, 'w', encoding='utf-8') as file: with open(output_file, 'w', encoding='utf-8') as file:
counter = 1 counter = 1
for content in all_texts1_list: for content in all_texts1_list:
# 使用内容的前25个字符作为去重的依据
key = content[:25] # 提取前25个字符
if key not in seen_contents: # 如果前30个字符未出现过
file.write(f"{counter}. {content}\n") file.write(f"{counter}. {content}\n")
file.write("..............." + '\n') file.write("..............." + '\n')
seen_contents.add(key) # 标记前30个字符为已写入
counter += 1 counter += 1
# 生成用户查询 # 生成用户查询
@ -525,7 +540,8 @@ def handle_query(file_path, user_query, output_file, result_key, keywords):
# model_ans = qianwen_long(file_id, user_query) # model_ans = qianwen_long(file_id, user_query)
num_list = process_string_list(model_ans) # 处理模型返回的序号 num_list = process_string_list(model_ans) # 处理模型返回的序号
print(result_key + "选中的序号:" + str(num_list)) print(result_key + "选中的序号:" + str(num_list))
# print(all_texts1_list)
# print(all_text1_items)
for index in num_list: for index in num_list:
if 1 <= index <= len(all_texts1_list): if 1 <= index <= len(all_texts1_list):
original_global_idx = all_text1_items[index - 1][0] original_global_idx = all_text1_items[index - 1][0]
@ -566,9 +582,11 @@ def combine_find_invalid(invalid_docpath, output_dir):
任务目标 任务目标
从文本中筛选所有描述否决投标拒绝投标投标响应无效或类似表述的情况并返回对应的序号 从文本中筛选所有描述否决投标拒绝投标投标响应无效或类似表述的情况并返回对应的序号
要求与指南 要求与指南
文本中可能存在无关的信息请准确筛选符合条件的信息并将符合条件的信息的序号返回 1.投标相关主体包括但不限于投标人中标人供应商联合体投标各方响应人应答人或其他描述投标方的词语
1.文本中可能存在无关的信息请准确筛选符合条件的信息即怎样的情况下,投标相关主体的投标将被否决拒绝作为无效标或者是投标无效响应无效等请返回符合条件的信息的序号
2.若条款内容包含'否决投标的情况说明'这样的笼统描述而未说明具体的情形则无需添返回该条款
输出格式 输出格式
[x, x, x] 的形式返回x 为符合条件的信息的序号为自然数 [x, x, x] 的形式返回x 为符合条件的信息的序号为自然数无需额外返回解释与说明
如果文本中没有符合条件的信息请返回 [] 如果文本中没有符合条件的信息请返回 []
特殊情况 特殊情况
如果某序号的内容明显分为几部分且一部分内容符合筛选条件但其他部分明显是无关内容请返回符合部分的字符串内容代替序号 如果某序号的内容明显分为几部分且一部分内容符合筛选条件但其他部分明显是无关内容请返回符合部分的字符串内容代替序号
@ -587,7 +605,7 @@ def combine_find_invalid(invalid_docpath, output_dir):
要求与指南 要求与指南
文本中可能存在无关的信息请准确筛选符合条件的信息并将符合条件的信息的序号返回 文本中可能存在无关的信息请准确筛选符合条件的信息并将符合条件的信息的序号返回
输出格式 输出格式
返回结果以 [x, x, x] 的形式其中 x 为符合条件的信息的序号为自然数 返回结果以 [x, x, x] 的形式其中 x 为符合条件的信息的序号为自然数无需额外返回解释与说明
如果文本中没有任何符合条件的废标情况请返回 [] 如果文本中没有任何符合条件的废标情况请返回 []
示例输出,仅供格式参考 示例输出,仅供格式参考
[1,3,4,6] [1,3,4,6]
@ -611,7 +629,7 @@ def combine_find_invalid(invalid_docpath, output_dir):
若在语境中其指代或包含投标相关主体则应将其考虑在内否则排除该条款 若在语境中其指代或包含投标相关主体则应将其考虑在内否则排除该条款
**输出格式** **输出格式**
返回结果以 [x, x, x] 的形式其中 x 为符合条件的条款的序号为自然数 返回结果以 [x, x, x] 的形式其中 x 为符合条件的条款的序号为自然数无需额外返回解释与说明
如果没有符合条件的条款返回 `[]` 如果没有符合条件的条款返回 `[]`
**示例** **示例**
- **符合条件** - **符合条件**
@ -661,10 +679,10 @@ if __name__ == '__main__':
# doc_path = r'C:\Users\Administrator\Desktop\new招标文件\tmp\2024-贵州-贵州省罗甸县 2024 年度广州市协作资金龙坪镇、边阳镇产业路硬化建设项目.docx' # doc_path = r'C:\Users\Administrator\Desktop\new招标文件\tmp\2024-贵州-贵州省罗甸县 2024 年度广州市协作资金龙坪镇、边阳镇产业路硬化建设项目.docx'
pdf_path = r'C:\Users\Administrator\Desktop\新建文件夹 (3)\废标\“天府粮仓”青白江区“一园三片”数字化提升和标准化体系建设项目(三次)招标文件N510113202400010820250102001.pdf' pdf_path = r'C:\Users\Administrator\Desktop\新建文件夹 (3)\废标\“天府粮仓”青白江区“一园三片”数字化提升和标准化体系建设项目(三次)招标文件N510113202400010820250102001.pdf'
output_dir = r"C:\Users\Administrator\Desktop\新建文件夹 (3)\废标" output_dir = r"D:\flask_project\flask_app\static\output\output1\63504625-9178-47df-b513-17709434fa68\tmp"
# invalid_added = insert_mark(pdf_path) # invalid_added = insert_mark(pdf_path)
# # invalid_added_docx = pdf2docx(invalid_added) # # invalid_added_docx = pdf2docx(invalid_added)
invalid_added_docx=r'C:\Users\Administrator\Desktop\测试信号测试信号.docx' invalid_added_docx=r'D:\flask_project\flask_app\static\output\output1\63504625-9178-47df-b513-17709434fa68\invalid_added.docx'
results = combine_find_invalid(invalid_added_docx, output_dir) results = combine_find_invalid(invalid_added_docx, output_dir)
end_time = time.time() end_time = time.time()
print("Results:", json.dumps(results, ensure_ascii=False, indent=4)) print("Results:", json.dumps(results, ensure_ascii=False, indent=4))

View File

@ -217,34 +217,28 @@ def judge_consortium_bidding(baseinfo_list):
baseinfo_list[:] = updated_list baseinfo_list[:] = updated_list
return accept_bidding return accept_bidding
#字符串列表转为普通列表,从qianwen回答中提取 #字符串列表转为普通列表,从大模型回答中提取
def process_string_list(string_list): def process_string_list(string_list):
# 使用正则表达式匹配方括号内的内容 # 使用正则表达式匹配方括号内的内容
try:
match = re.search(r'\[(.*?)\]', string_list) match = re.search(r'\[(.*?)\]', string_list)
if match: if match:
# 获取匹配的内容,即方括号内的部分 # 获取匹配的内容,即方括号内的部分
content_inside_brackets = match.group(1) content_inside_brackets = match.group(1)
if content_inside_brackets: # 检查内容是否为空 if content_inside_brackets: # 检查内容是否为空
# 检查内容是否是数字列表 # 提取所有数字项,并转换为整数
if all(item.strip().isdigit() for item in content_inside_brackets.split(',')): numbers = [
# 如果是数字,不用加引号,直接保留数字 int(item.strip()) for item in content_inside_brackets.split(',')
formatted_list = '[' + ', '.join(item.strip() for item in content_inside_brackets.split(',') if item.strip()) + ']' if re.match(r'^\d+$', item.strip()) # 正则表达式判断是否为纯数字
]
return numbers
else: else:
# 如果不全是数字,按字符串处理 return [] # 如果内容为空,直接返回空列表
formatted_list = '[' + ', '.join(f"'{item.strip()}'" for item in content_inside_brackets.split(',') if item.strip()) + ']'
else: else:
return [] # 直接返回空列表如果内容为空 return [] # 如果没有匹配到内容,返回空列表
except Exception as e:
# 使用 ast.literal_eval 来解析格式化后的字符串 print(f"Error occurred: {e}")
try: return [] # 出现任何异常时返回空列表
actual_list = ast.literal_eval(formatted_list)
return actual_list
except SyntaxError as e:
print(f"禁止投标情形: Error parsing list: {e}")
return []
else:
# 如果没有匹配到内容,返回空列表
return []
def get_global_logger(unique_id): def get_global_logger(unique_id):
if unique_id is None: if unique_id is None: