Rewriter 2 лет назад
Родитель
Сommit
15e354c169

+ 53 - 0
QAsystem.py

@@ -0,0 +1,53 @@
+#encoding:utf-8
+from fastapi import FastAPI
+from py2neo import Graph
+from chatbot_graph import ChatBotGraph
+
+app = FastAPI()
+
+
+@app.get("/question")
+async def read_item(question: str):
+    handler = ChatBotGraph()
+    answer = handler.chat_main(question)
+    if(answer == "抱歉,我不知道"):
+        return {
+            "code": 404,
+            "data": answer,
+            "msg": "未找到答案"
+        }
+    return {
+        "code": 200,
+        "data": answer,
+        "msg": None
+    }
+
+if __name__ == '__main__':
+    
+    # 连接到Neo4j数据库
+    graph = Graph(
+                "bolt://127.0.0.1:7687",
+                # host="127.0.0.1",
+                # http_port=7474,
+                # user="neo4j",
+                # password="123456"
+                # http_port=7687,  # neo4j 服务器监听的端口号
+                user="neo4j",  # 数据库user name,如果没有更改过,应该是neo4j
+                password="123456")
+
+    # 查询实体信息
+    query = "MATCH (n) RETURN n"
+    results = graph.run(query)
+
+    # 将实体信息写入到TXT文件中
+    with open("./dict/entity.txt", "w",encoding = 'utf-8') as f:
+        for record in results:
+            node = record["n"]
+            f.write(f"{node['name']}\n")
+    
+    
+    import uvicorn
+    uvicorn.run(app=app,
+                host="0.0.0.0",
+                port=9998,
+                workers=1)

+ 51 - 0
QAsystem.spec

@@ -0,0 +1,51 @@
+# -*- mode: python ; coding: utf-8 -*-
+
+
+block_cipher = None
+
+
+a = Analysis(
+    ['QAsystem.py'],
+    pathex=[],
+    binaries=[],
+    datas=[],
+    hiddenimports=[],
+    hookspath=[],
+    hooksconfig={},
+    runtime_hooks=[],
+    excludes=[],
+    win_no_prefer_redirects=False,
+    win_private_assemblies=False,
+    cipher=block_cipher,
+    noarchive=False,
+)
+pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
+
+exe = EXE(
+    pyz,
+    a.scripts,
+    [],
+    exclude_binaries=True,
+    name='QAsystem',
+    debug=False,
+    bootloader_ignore_signals=False,
+    strip=False,
+    upx=True,
+    console=True,
+    disable_windowed_traceback=False,
+    argv_emulation=False,
+    target_arch=None,
+    codesign_identity=None,
+    entitlements_file=None,
+    icon=['QA.ico'],
+)
+coll = COLLECT(
+    exe,
+    a.binaries,
+    a.zipfiles,
+    a.datas,
+    strip=False,
+    upx=True,
+    upx_exclude=[],
+    name='QAsystem',
+)

+ 98 - 0
answer_search.py

@@ -0,0 +1,98 @@
+
+from py2neo import Graph
+
+
+class AnswerSearcher:
+    def __init__(self):
+        self.g = Graph(
+            "bolt://127.0.0.1:7687",
+            # host="127.0.0.1",
+            # http_port=7474,
+            # user="neo4j",
+            # password="123456"
+            # http_port=7687,  # neo4j 服务器监听的端口号
+            user="neo4j",  # 数据库user name,如果没有更改过,应该是neo4j
+            password="123456")
+        self.num_limit = 20
+
+    '''执行cypher查询,并返回相应结果'''
+
+    def search_main(self, sqls):
+        final_answers = []
+        for sql_ in sqls:
+            question_type = sql_['question_type']
+            queries = sql_['sql']
+            answers = []
+            for query in queries:
+                ress = self.g.run(query).data()
+                answers += ress
+            final_answer = self.answer_prettify(question_type, answers)
+            if final_answer:
+                final_answers.append(final_answer)
+        return final_answers
+
+    '''根据对应的qustion_type,板调用相应的回复模'''
+
+    def answer_prettify(self, question_type, answers):
+        final_answer = []
+        if not answers:
+            return ''
+        if question_type == 'entity_cause':
+            desc = [i['c.name'] for i in answers]
+            subject = answers[0]['a.name']
+            final_answer = '{0}现象的原因包括:{1}'.format(
+                subject, ';'.join(list(set(desc))[:self.num_limit]))
+
+        elif question_type == 'parts':
+            desc = [i['a.name'] for i in answers]
+            subject = answers[0]['c.name']
+            final_answer = '{0}的性能故障可能有:{1}'.format(
+                subject, ';'.join(list(set(desc))[:self.num_limit]))
+
+        elif question_type == 'solve':
+            desc = [i['c.name'] for i in answers]
+            subject = answers[0]['a.name']
+            final_answer = '{0}的排故流程是:{1}'.format(
+                subject, ';'.join(list(set(desc))[:self.num_limit]))
+
+        elif question_type == 'entity_desc':
+            subject = answers[0]['c.name']
+            result = {}
+
+            for answer in answers:
+                rel_name = answer['rel_name']
+                target_node_name = answer['target_nodes']
+                if rel_name not in result:
+                    result[rel_name] = []
+                result[rel_name].append(target_node_name)
+
+            answer_list = []
+            for key in result:
+                if result[key]:
+                    desc = '、'.join(result[key][0])
+                    answer_list.append('{0}{1}有:{2}'.format(subject, key, desc))
+            final_answer = ';\n'.join(answer_list)
+
+        elif question_type == 'entity_desc1':
+            subject = answers[0]['a.name']
+            result = {}
+
+            for answer in answers:
+                rel_name = answer['rel_name']
+                source_node_name = answer['source_nodes']
+                if rel_name not in result:
+                    result[rel_name] = []
+                result[rel_name].append(source_node_name)
+
+            answer_list = []
+            for key in result:
+                if result[key]:
+                    desc = '、'.join(result[key][0])
+                    answer_list.append('{0}被发出的{1}关系有:{2}'.format(subject, key, desc))
+            final_answer = ';'.join(answer_list)
+
+        return final_answer
+
+
+if __name__ == '__main__':
+    searcher = AnswerSearcher()

