简介
完整项目资源链接:https://download.csdn.net/download/m0_46573428/87796553
项目详细信息请看:https://blog.csdn.net/m0_46573428/article/details/130071302
知识问答几乎是所有知识图谱应用里的重头戏,也花了我非常多的精力去写。
功能设计:输入问题,后台检索答案并返回。
主要代码
前端
Html
这段代码是一个Vue.js组件的模板(template),其中包含了网页界面的HTML代码。
该界面主要分为三个部分:
1. 头部信息 在div.head
元素中,有一个标题"小军智能问答助手"
2. 中间问答部分 在div.dialogue
元素中,包含了对话框。具体而言,它包含了两个子元素:
-
div.dialogue1
:用于展示已有的对话内容。其中包含了一个div.left
素,用于显示机器人的自我介绍,以及若干对话记录。 -
div.dialogue2
:用于编辑新的对话内容。其中包含了一个textarea
元素和一个按钮,分别用于编辑问题和发送问题。
3. 右侧栏 在div
元素中,定义了一个宽度为29%、高度为490px的元素。它包含了两个子元素:
-
第一个子元素:包含了一个标题"h2"和一个无序列表,用于列出常见的热点问题;
-
第二个子元素:包含了一个标题"h2"和一个无序列表,用于推荐相关的文章或内容。
<template>
<div style="padding-top: 8%">
<!-- 小军智能问答助手 -->
<div class="main">
<!-- head -->
<div class="head">
<span>小军智能问答助手</span>
</div>
<!-- 对话框 -->
<div class="dialogue">
<!-- 对话展示 -->
<div class="dialogue1" ref="messageContent">
<div class="left" style="margin-top: 20px">我是智能问答助手小军</div>
<div v-for="(item, index) in dialogue" :key="index" :class="item[0]">
{{ item[1] }}
</div>
</div>
<!-- 对话编辑 -->
<div class="dialogue2">
<textarea
v-model="question"
style="background: rgb(255 255 255 / 0%)"
></textarea>
<button @click="addRight()">发 送</button>
</div>
</div>
<!-- 右边栏 -->
<div style="height: 490px; width: 29%; float: left">
<div style="height: 50%">
<h2>热点问题</h2>
<ul>
<li>歼-11有哪些缺点?</li>
<li>歼-11有哪些缺点?</li>
<li>歼-11有哪些缺点?</li>
<li>歼-11有哪些缺点?</li>
</ul>
</div>
<div style="height: 50%">
<h2>相关推荐</h2>
<ul>
<li>歼-11</li>
<li>歼-20</li>
<li>XX战斗机</li>
<li>XX战斗机</li>
<li>XX战斗机</li>
</ul>
</div>
</div>
</div>
</div>
</template>
Script
这段代码是一个Vue.js的组件定义,主要实现了以下功能:
1. 定义了一个名称为"Query"的Vue组件,且不依赖于任何外部数据或属性(props
为空对象)。
2. 在data()
函数中定义了该组件的局部数据,包括:
-
question
: 用于绑定问题输入框的值; -
dialogue
: 用于保存对话记录的数组。 -
ans
: 用于保存服务器返回的问题回答结果。
3. 在methods
中定义了一个名为addRight()
的方法,用于在点击"发送"按钮后,将新的问题发送给服务器,并更新对话记录和回答结果。具体而言,该方法会:
-
将当前问题添加到
dialogue
数组中,显示在右侧(即"right"类)。 -
使用axios库向服务器发送GET请求,并传递问题字符串作为查询参数。
-
当接收到响应时,将其中的回答结果保存在
ans
变量中,并将其添加到dialogue
数组中,显示在左侧(即"left"类)。 -
当请求失败时,弹出提示窗口:"Query failed!"
-
清空问题输入框的值
-
最后使用nextTick()方法以确保滚动条在新消息到来时可以自动滚动到最底部。
<script>
export default {
name: "Query",
props: {},
data() {
return {
question: "",
dialogue: [
["right", "瓷器中的“罐丞”是什么?"],
[
"left",
"罐丞是一种可以用来保存食物或饮料的瓷器器皿。",
],
],
ans: "",
};
},
methods: {
addRight: function () {
this.dialogue.push(["right", this.question]);
this.axios
.get("http://localhost:8000/Query?question=" + this.question)
.then((res) => {
this.ans = res.data;
this.dialogue.push(["left", this.ans]);
console.log(this.ans);
})
.catch((error) => {
alert("Query failed!");
});
this.question = "";
// 让滚动条始终在最底部
this.$nextTick(() => {
this.$refs.messageContent.scrollTop =
this.$refs.messageContent.scrollHeight;
});
},
},
};
</script>
Css
<style scoped>
.main {
height: 550px;
width: 50%;
background: rgb(255 255 255 / 70%);
padding-top: 0%;
border-radius: 5px;
margin: auto;
box-shadow: rgb(0 0 0 / 20%) 0px 3px 10px;
}
li {
list-style: none;
}
.head {
border-radius: 5px 5px 0px 0px;
float: left;
width: 100%;
border-bottom: #e3e3e3 solid 1px;
}
.head > span {
float: left;
font-size: 20px;
line-height: 60px;
color: #486e53;
padding-left: 30px;
font-weight: bold;
}
.dialogue {
border-right: #e3e3e3 solid 1px;
height: 490px;
float: left;
width: 70%;
}
.dialogue1 {
height: 70%;
float: left;
width: 100%;
overflow-y: auto;
}
.dialogue1::-webkit-scrollbar {
width: 5px;
}
.dialogue1::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 5px;
}
.dialogue2 {
border-top: #e3e3e3 solid 1px;
height: 30%;
float: left;
width: 100%;
}
h2 {
color: #486e53;
margin: 15px;
float: left;
clear: both;
}
li {
width: 90%;
float: left;
padding-left: 15px;
padding-bottom: 5px;
color: #486e53;
}
.dialogue > div > button {
height: 35px;
width: 100px;
background: #eee;
float: right;
border: none;
border-radius: 5px;
color: #6da97e;
font-weight: bold;
margin-right: 20px;
}
.dialogue > div > textarea {
width: 93%;
height: 60px;
border: none;
resize: none;
padding: 15px;
outline: none;
}
.left {
float: left;
padding: 10px;
background: #486e53;
margin: 10px 20px 10px 20px;
clear: both;
color: white;
border-radius: 5px;
max-width: 400px;
font-size: 16px;
}
.right {
float: right;
padding: 10px;
background: #017db3;
margin: 10px 20px 10px 20px;
color: white;
border-radius: 5px;
text-align: right;
font-size: 16px;
max-width: 400px;
clear: both;
}
</style>
后端
这段代码实现了一个问题回答的功能,主要包括如下两部分:
-
属性类问题的回答 当输入的
query
中不含有问号"?"时,会解析出问题的主语(例如"歼-11")和属性(例如"翼长"), 然后从数据库中读取相关数据(即./data/china.txt
文件),在其中查找与主语和属性均相符的记录。 若找到了符合条件的记录,则返回其中的结果(即瓷器制作瑕疵);否则返回"Oops,数据库中暂时没有相关数据。" -
QA 问答形式的问题回答 当输入的
query
中含有问号"?"时,会将其与事先存储在./data/QA.txt
文件中的所有问题匹配,并计算匹配度。 若匹配度大于0.8,则返回对应的答案;否则返回"Oops,数据库中暂时没有相关数据。"
需要注意的是,对于属性类问题,该程序只能处理数据集中包含的内容,而对于QA形式的问题,其结果取决于词向量的匹配程度,因此可能存在不可靠或错误的答案。同时,该程序使用了一些具体的文件路径和数据格式,因此需要保证运行环境符合要求。
def Query(query):
"""
作用:将query进行处理,进行neo4j查询
输入:问答的query
输出:neo4j查询后返回的答案
"""
# 读取问答数据
with open(r'./data/QA.txt', 'r') as f:
lines = [line.strip() for line in f.readlines() if line.strip()]
odd_lines, even_lines = [], []
for i, line in enumerate(lines):
if i % 2 == 0:
even_lines.append(line)
else:
odd_lines.append(line)
QA = []
for i in range(len(even_lines)):
QA.append([even_lines[i],odd_lines[i]])
# 回答属性类问题
if '?' not in query:
ans = ''
with open(r'./data/china.txt', 'r') as f:
china_list = [line.strip().split(',') for line in f.readlines()]
q = query.split('的')
for i in china_list:
if q[0] == i[0]:
if q[1] == i[1]:
return i[2]
if ans == '':
return 'Oops,数据库中暂时没有相关数据。'
# 回答QA
else:
t = 0
ans = ''
for i in QA:
rate = string_similar(query, i[0])
if rate > t and rate > 0.8:
t = rate
ans = i[1]
if ans == '':
return 'Oops,数据库中暂时没有相关数据。'
else:
return ans
# print(Query('歼-11有哪些缺点?'))
# print(Query('歼-11的翼长'))