kgrag/kg_build_v2/get_text_node_reala.py
2026-06-30 13:35:52 +08:00

332 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from openai import OpenAI
from typing import List, Dict
import json
from langchain_text_splitters import MarkdownHeaderTextSplitter, CharacterTextSplitter
import requests
import json
from modelsAPI.model_api import OpenaiAPI
def _split_markdown(text, chunk_size=2048, chunk_overlap=50):
"""
根据 max_level 动态生成 headers_to_split_on 配置
规则:
- max_level=1 → 只按 # 分割
- max_level=2 → 按 # 和 ## 分割
- 以此类推
"""
# 动态生成 headers_to_split_on 配置(目前固定为 Header_1
headers_to_split_on = [("#", "Header_1")]
# 初始化分割器
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=headers_to_split_on,
strip_headers=True
)
chunks = splitter.split_text(text)
char_splitter = CharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=len,
separator="\n\n" # 更合理的分隔符
)
final_chunks = []
start_chars = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "", "",
"", "", "", "", "", "", "", "", ""," 故障"]
new_header = []
# 提取所有 Header_1 并筛选出“有效标题”
for chunk in chunks:
header_1 = chunk.metadata.get('Header_1', '')
if header_1 and header_1[0] in start_chars:
new_header.append(header_1)
new_header_set = set(new_header)
# 构建带标题前缀的 final_chunks
for chunk in chunks:
header_1 = chunk.metadata.get('Header_1', '')
content = chunk.page_content
if len(content) <= 20000:
chunk_with_header = f"{header_1}\n{content}" if header_1 else content
final_chunks.append(chunk_with_header)
else:
split_texts = char_splitter.split_documents([chunk])
for split_chunk in split_texts:
chunk_with_header = f"{header_1}\n{split_chunk.page_content}" if header_1 else split_chunk.page_content
final_chunks.append(chunk_with_header)
# ===== 重新分组,并记录每个组的 header =====
rechunked = []
rechunked_headers = [] # 新增:每个 rechunked 块对应的 header
current = ""
current_header = "" # 当前正在构建的块所属的标题
for chunk in final_chunks:
is_new_section = False
matched_header = ""
# 检查是否以某个 new_header 开头
for h in new_header_set:
if chunk.startswith(h + "\n"):
is_new_section = True
matched_header = h
break
if is_new_section:
# 保存上一段
if current:
rechunked.append(current)
rechunked_headers.append(current_header)
# 开启新段
current = chunk
current_header = matched_header
else:
# 合并到当前段
if current:
current += "\n" + chunk
else:
current = chunk
current_header = "" # 如果开头无标题,则 header 为空
# 添加最后一段
if current:
rechunked.append(current)
rechunked_headers.append(current_header)
return rechunked, rechunked_headers
Ontology = ["舰艇", "系统", "设备", "零部件", "故障", "修理", "维修项目","操作项目","保养"]
Relationships = ["包含", "组成", "解决", "用于", "使用","具有"]
# 节点类型及其属性定义
NODE_TYPES = {
"舰艇": ["名称","型号", "弦号", "设计单位", "总装工厂", "所属部队"],
"系统": ["名称", "技术责任单位", "生产单位", "级别"],
"设备": ["名称", "型号", "技术责任单位", "生产单位", "技术状态", "生产日期", "启用时间","运行时间","运行条件"],
"零部件": ["名称", "型号", "技术责任单位", "生产单位"],
"故障": ["故障现象名称", "故障原因", "故障影响", "故障类型", "发生时间", "处置情况", "修复情况"],
"修理": ["修理方案","修理人员", "修理时间", "修理工具", "备品备件", "修理类型", "维修项目"],
"维修项目": ["名称","维修项目编号", "组成编码", "维修设备名称", "维修间隔期", "维修级别", "页码", "安全防护要求", "安全注意事项","工具","备品备件","消耗材料","人力人员","修理步骤"],
"操作项目": ["名称", "操作项目编号", "安全防护", "注意事项","保障设施、保障设备(工具)", "人力人员", "操作步骤"],
"保养" : ["保养人员","保养时间","保养工具","保养频率"]
}
Ontology_DESCRIPTION = {
"舰艇": ["代表一艘完整海上作战或保障平台的实体,是所有系统、设备和零部件的最高层级载体。区别于“系统”或“设备”,舰艇具有独立的型号、弦号和部队归属,不可作为其他舰艇的组成部分。"],
"系统": ["舰艇中实现某一类功能(如动力、导航、通信)的集成化功能单元,由多个设备协同组成。与“设备”不同,系统本身不直接对应物理装置,而是逻辑/功能层面的集合;与“舰艇”不同,系统不具备独立航行能力或部队归属。"],
"设备": ["安装在舰艇上、具有独立型号和运行状态的物理装置,可被启停、监控运行时间,并可能产生故障。区别于“零部件”,设备是可独立更换或维修的功能单元;区别于“系统”,设备是具体硬件而非功能集合。"],
"零部件": ["构成设备的不可再拆分的基础物理元件(如轴承、电路板、密封圈),通常无独立运行状态或启用时间。与“设备”关键区别在于:零部件不能单独运行,也不记录运行时间或技术状态变更。"],
"故障": ["设备或系统在运行中出现的异常状态或失效事件,必须包含具体现象(如“无法启动”)、原因(如“电源短路”)及影响。区别于“修理”或“保养”,故障是问题本身,而非应对措施;不包含操作步骤或人员信息。"],
"修理": ["针对已发生故障所执行的一次性修复行为,包含具体时间、人员、工具、方案和所关联的维修项目。区别于“保养”,修理是响应式、非周期性的;区别于“维修项目”,修理是实际发生的实例,而非标准化规程。"],
"维修项目": ["标准化、可重复执行的维修任务规程,规定了某类设备或系统在特定条件下应如何维修,包含编号、步骤、材料、安全要求等。区别于“修理”,维修项目是模板或规范,而非具体事件;不包含实际发生时间或人员。"],
"操作项目": ["舰艇正常运行中需执行的标准操作流程(如启动主机、校准雷达),强调操作步骤与安全保障。区别于“维修项目”,操作使用项目用于日常使用而非维护"],
"保养" : ["按计划周期性执行的预防性维护活动(如润滑、清洁、检测),目的是延缓性能退化。"]
}
RELATIONSHIP_TYPES = {
"包含": ["舰艇包含系统", "系统包含设备","设备包含零部件","修理包含维修项目"],
"解决": ["修理解决故障", "维修项目解决故障"],
"使用": ["设备使用操作项目", "设备使用保养","设备使用维修项目"],
"具有": ["设备具有故障","零部件具有故障"]
}
def create_extraction_prompt(
text: str,
ontology: List[str],
Ontology_DESCRIPTION: Dict[str, List[str]],
relationships: List[str],
node_types: Dict[str, List[str]],
relationship_types: Dict[str, List[str]]
) -> str:
# 构建已有本体的定义(用于上下文)
ontology_def_descriptions = []
for etype in ontology:
clean_etype = etype.strip()
if clean_etype in Ontology_DESCRIPTION:
desc = "".join(Ontology_DESCRIPTION[clean_etype])
ontology_def_descriptions.append(f"- {clean_etype}{desc}")
else:
ontology_def_descriptions.append(f"- {clean_etype}:无明确定义")
# 构建关系示例
rel_examples = []
for rtype, examples in relationship_types.items():
for ex in examples[:1]:
rel_examples.append(f" - {ex}")
prompt = f"""你是一个专业的舰艇维修领域工程师。请基于给出的本体和属性等信息,抽取出实体、关系以及相关属性值。
> ⚠️ 重要说明:
> - **本体Ontology Class是抽象概念类别**,是对特定领域中概念体系的形式化、结构化规范,用于明确定义该领域内的实体类型(类)。
### 已有本体类型:
{chr(10).join(ontology_def_descriptions)}
### 已有关系类型:
- {"".join(relationships)}
典型用法示例:
{chr(10).join(rel_examples)}
### 待分析文本:
{text.strip()}
### 你的任务:
1、根据给出的本体、关系以及相应的属性从文本中抽取出所有可能的实体、关系以及相关属性值。
2、不要随意添加无效属性抽取的实体属于本体范围内关系属于关系范围内。、
### 输出格式:
请输出json格式内容不要输出其他格式和额外内容
{{
"entities": [
{{
"type": "设备",
"name": "1 号主机冷却系统",
"properties": {{
"名称": "1 号主机冷却系统",
"型号": "",
"技术责任单位": "XX 舰艇保障大队",
"生产单位": "",
"技术状态": "",
"生产日期": "",
"启用时间": "",
"运行时间": "",
"运行条件": ""
}}
}},
{{
"type": "故障",
"name": "1 号主机冷却系统温度异常升高",
"properties": {{
"故障现象": "1 号主机冷却系统温度异常升高",
"故障原因": "根据 A 设备发生的温度异常升高现象,结合相关技术手册与历史故障记录,分析如下:
(一)冷却液循环泵可能存在异常,导致流量不足;
(二)热交换器内部堵塞或外部散热片污损,影响散热效率;
(三)温度传感器或控制系统信号异常,导致误报警。
",
"故障影响": "",
"故障类型": "",
"发生时间": "2013 年 05 月 7 日 9 时 23 分 37 秒",
"处置情况": " ",
"修复情况": ""
“”
}}
}}
],
"relationships": [
{{
"type": "具有",
"from_entity": "1 号主机冷却系统",
"to_entity": "1 号主机冷却系统温度异常升高"
}}
]
}}
注意:
- 不要生成一些关系,如果没有就不要推荐
- 如果文本没有符合的关系和实体,不要进行强行抽取
"""
return prompt
def extract_text_node_relationship(
text: List[str],
ontology: List[str],
Ontology_DESCRIPTION: Dict[str, List[str]],
relationships: List[str],
node_types: Dict[str, List[str]],
relationship_types: Dict[str, List[str]]
):
new_entities_result = []
new_relationships_result = []
for ins in text:
final_prompt = create_extraction_prompt(
text=ins,
ontology=ontology,
Ontology_DESCRIPTION=Ontology_DESCRIPTION,
relationships=relationships,
relationship_types=relationship_types,
node_types=node_types
)
res_str = OpenaiAPI.openai_chat(final_prompt,timeout=180)
# 处理 API 调用失败
if res_str is None:
print("⚠️ 跳过当前 chunkAPI 调用失败")
continue
# 尝试解析 JSON
try:
res = json.loads(res_str)
except json.JSONDecodeError as e:
print(f"❌ JSON 解析失败: {e}")
print(f"原始响应内容: {repr(res_str)}")
continue
# 安全访问字段
new_entities = res.get("entities", [])
new_relationships = res.get("relationships", [])
for entity in new_entities:
if "properties" in entity and isinstance(entity["properties"], dict):
entity["properties"]["切片"] = ins
new_entities_result.extend(new_entities)
new_relationships_result.extend(new_relationships)
# 可选:最后汇总输出
# print("\n=== 最终结果 ===")
# print("生成文本本体:", new_entities_result)
# print("生成文本关系:", new_relationships_result)
return new_entities_result,new_relationships_result
# if __name__ == "__main__":
# text = """
# # 1螺旋桨本体
# 功能与特性能量转换的核心。它将主机的旋转动能转化为水流的反作用力推力。其特性由材料如镍铝青铜、锰青铜、桨叶数3-6叶、盘面比、螺距比等决定直接影响效率、空泡和振动性能。
# 相互关系:直接安装在尾轴(螺旋桨轴) 末端,其扭矩由尾轴传递,其推力通过推力轴承传递给船体。
# 2轴系
# 功能与特性:动力传递的桥梁。包括:
# s
# 推力轴及推力轴承:承受螺旋桨产生的巨大轴向推力,并将其传递给船体结构,是决定船舶能否前进、后退的关键。
# 中间轴:连接主机输出端与推力轴/尾轴。
# 尾轴(螺旋桨轴):穿过尾轴管,末端安装螺旋桨,工作环境恶劣(浸没海水中),通常需包覆铜套防腐。
# 相互关系:将主机的旋转输出与螺旋桨本体刚性连接,形成一个完整的动力传递链。推力轴承是轴系与船体结构之间的关键受力界面。
# 3尾轴管与密封系统功能与特性
# 尾轴管:固定于船体尾端,支撑尾轴并形成从船内(机舱)到船外(海水)的通道。
# 密封系统(首尾密封):绝对关键的安全设备。防止海水沿尾轴流入机舱(尾密封),同时防止润滑油泄漏(首尾密封均有此功能)。通常采用唇式密封或面式密封,材料耐磨、耐腐蚀。
# 相互关系:为尾轴提供支撑和润滑(油润滑或水润滑),其密封系统直接保护尾轴并确保机舱安全,与轴系和船体结构紧密集成。
# 4毂帽与导流罩功能与特性
# 毂帽:安装在螺旋桨毂后端,呈流线型,用于减少桨毂后部产生的涡流阻力,提高效率。
# 导流罩(如桨毂涡流消除器):安装在桨毂前方,改善流入桨叶的水流状态,尤其适用于肥大船型,能提升效率、减少振动。
# 相互关系:直接安装在螺旋桨本体的毂上,是其水动力性能的优化附件。
# 系统相互关系总结:
# 主机驱动轴系旋转,轴系末端的尾轴带动螺旋桨本体旋转。螺旋桨产生的推力通过尾轴传递至推力轴承,最终作用在船体上使其运动。尾轴管及密封系统为这一旋转运动提供支撑、润滑和至关重要的水密保障。毂帽和导流罩则作为螺旋桨本体的附件,优化其水动力性能。所有子设备协同工作的核心目标,是确保主机功率被高效、平稳、可靠地转化为推进船舶前进的有效推力。 任何一环失效(如密封泄漏、轴承损坏)都将导致整个推进系统瘫痪。
# """
# content = []
# content.append(text)
# extract_text_node_relationship(content,ontology=Ontology,Ontology_DESCRIPTION=Ontology_DESCRIPTION,relationships=Relationships,relationship_types=RELATIONSHIP_TYPES,node_types=NODE_TYPES)