+ 38 - 0
chatbot_graph.py

@@ -0,0 +1,38 @@
+
+from question_classifier import *
+from question_parser import *
+from answer_search import *
+from process import process
+'''问答类'''
+
+
+class ChatBotGraph:
+    def __init__(self):
+        self.classifier = QuestionClassifier()
+        self.parser = QuestionParser()
+        self.searcher = AnswerSearcher()
+        
+
+    def chat_main(self, sent):
+        answer = '抱歉,我不知道'
+        if(";" in sent):
+            return process(sent)
+        res_classify = self.classifier.classify(sent)
+        if not res_classify:
+            answer = '完全找不到对应实体'
+            return answer
+        res_sql = self.parser.parser_main(res_classify)
+        final_answers = self.searcher.search_main(res_sql)
+        if not final_answers:
+            answer = '未查到' + list(res_classify['args'].keys())[0] +'对应的' + res_classify['question_types'][0]
+            return answer
+        else:
+            return '\n'.join(final_answers)
+
+
+if __name__ == '__main__':
+    handler = ChatBotGraph()
+    while 1:
+        question = input('用户:')
+        answer = handler.chat_main(question)
+        print('回答:', answer)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
data/medical.json


+ 5 - 0
dict/cause.txt

@@ -0,0 +1,5 @@
+液压2系统故障信号继电器故障
+飞机系统2号继电器盒X86插头松脱
+线路故障
+2号电传计算机故障
+电源线路短路

+ 2 - 0
dict/code.txt

@@ -0,0 +1,2 @@
+114514
+123456

+ 38 - 0
dict/deny.txt

@@ -0,0 +1,38 @@
+否
+非
+不
+无
+弗
+勿
+毋
+未
+没
+莫
+没有
+防止
+不再
+不会
+不能
+忌
+禁止
+防止
+难以
+忘记
+忽视
+放弃
+拒绝
+杜绝
+不是
+并未
+并无
+仍未
+难以出现
+切勿
+不要
+不可
+别
+管住
+注意
+小心
+少
+

+ 24 - 0
dict/entity.txt

@@ -0,0 +1,24 @@
+继电器失效
+液压告警灯熄灭
+再次进行电传PBIT测试,依旧报此故障
+液压2系统故障信号继电器故障
+飞机系统2号继电器盒X86插头松脱
+线路故障
+首先判读飞参,明确液压信号是否正常
+其次,连接检查仪,检查液压2良好信号
+再次,断开液压,飞机下电,检查平台系统2号继电器盒状态
+再次,平台下电,检查电缆阻值和继电器插头阻值
+114514
+维修
+液压2系统压力正常
+2号电传计算机故障
+自测试过程,报四个通道液压2良好信号故障,BIT故障灯亮
+电源故障
+飞机无法正常上电
+电源线路短路
+首先检查电源连接,确认连接正常
+其次,检查保险丝是否烧断
+再次,检查电源线路是否有短路现象
+123456
+维修
+飞机启动过程中突然断电

+ 2 - 0
dict/fault.txt

@@ -0,0 +1,2 @@
+继电器失效
+电源故障

+ 2 - 0
dict/level.txt

@@ -0,0 +1,2 @@
+维修
+维修

+ 2 - 0
dict/maintain.txt

@@ -0,0 +1,2 @@
+'首先判读飞参,明确液压信号是否正常\n其次,连接检查仪,检查液压2良好信号\n再次,断开液压,飞机下电,检查平台系统2号继电器盒状态\n再次,平台下电,检查电缆阻值和继电器插头阻值'
+'首先检查电源连接,确认连接正常\n其次,检查保险丝是否烧断\n再次,检查电源线路是否有短路现象'

+ 3 - 0
dict/parts.txt

@@ -0,0 +1,3 @@
+发动机
+继电器
+引擎

+ 6 - 0
dict/phenomenon.txt

@@ -0,0 +1,6 @@
+液压告警灯熄灭
+再次进行电传PBIT测试,依旧报此故障
+液压2系统压力正常
+自测试过程,报四个通道液压2良好信号故障,BIT故障灯亮
+飞机无法正常上电
+飞机启动过程中突然断电

+ 22 - 0
distance.py

@@ -0,0 +1,22 @@
+def edit_distance(text1, text2):
+    # 初始化矩阵
+    m = len(text1) + 1
+    n = len(text2) + 1
+    dp = [[0 for _ in range(n)] for _ in range(m)]
+
+    # 初始化第一行和第一列
+    for i in range(1, m):
+        dp[i][0] = i
+    for j in range(1, n):
+        dp[0][j] = j
+
+    # 计算编辑距离
+    for i in range(1, m):
+        for j in range(1, n):
+            if text1[i-1] == text2[j-1]:
+                dp[i][j] = dp[i-1][j-1]
+            else:
+                dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
+
+    # 返回编辑距离
+    return dp[-1][-1]

