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

336 lines
17 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 = {
"舰艇": ["名称", "型号", "弦号", "设计单位", "总装工厂", "所属部队"],
"系统": ["名称", "型号", "生产单位", "等级","功能"],
"子系统": ["名称", "型号", "生产单位", "等级","功能"],
"一级零部件": ["名称", "型号", "技术责任单位", "生产单位"],
"二级零部件": ["名称", "型号", "技术责任单位", "生产单位"],
"故障模式": ["名称", "故障原因", "故障影响", "故障类型", "发生时间", "处置情况", "修复情况","维修方案"],
"维修方案": ["名称", "维修项目编号","维修间隔期", "安全注意事项", "保障设备(工具)", "备品备件", "消耗材料", "人力人员", "备品备件", "修前判据", "修理步骤及工艺", "验收标准"],
"操作项目": ["名称", "操作项目编号", "安全防护", "注意事项", "保障设施、保障设备(工具)", "人力人员", "操作步骤"],
"备品备件" : ["名称", "规格", "型号", "图号或标准号或代号","计量单位", "单机重量", "尺寸长X宽X高mm", "单机装配数量","实物图片电子文档名称","MTBF(b)","生成厂家",
"出厂日期",
"供货周期(天)",
"有效期(月)",
"使用寿命h)",
"备件箱号",
"储存要求_环境",
"储存要求_期限",
"停产后供应方式"],
"维修手册": ["名称", "url"],
"操作使用手册": ["名称", "url"],
}
Ontology_DESCRIPTION = {
"舰艇": ["代表一艘完整海上作战或保障平台的实体,是所有系统、设备和零部件的最高层级载体。区别于“系统”或“设备”,舰艇具有独立的型号、弦号和部队归属,不可作为其他舰艇的组成部分。"],
"系统": ["舰艇中实现某一类功能(如动力、导航、通信)的集成化功能单元,由多个设备协同组成。与“设备”不同,系统本身不直接对应物理装置,而是逻辑/功能层面的集合;与“舰艇”不同,系统不具备独立航行能力或部队归属。"],
"子系统": ["系统内部为实现特定子功能而划分的独立功能模块,是系统的直接组成部分。子系统既具备相对独立的功能完整性(可单独测试或隔离),又必须依赖所属系统才能发挥最终战术效能,是连接系统逻辑与物理设备的中间层级。"],
"部件": ["构成子系统或设备的最小可独立拆卸、更换的物理实体单元常称为LRU即外场可更换单元。部件具有明确的物理边界和接口通常无需深层拆解即可进行整体替换是维修作业中直接操作的主要对象。"],
"一级零部件": ["部件内部的核心功能组件,是部件的直接构成元素。一级零部件通常承担部件内的主要能量转换、信号处理或机械传动任务,其故障往往导致整个部件功能失效,需通过专业工具拆解部件后方可触及。"],
"二级零部件": ["一级零部件的细分构成单元,属于更深层次的基礎元件(如电阻、电容、密封圈、轴承等)。二级零部件通常不具备独立的功能意义,主要作为基础材料或标准件存在,一般仅在车间级深度维修或制造过程中涉及。"],
"故障模式": ["对舰艇装备在运行过程中表现出的异常状态、性能退化或功能丧失现象的标准化描述。故障模式明确了“发生了什么错误”(如断裂、短路、泄漏、卡滞),是关联故障现象与维修方案的桥梁,不包含原因分析或解决措施。"],
"维修方案": ["针对特定故障模式或预防性维护需求,制定的一套标准化的技术处置流程集合。维修方案详细规定了诊断步骤、拆装工艺、测试标准及所需资源,旨在指导维修人员恢复装备的技术战术性能,是维修决策的核心依据。"],
"操作项目": ["舰员在日常使用、值更或训练过程中,对装备执行的具体动作指令或检查任务(如启动、切换模式、参数读取、日常擦拭)。操作项目侧重于装备的正确使用与状态监控,区别于以修复为目的的“维修方案”。"],
"备品备件": ["为保障舰艇装备持续运行和及时修复,预先储备的可替换物理实体的总称。备品备件涵盖了从部件到二级零部件的各个层级,其管理核心在于平衡库存成本与战备完好率,确保在故障发生时能立即供应。"],
"维修手册": ["记载装备维修理论、故障排查逻辑、详细修理工艺、测试规范及安全技术要求的权威性技术文档。维修手册主要面向维修技术人员,提供“如何修”的深度指导,是实施维修方案的法定依据。"],
"操作使用手册": ["指导舰员正确、安全、高效地使用装备的功能说明与操作规程文档。操作使用手册主要面向装备操作人员,内容涵盖工作原理简介、操作步骤、应急处置及日常保养要求,侧重于“如何用”而非“如何修”。"]
}
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
async def extract_text_node_relationship(
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]]
):
final_prompt = create_extraction_prompt(
text=text,
ontology=ontology,
Ontology_DESCRIPTION=Ontology_DESCRIPTION,
relationships=relationships,
relationship_types=relationship_types,
node_types=node_types
)
res_str = await OpenaiAPI.openai_chat_aysnc(final_prompt,timeout=600)
# 处理 API 调用失败
if res_str is None:
print("⚠️ 跳过当前 chunkAPI 调用失败")
# 尝试解析 JSON
try:
res = json.loads(res_str)
except json.JSONDecodeError as e:
print(f"❌ JSON 解析失败: {e}")
print(f"原始响应内容: {repr(res_str)}")
# 安全访问字段
new_entities = res.get("entities", [])
new_relationships = res.get("relationships", [])
# 可选:最后汇总输出
# print("\n=== 最终结果 ===")
# print("生成文本本体:", new_entities_result)
# print("生成文本关系:", new_relationships_result)
return new_entities,new_relationships
# 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)