title enhancement

This commit is contained in:
wvivi2023 2024-02-28 16:40:45 +08:00
parent d123ad7c29
commit bac5b22879
3 changed files with 41 additions and 19 deletions

View File

@ -370,7 +370,10 @@ class KnowledgeFile:
if not docs: if not docs:
return [] return []
#先给二级下 被分开的三级目录分块 增加二级标题,再给分开的二级目录增加一级标题,然后给整个文档的所有分块增加文档标题分块 #先给三级下 被分开的四级目录分块 增加三级标题,
#再给二级下 被分开的三级目录分块 增加二级标题,
#再给分开的二级目录增加一级标题,
#然后给整个文档的所有分块增加文档标题分块
if zh_title_enhance: if zh_title_enhance:
docs = zh_third_title_enhance(docs) docs = zh_third_title_enhance(docs)
docs = zh_second_title_enhance(docs) docs = zh_second_title_enhance(docs)

View File

@ -80,8 +80,8 @@ class ChineseRecursiveTextSplitter(RecursiveCharacterTextSplitter):
text = re.sub(r'(\n+((一)|(二)|(三)|(四)|(五)|(六)|(七)|(八)|(九)|(十)|(十一)|(十二)|(十三)|(十四)|(十五)|(十六)|(十七)|(十八)|(十九)|(二十)))', r"\n\n\n\n\n\n\1", text) text = re.sub(r'(\n+((一)|(二)|(三)|(四)|(五)|(六)|(七)|(八)|(九)|(十)|(十一)|(十二)|(十三)|(十四)|(十五)|(十六)|(十七)|(十八)|(十九)|(二十)))', r"\n\n\n\n\n\n\1", text)
text = re.sub(r'(\n+(\(一\)|\(二\)|\(三\)|\(四\)|\(五\)|\(六\)|\(七\)|\(八\)|\(九\)|\(十\)|\(十一\)|\(十二\)|\(十三\)|\(十四\)|\(十五\)|\(十六\)|\(十七\)|\(十八\)|\(十九\)|\(二十\)))', r"\n\n\n\n\n\n\1", text) text = re.sub(r'(\n+(\(一\)|\(二\)|\(三\)|\(四\)|\(五\)|\(六\)|\(七\)|\(八\)|\(九\)|\(十\)|\(十一\)|\(十二\)|\(十三\)|\(十四\)|\(十五\)|\(十六\)|\(十七\)|\(十八\)|\(十九\)|\(二十\)))', r"\n\n\n\n\n\n\1", text)
#四级目录 # 不支持对四级目录分块,如果需要通过手工分段来实现
text = re.sub(r'(\n+(?<!\.|[a-zA-Z0-9])[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))', r"\n\n\n\n\1", text) # 再通过 1.2.3 # text = re.sub(r'(\n+(?<!\.|[a-zA-Z0-9])[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))', r"\n\n\n\n\1", text) # 再通过 1.2.3
text = text.rstrip() # 段尾如果有多余的\n就去掉它 text = text.rstrip() # 段尾如果有多余的\n就去掉它
self.is_recursive = True self.is_recursive = True
for i, _s in enumerate(separators): for i, _s in enumerate(separators):

View File