+ 102 - 0
get_entity.py

@@ -0,0 +1,102 @@
+from py2neo import Graph
+
+# Neo4j数据库连接信息
+uri = "bolt://localhost:7687"  # Neo4j数据库URI
+username = "neo4j"  # Neo4j数据库用户名
+password = "123456"  # Neo4j数据库密码
+
+# 连接Neo4j数据库
+graph = Graph(uri, auth=(username, password))
+
+query = "MATCH (n) RETURN n.name AS name"
+result = graph.run(query)
+
+# 将节点名称写入文件
+with open("./dict/entity.txt", "w",encoding = 'utf-8') as file:
+    for record in result:
+        name = record["name"]
+        file.write(name + "\n")
+
+# 获取所有标签为"故障代码"的节点的name属性,并保存到txt文件中
+def get_code():
+    query = "MATCH (n:故障代码) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [record["name"] for record in results]
+    
+    with open("./dict/code.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障代码已保存到code.txt文件中。")
+
+def get_fault():
+    query = "MATCH (n:故障名称) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [record["name"] for record in results]
+    
+    with open("./dict/fault.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障名称已保存到fault.txt文件中。")
+
+def get_phenomenon():
+    query = "MATCH (n:故障现象) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [record["name"] for record in results]
+    
+    with open("./dict/phenomenon.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障现象已保存到phenomenon.txt文件中。")
+
+def get_cause():
+    query = "MATCH (n:故障原因) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [record["name"] for record in results]
+    
+    with open("./dict/cause.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障原因已保存到cause.txt文件中。")
+
+def get_maintain():
+    query = "MATCH (n:故障流程) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [repr(record["name"]) for record in results]
+    
+    with open("./dict/maintain.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障现象已保存到maintain.txt文件中。")
+
+def get_level():
+    query = "MATCH (n:故障等级) RETURN n.name AS name"
+    results = graph.run(query)
+    names = [record["name"] for record in results]
+    
+    with open("./dict/level.txt", "w",encoding = 'utf-8') as file:
+        for name in names:
+            file.write(name + "\n")
+
+    print("故障等级已保存到level.txt文件中。")
+
+# 从txt文件中读取节点的name属性
+def read_nodes_from_file():
+    with open("./dict/maintain.txt", "r",encoding = 'utf-8') as file:
+        names = [eval(line.strip()) for line in file]
+
+    return names
+
+# 示例代码的执行
+get_code()  # 获取并保存节点到txt文件中
+get_cause()
+get_fault()
+get_level()
+get_maintain()
+get_phenomenon()
+node_names = read_nodes_from_file()  # 从txt文件中读取节点名称
+print("从txt文件中读取的节点名称:", node_names)

+ 21 - 0
jaccard.py

@@ -0,0 +1,21 @@
+#import numpy as np
+#from scipy.spatial.distance import pdist#直接调包可以计算JC值 :需要两个句子长度一样;所以暂时不用
+import jieba
+ 
+def Jaccrad(model, reference):#terms_reference为源句子,terms_model为候选句子
+    terms_reference= jieba.cut(reference)#默认精准模式
+    terms_model= jieba.cut(model)
+    grams_reference = set(terms_reference)#去重;如果不需要就改为list
+    grams_model = set(terms_model)
+    temp=0
+    for i in grams_reference:
+        if i in grams_model:
+            temp=temp+1#交集
+    fenmu=len(grams_model)+len(grams_reference)-temp #并集
+    jaccard_coefficient=float(temp/fenmu)
+    return jaccard_coefficient
+ 
+a="发动机灯亮"
+b="发动机灯变亮"
+jaccard_coefficient=Jaccrad(a,b)
+print(jaccard_coefficient)

+ 40 - 0
mapping.py

@@ -0,0 +1,40 @@
+import json
+import numpy as np
+from mapping1.onehot_generate import onehot_generate
+onehot_generate()
+# 从文件读取关键词与one-hot编码的字典
+with open("./mapping1/keyword_one_hot_dict.json", "r", encoding="utf-8") as json_file:
+    keyword_one_hot_dict = json.load(json_file)
+
+# 从文件读取故障现象词的向量字典
+with open("./mapping1/phenomenon_vector_dict.json", "r", encoding="utf-8") as json_file:
+    phenomenon_vector_dict = json.load(json_file)
+
+
+def mapping(sentence: str):
+    # 初始化词向量
+    sentence_vector = np.zeros(len(keyword_one_hot_dict[list(keyword_one_hot_dict.keys())[0]]), dtype=np.int32)
+
+    # 遍历关键词表,逐个查找关键词是否在句子中
+    for word in keyword_one_hot_dict.keys():
+        if word in sentence:
+            keyword_vector = np.array(keyword_one_hot_dict[word], dtype=np.int32)
+            sentence_vector += keyword_vector
+
+    # 判断是否有对应的故障现象
+    matched_phenomenon = None
+    for phenomenon, vector in phenomenon_vector_dict.items():
+        if np.array_equal(sentence_vector, vector):
+            matched_phenomenon = phenomenon
+            break
+
+    # 输出结果
+    if matched_phenomenon:
+        return(matched_phenomenon)
+    else:
+        return None
+
+
+# 输入句子
+#sentence = "液压2系统压力正常"
+#print(mapping(sentence))

BIN
mapping1/__pycache__/onehot_generate.cpython-37.pyc


BIN
mapping1/__pycache__/onehot_generate.cpython-39.pyc


+ 842 - 0
mapping1/keyword_one_hot_dict.json

@@ -0,0 +1,842 @@
+{
+    "PBIT": [
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "不灵敏": [
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "依旧": [
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "刹车": [
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "加速": [
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "压力正常": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "发动机": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "启动过程": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "噪音": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "失灵": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "异响": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "引擎": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "打不动": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "断电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "方向盘": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "无效": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "正常上电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "没电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "液压": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "液压2": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "漏油": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "灭": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "灯": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "点火": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0
+    ],
+    "爆胎": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0
+    ],
+    "电池": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0
+    ],
+    "轮胎": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0
+    ],
+    "飞机": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1
+    ]
+}

+ 35 - 0
mapping1/main.py

@@ -0,0 +1,35 @@
+import json
+import numpy as np
+
+# 从文件读取关键词与one-hot编码的字典
+with open("keyword_one_hot_dict.json", "r", encoding="utf-8") as json_file:
+    keyword_one_hot_dict = json.load(json_file)
+
+# 从文件读取故障现象词的向量字典
+with open("phenomenon_vector_dict.json", "r", encoding="utf-8") as json_file:
+    phenomenon_vector_dict = json.load(json_file)
+
+# 输入句子
+sentence = "液压2系统压力正常"
+
+# 初始化词向量
+sentence_vector = np.zeros(len(keyword_one_hot_dict[list(keyword_one_hot_dict.keys())[0]]), dtype=np.int32)
+
+# 遍历关键词表,逐个查找关键词是否在句子中
+for word in keyword_one_hot_dict.keys():
+    if word in sentence:
+        keyword_vector = np.array(keyword_one_hot_dict[word], dtype=np.int32)
+        sentence_vector += keyword_vector
+
+# 判断是否有对应的故障现象
+matched_phenomenon = None
+for phenomenon, vector in phenomenon_vector_dict.items():
+    if np.array_equal(sentence_vector, vector):
+        matched_phenomenon = phenomenon
+        break
+
+# 输出结果
+if matched_phenomenon:
+    print("故障现象:", matched_phenomenon)
+else:
+    print("无")

+ 102 - 0
mapping1/mapping.json

@@ -0,0 +1,102 @@
+[
+    {
+        "keywords": [
+            "飞机",
+            "正常上电"
+        ],
+        "phenomenon": "飞机无法正常上电"
+    },
+    {
+        "keywords": [
+            "飞机",
+            "启动过程",
+            "断电"
+        ],
+        "phenomenon": "飞机启动过程中突然断电"
+    },
+    {
+        "keywords": [
+            "液压2",
+            "压力正常"
+        ],
+        "phenomenon": "液压2系统压力正常"
+    },
+    {
+        "keywords": [
+            "液压",
+            "灯",
+            "灭"
+        ],
+        "phenomenon": "液压告警灯熄灭"
+    },
+    {
+        "keywords": [
+            "PBIT",
+            "依旧"
+        ],
+        "phenomenon": "再次进行电传PBIT测试,依旧报此故障"
+    },
+    {
+        "keywords": [
+            "电池",
+            "没电"
+        ],
+        "phenomenon": "电池没电"
+    },
+    {
+        "keywords": [
+            "刹车",
+            "失灵"
+        ],
+        "phenomenon": "刹车失灵"
+    },
+    {
+        "keywords": [
+            "方向盘",
+            "打不动"
+        ],
+        "phenomenon": "方向盘打不动"
+    },
+    {
+        "keywords": [
+            "加速",
+            "不灵敏"
+        ],
+        "phenomenon": "加速不灵敏"
+    },
+    {
+        "keywords": [
+            "发动机",
+            "漏油"
+        ],
+        "phenomenon": "发动机漏油"
+    },
+    {
+        "keywords": [
+            "轮胎",
+            "爆胎"
+        ],
+        "phenomenon": "轮胎爆胎"
+    },
+    {
+        "keywords": [
+            "点火",
+            "无效"
+        ],
+        "phenomenon": "点火无效"
+    },
+    {
+        "keywords": [
+            "引擎",
+            "异响"
+        ],
+        "phenomenon": "引擎异响"
+    },
+    {
+        "keywords": [
+            "刹车",
+            "噪音"
+        ],
+        "phenomenon": "刹车噪音"
+    }
+]

+ 78 - 0
mapping1/mapping_generate.py