@ -4,8 +4,8 @@ import re
def get_fist_level_title( def get_fist_level_title(
text: str, text: str,
) -> bool: ) -> bool:
# 文本长度为0的话或长度大于25肯定不是title # 文本长度为0,肯定不是title
if len(text) == 0 and len (text)>= 25: if len(text) == 0:
print("Not a title. Text is empty or longer than 25.") print("Not a title. Text is empty or longer than 25.")
return "" return ""
@ -16,8 +16,7 @@ def get_fist_level_title(
ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN) ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN)
if ENDS_IN_PUNCT_RE.search(first_line) is not None: if ENDS_IN_PUNCT_RE.search(first_line) is not None:
return "" return ""
FIRST_TITLE = r'((?<!.)\d+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9])|((?<!.)第\s*\S+\s*章\s+\S+))'
FIRST_TITLE = r'((?<!.)\d+[^\S\n]+[^\s\.]+\S+|(?<!.)第\s*\S+\s*章\s+)'
TITLE_PUNCT_RE = re.compile(FIRST_TITLE) TITLE_PUNCT_RE = re.compile(FIRST_TITLE)
if TITLE_PUNCT_RE.search(first_line) is not None: if TITLE_PUNCT_RE.search(first_line) is not None:
return first_line return first_line
@ -28,7 +27,8 @@ def get_second_level_title(
text: str, text: str,
) -> str: ) -> str:
# 文本长度为0的话肯定不是title # 文本长度为0的话肯定不是title
if len(text) == 0 and len (text)>= 25: lenght = len(text)
if lenght == 0:
print("Not a title. Text is empty or longer than 25.") print("Not a title. Text is empty or longer than 25.")
return "" return ""
@ -39,7 +39,12 @@ def get_second_level_title(
ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN) ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN)
if ENDS_IN_PUNCT_RE.search(first_line) is not None: if ENDS_IN_PUNCT_RE.search(first_line) is not None:
return "" return ""
#3 ****
#3.1 *****
#3.1.1 *****
#另一个分块
#3.1.2 ***** 所以二级目录可能在第二行 和第一行
Second_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9])|(?<!.)第\s*\S+\s*条\s+|(?<!.)第\s*\S+\s*条(:|)|(?<!.)(一、|二、|三、|四、|五、|六、|七、|八、|九、|十、|十一、|十二、|十三、|十四、|十五、|十六、|十七、|十八、|十九、|二十、))' Second_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9])|(?<!.)第\s*\S+\s*条\s+|(?<!.)第\s*\S+\s*条(:|)|(?<!.)(一、|二、|三、|四、|五、|六、|七、|八、|九、|十、|十一、|十二、|十三、|十四、|十五、|十六、|十七、|十八、|十九、|二十、))'
TITLE_PUNCT_RE = re.compile(Second_TITLE) TITLE_PUNCT_RE = re.compile(Second_TITLE)
if TITLE_PUNCT_RE.search(first_line) is not None: if TITLE_PUNCT_RE.search(first_line) is not None:
@ -82,7 +87,7 @@ def is_third_level_content(
splitlines = text.splitlines() splitlines = text.splitlines()
first_line = splitlines[0] first_line = splitlines[0]
Third_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))|((?<!.)表\s*[A-Za-z0-9]+(\s*\.\s*[A-Za-z0-9]+)*\s+)|((?<!.)(一)|(二)|(三)|(四)|(五)|(六)|(七)|(八)|(九)|(十)|(十一)|(十二)|(十三)|(十四)|(十五)|(十六)|(十七)|(十八)|(十九)|(二十))|((?<!.)(\(一\)|\(二\)|\(三\)|\(四\)|\(五\)|\(六\)|\(七\)|\(八\)|\(九\)|\(十\)|\(十一\)|\(十二\)|\(十三\)|\(十四\)|\(十五\)|\(十六\)|\(十七\)|\(十八\)|\(十九\)|\(二十\)))' Third_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))|((?<!.)表\s*[A-Za-z0-9]+(\s*\.\s*[A-Za-z0-9]+)*\s+)|((?<!.)(一)|(二)|(三)|(四)|(五)|(六)|(七)|(八)|(九)|(十)|(十一)|(十二)|(十三)|(十四)|(十五)|(十六)|(十七)|(十八)|(十九)|(二十))|((?<!.)(\(一\)|\(二\)|\(三\)|\(四\)|\(五\)|\(六\)|\(七\)|\(八\)|\(九\)|\(十\)|\(十一\)|\(十二\)|\(十三\)|\(十四\)|\(十五\)|\(十六\)|\(十七\)|\(十八\)|\(十九\)|\(二十\)))'
TITLE_PUNCT_RE = re.compile(Third_TITLE) TITLE_PUNCT_RE = re.compile(Third_TITLE)
if TITLE_PUNCT_RE.search(first_line) is not None: if TITLE_PUNCT_RE.search(first_line) is not None:
return True return True
@ -93,7 +98,7 @@ def get_third_level_title(
text: str, text: str,
) -> str: ) -> str:
# 文本长度为0的话肯定不是title # 文本长度为0的话肯定不是title
if len(text) == 0 and len (text)>= 25: if len(text) == 0:
print("Not a title. Text is empty or longer than 25.") print("Not a title. Text is empty or longer than 25.")
return "" return ""
@ -104,7 +109,13 @@ def get_third_level_title(
ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN) ENDS_IN_PUNCT_RE = re.compile(ENDS_IN_PUNCT_PATTERN)
if ENDS_IN_PUNCT_RE.search(first_line) is not None: if ENDS_IN_PUNCT_RE.search(first_line) is not None:
return "" return ""
#3 ****
#3.1 *****
#3.1.1 *****
#3.1.1.1 *****
#另一个分块
#3.1.1.2 ***** 所以三级级目录可能在第三行 和第二行及第一行
Third_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))' Third_TITLE = r'((?<!.)[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+\s*\.\s*[a-zA-Z0-9]+[^\S\n]+[^\s\.]+(?!\.|[a-zA-Z0-9]))'
TITLE_PUNCT_RE = re.compile(Third_TITLE) TITLE_PUNCT_RE = re.compile(Third_TITLE)
if TITLE_PUNCT_RE.search(first_line) is not None: if TITLE_PUNCT_RE.search(first_line) is not None:
@ -114,6 +125,12 @@ def get_third_level_title(
Second_line = splitlines[1] Second_line = splitlines[1]
if TITLE_PUNCT_RE.search(Second_line) is not None: if TITLE_PUNCT_RE.search(Second_line) is not None:
return Second_line return Second_line
else:
if len(splitlines)>2:
Second_line = splitlines[2]
if TITLE_PUNCT_RE.search(Second_line) is not None:
return Second_line
return "" return ""
#judge if it is 4th level content #judge if it is 4th level content
@ -162,7 +179,6 @@ def zh_third_title_enhance(docs: Document) -> Document:
#给三级被分开的内容 增加二级标题 #给三级被分开的内容 增加二级标题
def zh_second_title_enhance(docs: Document) -> Document: def zh_second_title_enhance(docs: Document) -> Document:
title = None title = None
print(f"zh_second_title_enhance ....")
if len(docs) > 0: if len(docs) > 0:
for doc in docs: for doc in docs:
print(f"zh_second_title_enhance: {doc}") print(f"zh_second_title_enhance: {doc}")
@ -188,26 +204,29 @@ def zh_first_title_enhance(docs: Document) -> Document:
title = None title = None
if len(docs) > 0: if len(docs) > 0:
for doc in docs: for doc in docs:
print(f"zh_first_title_enhance: {doc}")
first_title = get_fist_level_title(doc.page_content) first_title = get_fist_level_title(doc.page_content)
if first_title: if first_title:
title = first_title title = first_title
print(f"title: {title}")
elif title: elif title:
temp_second_content = is_second_level_content(doc.page_content) temp_second_content = is_second_level_content(doc.page_content)
if temp_second_content: if temp_second_content:
print(f"is_second_level_content : {temp_second_content}")
doc.page_content = f"{title} {doc.page_content}" doc.page_content = f"{title} {doc.page_content}"
else: else:
title = None title = None
print(f"final title: {title}")
return docs return docs
else: else:
print("zh_first_title_enhance 文件不存在") print("zh_first_title_enhance 文件不存在")
if __name__ == "__main__": if __name__ == "__main__":
str = """8.1.3 采购过程\n为统筹资产管理相关的采购需求,统一设备采购标准,保障采购的产品和服务的质量,应策划、实 施和控制电网实物资产相关的采购过程。采购过程包括招标采购、仓储配送及到货验收等。对产品和服 务的采购以及供应商的选择等,应按照 8.3 外包的要求进行管理。策划、实施和控制时应满足:\na) 应统计和分析建设、运维阶段的设备质量信息,如设备缺陷信息、故障信息及使用寿命等,用 于指导设备采购标准的制定。应系统性评估企业的采购需求以及内外部机会,确定采购策略, 从而降低企业的整体成本,发挥企业的内外部优势,如实施战略采购、超市化采购等;\nb) 库存物资应进行统一管理,建立包含不同业务形成的实物库存的台账,如利用 ERP 系统建立库 存物资“一本账 ”,准确反映实体仓库内库存实物信息。应根据合同交付和物资使用的要求, 统一进行物资配送的调度和协调,以满足安全、准时、快捷、服务优质等要求;\nc) 应综合考虑设备的价值、重要性、复杂性等因素,确定监造设备范围(如变压器、换流变、串\nQ/GDW 12219—2022\n联补偿装置、换流阀等)和监造方式(如驻厂监造、关键点见证等);物资抽检应覆盖所有供 应商及所有物资类别;现场验收应按照策划的方式进行。应保留监造、抽检和现场验收相关的 文件和过程控制记录。' metadata={'source': '/home/bns001/Langchain-Chatchat_0.2.9/knowledge_base/test/content/资产全寿命周期管理体系实施指南.docx'} str = """1 总 则\n1.1 本导则是编制和审查城市电力网(以下简称城网)规划的指导性文件,其 适用范围为国家电网公司所属的各网省公司、城市供电公司。\n1.2 城网是城市行政区划内为城市供电的各级电压电网的总称。城网是电力系 统的主要负荷中心,作为城市的重要基础设施之一,与城市的社会经济发展密切 相关。各城市应根据《中华人民共和国城市规划法》和《中华人民共和国电力法》 的相关规定,编制城网规划,并纳入相应的城市总体规划和各地区详细规划中。\n1.3 城网规划是城市总体规划的重要组成部分,应与城市的各项发展规划相互 配合、同步实施,做到与城市规划相协调,落实规划中所确定的线路走廊和地下 通道、变电站和配电室站址等供电设施用地。\n1.4 城网规划的目的是通过科学的规划,建设网络坚强、结构合理、安全可靠、 运行灵活、节能环保、经济高效的城市电网,不断提高城网供电能力和电能质量, 以满足城市经济增长和社会发展的需要。 ' metadata={'source': '/home/bns001/Langchain-Chatchat_0.2.9/knowledge_base/test/content/资产全寿命周期管理体系实施指南.docx'}"""
title: 为统筹资产管理相关的采购需求统一设备采购标准保障采购的产品和服务的质量应策划 施和控制电网实物资产相关的采购过程采购过程包括招标采购仓储配送及到货验收等对产品和服 务的采购以及供应商的选择等应按照 8.3 外包的要求进行管理策划实施和控制时应满足 title = get_fist_level_title(str)
"""
title = is_third_level_content(str)
print(title) print(title)
#title = get_second_level_title(str)
#print(title)
#zh_second_title_enhance() #zh_second_title_enhance()