@@ -0,0 +1,78 @@
+import json
+
+# 保存多个映射关系到 JSON 文件
+data = [
+    {
+        "keywords": [
+            "飞机",
+            "正常上电"
+        ],
+        "phenomenon": "飞机无法正常上电"
+    },
+    {
+        "keywords": [
+            "飞机",
+            "启动过程",
+            "断电"
+        ],
+        "phenomenon": "飞机启动过程中突然断电"
+    },
+    {
+        "keywords": ["液压2","压力正常"],
+        "phenomenon": "液压2系统压力正常"
+    },
+    {
+        "keywords": ["液压","灯", "灭"],
+        "phenomenon": "液压告警灯熄灭"
+    },
+    {
+        "keywords": ["PBIT", "依旧"],
+        "phenomenon": "再次进行电传PBIT测试,依旧报此故障"
+    },
+    {
+        "keywords": ["电池", "没电"],
+        "phenomenon": "电池没电"
+    },
+    {
+        "keywords": ["刹车", "失灵"],
+        "phenomenon": "刹车失灵"
+    },
+    {
+        "keywords": ["方向盘", "打不动"],
+        "phenomenon": "方向盘打不动"
+    },
+    {
+        "keywords": ["加速", "不灵敏"],
+        "phenomenon": "加速不灵敏"
+    },
+    {
+        "keywords": ["发动机", "漏油"],
+        "phenomenon": "发动机漏油"
+    },
+    {
+        "keywords": ["轮胎", "爆胎"],
+        "phenomenon": "轮胎爆胎"
+    },
+    {
+        "keywords": ["点火", "无效"],
+        "phenomenon": "点火无效"
+    },
+    {
+        "keywords": ["引擎", "异响"],
+        "phenomenon": "引擎异响"
+    },
+    {
+        "keywords": ["刹车", "噪音"],
+        "phenomenon": "刹车噪音"
+    }
+]
+
+# 保存为 JSON 文件
+with open("./mapping.json", "w", encoding="utf-8") as json_file:
+    json.dump(data, json_file, ensure_ascii=False, indent=4)
+
+# 从文件读取
+with open("./mapping.json", "r", encoding="utf-8") as json_file:
+    loaded_data = json.load(json_file)
+
+print(loaded_data)

+ 55 - 0
mapping1/onehot_generate.py

@@ -0,0 +1,55 @@
+import json
+import numpy as np
+import os
+path = os.path.abspath(os.path.dirname(__file__))
+def onehot_generate():
+    # 从文件读取映射关系
+    with open(path + "/mapping.json", "r", encoding="utf-8") as json_file:
+        loaded_data = json.load(json_file)
+
+    # 提取关键词和故障现象
+    keywords_list = []
+    phenomenon_list = []
+
+    for mapping in loaded_data:
+        keywords_list.extend(mapping["keywords"])
+        phenomenon_list.append(mapping["phenomenon"])
+
+    # 生成关键词词表
+    vocabulary = sorted(set(keywords_list))
+
+    # 生成one-hot编码
+    one_hot_vectors = []
+    for word in vocabulary:
+        one_hot = [1 if word == w else 0 for w in vocabulary]
+        one_hot_vectors.append(one_hot)
+
+    # 转换为NumPy数组
+    one_hot_array = np.array(one_hot_vectors, dtype=np.int32)
+
+    # 生成关键词与one-hot编码的字典
+    keyword_one_hot_dict = {}
+    for i, word in enumerate(vocabulary):
+        keyword_one_hot_dict[word] = one_hot_array[i].tolist()
+
+    # 生成故障现象词的向量
+    phenomenon_vectors = []
+    for phenomenon in phenomenon_list:
+        vector_sum = np.zeros(len(vocabulary), dtype=np.int32)
+        for keyword in keywords_list:
+            if keyword in phenomenon:
+                vector_sum = np.logical_or(vector_sum, np.array(keyword_one_hot_dict[keyword], dtype=np.int32))
+        phenomenon_vectors.append(vector_sum.tolist())
+
+    # 创建故障现象词的向量字典
+    phenomenon_vector_dict = {}
+    for i, phenomenon in enumerate(phenomenon_list):
+        phenomenon_vector_dict[phenomenon] = [int(val) for val in phenomenon_vectors[i]]
+
+    # 保存关键词与one-hot编码的字典为JSON文件
+    with open(path + "/keyword_one_hot_dict.json", "w", encoding="utf-8") as json_file:
+        json.dump(keyword_one_hot_dict, json_file, ensure_ascii=False, indent=4)
+
+    # 保存故障现象词的向量字典为JSON文件
+    with open(path + "/phenomenon_vector_dict.json", "w", encoding="utf-8") as json_file:
+        json.dump(phenomenon_vector_dict, json_file, ensure_ascii=False, indent=4)

+ 422 - 0
mapping1/phenomenon_vector_dict.json

@@ -0,0 +1,422 @@
+{
+    "飞机无法正常上电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1
+    ],
+    "飞机启动过程中突然断电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1
+    ],
+    "液压2系统压力正常": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "液压告警灯熄灭": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        1,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "再次进行电传PBIT测试,依旧报此故障": [
+        1,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "电池没电": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0
+    ],
+    "刹车失灵": [
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "方向盘打不动": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "加速不灵敏": [
+        0,
+        1,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "发动机漏油": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "轮胎爆胎": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        1,
+        0
+    ],
+    "点火无效": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0
+    ],
+    "引擎异响": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ],
+    "刹车噪音": [
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+    ]
+}

+ 23 - 0
mapping1/step2.py

@@ -0,0 +1,23 @@
+import json
+
+def create_one_hot_encoding(vocabulary, word):
+    encoding = [0] * len(vocabulary)
+    if word in vocabulary:
+        encoding[vocabulary[word]] = 1
+    return encoding
+
+# 读取文本文件中的词表(使用 UTF-8 编码)
+with open("./vocabulary.txt", "r", encoding="utf-8") as file:
+    loaded_vocabulary = [word.strip() for word in file.readlines()]
+
+# 创建词汇表字典
+vocabulary_dict = {word: index for index, word in enumerate(loaded_vocabulary)}
+
+# 创建 one-hot 编码字典
+one_hot_dict = {word: create_one_hot_encoding(vocabulary_dict, word) for word in vocabulary_dict}
+
+# 保存为 JSON 文件(使用 UTF-8 编码)
+with open("./one_hot_dict.json", "w", encoding="utf-8") as json_file:
+    json.dump(one_hot_dict, json_file, ensure_ascii=False)
+
+print(one_hot_dict)

+ 12 - 0
mapping1/vocabulary.py

@@ -0,0 +1,12 @@
+vocabulary = ["客舱", "着火", "发动机"]
+
+# 写入到文件
+with open("./vocabulary.txt", "w", encoding="utf-8") as file:
+    for word in vocabulary:
+        file.write(word + "\n")
+
+# 从文件读取
+with open("./vocabulary.txt", "r", encoding="utf-8") as file:
+    loaded_vocabulary = [word.strip() for word in file.readlines()]
+
+print(loaded_vocabulary)

+ 110 - 0
process.py

@@ -0,0 +1,110 @@
+import re
+from mapping import mapping 
+from py2neo import Graph
+
+#text = "飞机启动过程中断电;飞机正常上电失败怎么解决"
+#text = "液压告警灯灭;液压2系统压力正常的原因"
+#text = "继电器失效;电源故障"
+
+cause_qwds = ['原因','成因', '为什么', '怎么会',  '怎样会', '为啥', '为何']
+solve_qwds = ['怎么解决','怎么处理','怎么修理','怎么修复','怎么维修','解决方法','处理方法','修理方法','修复方法','维修方法','怎么修','咋修','怎么办','处置']
+with open("./dict/fault.txt", 'r',encoding='utf-8') as file:
+    lines = file.readlines()
+        # 去除每行末尾的换行符并拆分为词
+faults = []
+for line in lines:
+    line = line.strip()  # 去除换行符
+    words = line.split()  # 拆分为词
+    faults.extend(words)  # 添加到数组
+def check_words(wds, sent):
+        for wd in wds:
+            if wd in sent:
+                return True
+        return False
+
+def process(text):
+    # 使用正则表达式按中文分号拆分句子
+    sentences1 = re.split(";", text)
+
+    # 去除空白字符
+    sentences = [s.strip() for s in sentences1 if s.strip()]
+
+    entities = []
+    for sentence in sentences:
+        result = mapping(sentence)
+        if(result != None):
+            entities.append(result)
+
+    #print(entities)
+
+    # 连接 Neo4j 数据库
+    graph = Graph("bolt://localhost:7687", auth=("neo4j", "123456"))
+    answer = ""
+    query = ""
+    #entities = ["液压2系统压力正常", "液压告警灯熄灭","再次进行电传PBIT测试,依旧报此故障"]
+    if(check_words(solve_qwds, text)):
+        if(entities == []):
+            return"未找到对应实体"
+        for i in entities:
+            query += "MATCH (a)-[:故障现象]->(:故障现象{name:'" + i + "'}) "
+
+        query += "MATCH (a)-[:排故流程]->(b:故障流程) RETURN a, b"
+
+        #print(query)
+
+        # 构建 Cypher 查询语句
+        #query = "MATCH (a:故障名称)-[:故障原因]->(:故障原因{name:'2号电传计算机故障'}), (a)-[:故障现象]->(:故障现象{name:'液压告警灯熄灭'}) MATCH (a)-[:排故流程]->(b:故障流程) RETURN a,b"
+
+        # 执行查询
+        result = graph.run(query, entities=entities)
+
+        
+
+        # Process the query result
+        for record in result:
+            fault_name = record['a']['name']
+            fault_process = record['b']['name']
+            answer += fault_name + "的排故流程是:\n" + fault_process + "\n"
+            #print(f"故障名称: {fault_name}")
+            #print(f"排故流程: {fault_process}")
+
+    elif(check_words(faults, text)):
+        for i in sentences:
+            query = "MATCH (a:故障名称{name:'" + i +"'})-[:排故流程]->(b:故障流程) RETURN a, b"
+            result = graph.run(query, entities=entities)
+            for record in result:
+                fault_name = record['a']['name']
+                fault_process = record['b']['name']
+                answer += fault_name + "的排故流程是:\n" + fault_process + "\n"
+
+    
+    elif(check_words(cause_qwds, text)):
+        if(entities == []):
+            return"未找到对应实体"
+        for i in entities:
+            query += "MATCH (a)-[:故障现象]->(:故障现象{name:'" + i + "'}) "
+
+        query += "MATCH (a)-[:故障原因]->(b:故障原因) RETURN a, b"
+
+        #print(query)
+
+        # 构建 Cypher 查询语句
+        #query = "MATCH (a:故障名称)-[:故障原因]->(:故障原因{name:'2号电传计算机故障'}), (a)-[:故障现象]->(:故障现象{name:'液压告警灯熄灭'}) MATCH (a)-[:排故流程]->(b:故障流程) RETURN a,b"
+
+        # 执行查询
+        result = graph.run(query, entities=entities)
+
+        for i in entities:
+            answer += i
+        answer += "的原因是:\n"
+        # Process the query result
+        for record in result:
+            fault_process = record['b']['name']
+            answer += fault_process + "\n"
+            #print(f"故障名称: {fault_name}")
+            #print(f"排故流程: {fault_process}")
+    
+    return answer
+
+#print(process(text))
+

+ 166 - 0
question_classifier.py

@@ -0,0 +1,166 @@
+
+import os
+import ahocorasick
+class QuestionClassifier:
+    def __init__(self):
+        cur_dir = '/'.join(os.path.abspath(__file__).split('/')[:-1])
+        # 特征词路径
+        self.entity_path = os.path.join(cur_dir, 'dict/entity.txt')
+        self.fault_path = os.path.join(cur_dir, 'dict/fault.txt')
+        self.parts_path = os.path.join(cur_dir, 'dict/parts.txt')
+        self.deny_path = os.path.join(cur_dir, 'dict/deny.txt')
+        # 加载特征词
+        self.entity_wds= [i.strip() for i in open(self.entity_path, encoding='utf-8') if i.strip()]
+        self.region_words = set(self.entity_wds)
+        self.deny_words = [i.strip() for i in open(self.deny_path,encoding='utf-8') if i.strip()]
+        # 构造领域actree
+        self.region_tree = self.build_actree(list(self.region_words))
+        # 构建词典
+        self.wdtype_dict = self.build_wdtype_dict()
+        # 问句疑问词
+        self.cause_qwds = ['原因','成因', '为什么', '怎么会',  '怎样会', '如何会', '为啥', '为何']
+        self.solve_qwds = ['解决','处理','修理','修复','维修','怎么修','咋修','怎么办']
+        
+        with open(self.fault_path, 'r',encoding='utf-8') as file:
+            lines = file.readlines()
+        # 去除每行末尾的换行符并拆分为词
+        self.faults = []
+        for line in lines:
+            line = line.strip()  # 去除换行符
+            words = line.split()  # 拆分为词
+            self.faults.extend(words)  # 添加到数组
+
+        with open(self.parts_path, 'r',encoding='utf-8') as file:
+            lines = file.readlines()
+        # 去除每行末尾的换行符并拆分为词
+        self.parts = []
+        for line in lines:
+            line = line.strip()  # 去除换行符
+            words = line.split()  # 拆分为词
+            self.parts.extend(words)  # 添加到数组
+        
+        print('model init finished ......')
+
+        return
+
+    '''分类主函数'''
+    def classify(self, question):
+        data = {}
+        max = 100.0
+        cur = ''
+        for i in self.entity_wds:
+            score = edit_distance(question, i)
+            if(score <= max):
+                if(score == max and len(i) < len(cur)):
+                    continue
+                cur = i
+                max = score
+        if(max == len(cur) + len(question)):return{}
+        medical_dict = {cur:['entity']}
+
+        data['args'] = medical_dict
+        #收集问句当中所涉及到的实体类型
+        types = ['entity']
+        #for type_ in medical_dict.values():
+        #    types += type_
+        question_type = 'others'
+
+        question_types = []
+
+        # 故障
+        if self.check_words(self.faults, question) and ('entity' in types):
+            question_type = 'solve'
+            question_types.append(question_type)
+
+        # 原因
+        if self.check_words(self.cause_qwds, question) and ('entity' in types):
+            question_type = 'entity_cause'
+            question_types.append(question_type)
+
+        if self.check_words(self.parts, question) and ('entity' in types):
+            question_type = 'parts'
+            question_types.append(question_type)
+
+        
+        #解决
+        if self.check_words(self.solve_qwds, question) and ('entity' in types):
+            question_type = 'solve'
+            question_types.append(question_type)
+
+        # 若没有查到相关的外部查询信息,那么则将描述信息返回
+        if question_types == [] and 'entity' in types:
+            question_types = ['entity_desc', 'entity_desc1']
+
+        # 将多个分类结果进行合并处理,组装成一个字典
+        data['question_types'] = question_types
+
+        return data
+
+    '''构造词对应的类型'''
+    def build_wdtype_dict(self):
+        wd_dict = dict()
+        for wd in self.region_words:
+            wd_dict[wd] = []
+            if wd in self.entity_wds:
+                wd_dict[wd].append('entity')
+        return wd_dict
+
+    '''构造actree,加速过滤'''
+    def build_actree(self, wordlist):
+        actree = ahocorasick.Automaton()
+        for index, word in enumerate(wordlist):
+            actree.add_word(word, (index, word))
+        actree.make_automaton()
+        return actree
+
+    '''问句过滤'''
+    def check_medical(self, question):
+        region_wds = []
+        for i in self.region_tree.iter(question):
+            wd = i[1][1]
+            region_wds.append(wd)
+        stop_wds = []
+        for wd1 in region_wds:
+            for wd2 in region_wds:
+                if wd1 in wd2 and wd1 != wd2:
+                    stop_wds.append(wd1)
+        final_wds = [i for i in region_wds if i not in stop_wds]
+        final_dict = {i:self.wdtype_dict.get(i) for i in final_wds}
+
+        return final_dict
+
+    '''基于特征词进行分类'''
+    def check_words(self, wds, sent):
+        for wd in wds:
+            if wd in sent:
+                return True
+        return False
+
+def edit_distance(text1, text2):
+    # 初始化矩阵
+    m = len(text1) + 1
+    n = len(text2) + 1
+    dp = [[0 for _ in range(n)] for _ in range(m)]
+
+    # 初始化第一行和第一列
+    for i in range(1, m):
+        dp[i][0] = i
+    for j in range(1, n):
+        dp[0][j] = j
+
+    # 计算编辑距离
+    for i in range(1, m):
+        for j in range(1, n):
+            if text1[i-1] == text2[j-1]:
+                dp[i][j] = dp[i-1][j-1]
+            else:
+                dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1
+
+    # 返回编辑距离
+    return dp[-1][-1]
+if __name__ == '__main__':
+    handler = QuestionClassifier()
+    while 1:
+        question = input('input an question:')
+        data = handler.classify(question)
+        print(data)

+ 85 - 0
question_parser.py

@@ -0,0 +1,85 @@
+
+class QuestionParser:
+
+    '''构建实体节点'''
+    def build_entitydict(self, args):
+        entity_dict = {}
+        for arg, types in args.items():
+            for type in types:
+                if type not in entity_dict:
+                    entity_dict[type] = [arg]
+                else:
+                    entity_dict[type].append(arg)
+
+        return entity_dict
+
+    '''解析主函数'''
+    def parser_main(self, res_classify):
+        args = res_classify['args']
+        entity_dict = self.build_entitydict(args)
+        question_types = res_classify['question_types']
+        sqls = []
+        for question_type in question_types:
+            sql_ = {}
+            sql_['question_type'] = question_type
+            sql = []
+            if question_type == 'parts':
+                sql = self.sql_transfer(question_type, entity_dict.get('entity'))
+
+            elif question_type == 'entity_cause':
+                sql = self.sql_transfer(question_type, entity_dict.get('entity'))
+
+            elif question_type == 'solve':
+                sql = self.sql_transfer(question_type, entity_dict.get('entity'))
+            
+            elif question_type == 'entity_desc':
+                sql = self.sql_transfer(question_type, entity_dict.get('entity'))
+            
+            elif question_type == 'entity_desc1':
+                sql = self.sql_transfer(question_type, entity_dict.get('entity'))
+
+
+
+            if sql:
+                sql_['sql'] = sql
+
+                sqls.append(sql_)
+
+        return sqls
+
+    '''针对不同的问题,分开进行处理'''
+    def sql_transfer(self, question_type, entities):
+        if not entities:
+            return []
+
+        # 查询语句
+        sql = []
+        # 查询故障的原因
+        if question_type == 'entity_cause':
+            sql = ["MATCH (a:故障现象{{name:'{0}'}})<-[:故障现象]-(b)-[:故障原因]->(c:故障原因) RETURN a.name, c.name ".format(i) for i in entities]
+            #sql = ["MATCH (e1:Entity {{name: '{0}'}})-[:Relation]->(e2:Entity {{name: '{1}'}}) MATCH (e2)-[r1:Relation {{name: '故障原因'}}]->(e3:Entity) MATCH (e3)-[r2:Relation {{name: '部件故障'}}]->(e4:Entity) RETURN e1.name + e2.name, e3.name + e4.name".format(entities[0], entities[1])]
+
+        # 查询部件的组成
+        elif question_type == 'parts':
+            sql = ["MATCH (n {{name: '{0}'}})-[r1:Relation {{name: '包含'}}]->(m)RETURN n.name, m.name".format(i) for i in entities]
+
+        # 查询故障的解决方法
+        elif question_type == 'solve':
+            sql = ["MATCH (a:故障名称{{name:'{0}'}}) -[:排故流程]->(c:故障流程) RETURN a.name, c.name ".format(i) for i in entities]
+
+        elif question_type == 'entity_desc':
+            sql = ["MATCH (n:Entity {{name: '{0}'}})-[r:Relation]->(m) WITH n, r.name AS rel_name, COLLECT(m.name) AS target_nodes RETURN n.name, rel_name, target_nodes".format(i) for i in entities]
+            
+        
+        elif question_type == 'entity_desc1':
+            sql = ["MATCH (n)-[r:Relation]->(m:Entity {{name: '{0}'}})WITH m, r.name AS rel_name, COLLECT(n.name) AS source_nodes RETURN m.name, rel_name, source_nodes".format(i) for i in entities]
+        # 已知检查查询故障
+        #elif question_type == 'check_entity':
+        #    sql = ["MATCH (m:Entity)-[r:need_check]->(n:Check) where n.name = '{0}' return m.name, r.name, n.name".format(i) for i in entities]
+
+        return sql
+
+
+
+if __name__ == '__main__':
+    handler = QuestionParser()

+ 27 - 0
test.py

@@ -0,0 +1,27 @@
+from py2neo import Graph
+
+# 连接 Neo4j 数据库
+graph = Graph("bolt://localhost:7687", auth=("neo4j", "123456"))
+
+entities = ["液压2系统压力正常", "液压告警灯熄灭", "再次进行电传PBIT测试,依旧报此故障"]
+
+query = ""
+for i in entities:
+    query += "MATCH (a)-[:故障现象]->(:故障现象{name:'" + i + "'}) "
+
+query += "MATCH (a)-[:排故流程]->(b:故障流程) RETURN b.name"
+
+print(query)
+
+
+# 构建 Cypher 查询语句
+#query = "MATCH (a:故障名称)-[:故障原因]->(:故障原因{name:'2号电传计算机故障'}), (a)-[:故障现象]->(:故障现象{name:'液压告警灯熄灭'}) MATCH (a)-[:排故流程]->(b:故障流程) RETURN a,b"
+
+# 执行查询
+result = graph.run(query)
+
+
+# Process the query result
+for record in result:
+    fault_process = record['b.name']
+    print(f"排故流程: {fault_process}")

+ 6 - 0
说明.txt

@@ -0,0 +1,6 @@
+故障原因:为什么xxxxx;xxxxx是什么原因;
+故障影响:xxxx有什么后果;xxxx有什么影响;xxxx会怎么样;xxxx会造成什么
+组成:xxxx有什么零件;xxxx由什么组成;xxxx包含什么
+维修方法:xxxx怎么修;xxxx处理方法;xxxx怎么解决
+检测工具:xxxx的检测工具;xxxx的测试工具;xxxx怎么诊断;
+部件故障:xxxx有什么故障;xxxx会有什么问题

Некоторые файлы не были показаны из-за большого количества измененных файлов