人脸识别与大模型问答
This commit is contained in:
parent
6c7c1c7fb9
commit
460991d615
|
|
@ -550,7 +550,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style vars="{{PicNum}}">
|
<style lang="scss" vars="{{PicNum}}">
|
||||||
@import url('./../../assets/styles/SurveillanceVideo.css');
|
@import url('./../../assets/styles/SurveillanceVideo.css');
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
<div class="main-left-list">
|
<div class="main-left-list">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div
|
<div
|
||||||
:class="windowId === item.windowId ? 'group-item group-item-selected':'group-item group-item-noSelected'"
|
:class="windowId == item.windowId ? 'group-item group-item-selected':'group-item group-item-noSelected'"
|
||||||
v-for="(item, index) in windowList" :key="index">
|
v-for="(item, index) in windowList" :key="index" @mousedown="switchWindow(item.windowId)">
|
||||||
<span @click="switchWindow(item.windowId)">{{ item.windowName }}</span>
|
<span>{{ item.windowName }}</span>
|
||||||
<i
|
<i
|
||||||
class="el-icon-delete" @click="deleteChatWindow(item.windowId)"
|
class="el-icon-delete" @click="deleteChatWindow(item.windowId)"
|
||||||
></i>
|
></i>
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="main-right">
|
<div class="main-right">
|
||||||
<div class="main-right-top">
|
<div class="main-right-top">
|
||||||
<div class="main-right-top-body">
|
<div class="main-right-top-body" ref="messageContainer">
|
||||||
<div class="main" v-for="(item, index) in answerList" :key="index">
|
<div class="main" v-for="(item, index) in answerList" :key="index">
|
||||||
<div class="problem">
|
<div class="problem">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img src="../../assets/images/answer.png" alt=""/>
|
<img src="../../assets/images/answer.png" alt=""/>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content" v-html="item.answer">
|
||||||
<span>{{ item.answer }}</span>
|
<!-- <span>{{ item.answer }}</span>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,135 +67,246 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import boxHeader from '@/views/components/boxHeader.vue'
|
import boxHeader from '@/views/components/boxHeader.vue';
|
||||||
import dialogue from '@/views/askRequest/dialogue.vue'
|
import dialogue from '@/views/askRequest/dialogue.vue';
|
||||||
import diagHistory from '@/views/askRequest/diagHistory.vue'
|
import diagHistory from '@/views/askRequest/diagHistory.vue';
|
||||||
import {
|
import {
|
||||||
deleteChatWindow,
|
deleteChatWindow,
|
||||||
getAllByWindowId,
|
getAllByWindowId,
|
||||||
getList,
|
getList,
|
||||||
insertChatWindow,
|
insertChatWindow,
|
||||||
insertQuestionAnswer,
|
insertQuestionAnswer
|
||||||
knowledgeBaseChat
|
} from '@/api/askRequest/askRequest';
|
||||||
} from '@/api/askRequest/askRequest'
|
import {v4 as uuidv4} from 'uuid';
|
||||||
import faceListShowPic from "@/views/updateFace/faceListShowPic.vue";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
// 注册组件
|
||||||
components: {
|
components: {
|
||||||
boxHeader,
|
boxHeader,
|
||||||
dialogue,
|
dialogue,
|
||||||
diagHistory
|
diagHistory
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 定义组件的数据
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
controller: '',
|
controller: new AbortController(), // 用于控制Fetch请求的中止信号
|
||||||
windowId: '',
|
windowId: '', // 当前窗口ID
|
||||||
windowList: [],
|
windowList: [], // 窗口列表
|
||||||
answerList: [],
|
answerList: [], // 回答列表
|
||||||
inputValue: '',
|
inputValue: '', // 输入框的值
|
||||||
isSearch: false,
|
isAncestor: false
|
||||||
value: '',
|
};
|
||||||
diagContentTmpMain: ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 当组件挂载时执行的逻辑
|
||||||
|
mounted() {
|
||||||
|
//this.getList(); // 获取窗口列表
|
||||||
|
this.loadLastWindowId(); // 加载最近访问的窗口ID
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当组件创建时执行的逻辑
|
||||||
created() {
|
created() {
|
||||||
this.controller = new AbortController();
|
this.getList(); // 获取窗口列表
|
||||||
this.getList();
|
|
||||||
},
|
},
|
||||||
|
// 监听器,监听windowId的变化
|
||||||
watch: {
|
watch: {
|
||||||
windowId(val) {
|
windowId(newWindowId) {
|
||||||
if (val) {
|
this.getAllByWindowId(newWindowId);
|
||||||
this.getAllByWindowId(val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
// 生成一个新的窗口ID
|
||||||
|
generateNewWindowId() {
|
||||||
|
const lastWindowId = uuidv4().replace(/-/g, "");
|
||||||
|
this.windowId = lastWindowId
|
||||||
|
localStorage.setItem('lastWindowId', lastWindowId);// 生成UUID并去掉所有的“-”
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载最近访问的窗口ID
|
||||||
|
loadLastWindowId() {
|
||||||
|
const lastWindowId = localStorage.getItem('lastWindowId'); // 从本地存储中获取最近使用的窗口ID
|
||||||
|
if (lastWindowId) {
|
||||||
|
this.windowId = lastWindowId; // 如果存在,则设置为当前窗口ID
|
||||||
|
} else {
|
||||||
|
this.generateNewWindowId(); // 否则生成一个新的窗口ID
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 切换窗口时保存窗口ID
|
||||||
|
switchWindow(windowId) {
|
||||||
|
if (this.isAncestor) {
|
||||||
|
this.$message.warning("问答进行中");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem('lastWindowId', windowId); // 将当前窗口ID存储在本地存储中
|
||||||
|
this.windowId = windowId; // 切换到新的窗口ID
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取窗口列表
|
||||||
getList() {
|
getList() {
|
||||||
getList().then(res => {
|
getList().then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.windowList = res.data;
|
this.windowList = res.data; // 如果请求成功,设置窗口列表
|
||||||
if (res.data.length > 0) {
|
if (this.windowList.length === 0) {
|
||||||
this.windowId = res.data[0].windowId;
|
this.generateNewWindowId();
|
||||||
|
this.answerList = []; // 如果窗口列表为空,清空回答列表
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
|
||||||
switchWindow(windowId) {
|
|
||||||
this.windowId = windowId;
|
|
||||||
},
|
},
|
||||||
|
// 根据窗口ID获取所有聊天记录
|
||||||
getAllByWindowId(windowId) {
|
getAllByWindowId(windowId) {
|
||||||
getAllByWindowId(windowId).then(res => {
|
getAllByWindowId(windowId).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.answerList = res.data;
|
this.answerList = res.data; // 如果请求成功,设置回答列表
|
||||||
|
this.scrollToBottom(); // 滚动到聊天记录的底部
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 删除聊天窗口
|
||||||
deleteChatWindow(windowId) {
|
deleteChatWindow(windowId) {
|
||||||
|
if (this.isAncestor) {
|
||||||
|
this.$message.warning("问答进行中");
|
||||||
|
return;
|
||||||
|
}
|
||||||
deleteChatWindow(windowId).then(res => {
|
deleteChatWindow(windowId).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message.success("删除成功");
|
this.$message.success("删除成功"); // 显示删除成功的提示信息
|
||||||
this.getList();
|
this.getList(); // 重新获取窗口列表
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
insertChatWindow() {
|
|
||||||
if (!this.windowId) {
|
|
||||||
this.$message.warning("已经是最新窗口");
|
|
||||||
}
|
|
||||||
this.windowId = '';
|
|
||||||
this.answerList = [];
|
|
||||||
},
|
|
||||||
submitInput() {
|
|
||||||
if (!this.windowId) {
|
|
||||||
insertChatWindow({windowName: this.inputValue}).then(res => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
this.getList();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
insertQuestionAnswer().then(res => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
this.getList();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.resAnswer(this.inputValue)
|
|
||||||
this.inputValue = ""; // 清空输入框
|
|
||||||
},
|
|
||||||
async resAnswer(question) {
|
|
||||||
let params = {
|
|
||||||
"query": question,
|
|
||||||
"knowledge_base_name": "lzh",
|
|
||||||
"top_k": 6,
|
|
||||||
"score_threshold": 1,
|
|
||||||
"stream": true,
|
|
||||||
}
|
|
||||||
knowledgeBaseChat(params).then(response => {
|
|
||||||
const reader = response.data.getReader();
|
|
||||||
|
|
||||||
function read() {
|
// 插入新的聊天窗口
|
||||||
reader.read().then(({done, value}) => {
|
insertChatWindow() {
|
||||||
if (done) {
|
this.generateNewWindowId();
|
||||||
console.log('Stream complete');
|
this.answerList = [];// 生成一个新的窗口ID
|
||||||
return;
|
},
|
||||||
|
|
||||||
|
// 提交输入内容
|
||||||
|
submitInput() {
|
||||||
|
if (this.answerList.length === 0) {
|
||||||
|
// 如果当前窗口没有聊天记录,插入一个新的聊天窗口
|
||||||
|
insertChatWindow({windowName: this.inputValue, windowId: this.windowId}).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.getList(); // 更新窗口列表
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.resAnswer(this.inputValue); // 处理输入内容
|
||||||
|
this.inputValue = ""; // 清空输入框
|
||||||
|
},
|
||||||
|
|
||||||
|
// 滚动到底部
|
||||||
|
scrollToBottom() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const container = this.$refs.messageContainer; // 获取消息容器的引用
|
||||||
|
if (container) {
|
||||||
|
container.scrollTop = container.scrollHeight; // 将容器滚动到最底部
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理回答逻辑
|
||||||
|
async resAnswer(question) {
|
||||||
|
this.isAncestor = true;
|
||||||
|
// 创建初始回答数据
|
||||||
|
const data = {
|
||||||
|
answer: "正在思考。。。", // 初始回答内容
|
||||||
|
question: question, // 提交的问题
|
||||||
|
windowId: this.windowId, // 当前窗口ID
|
||||||
|
};
|
||||||
|
this.answerList.push(data); // 将初始回答数据添加到回答列表中
|
||||||
|
this.scrollToBottom(); // 滚动到底部
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
query: question, // 提交给后端的查询参数
|
||||||
|
knowledge_base_name: 'lzh', // 使用的知识库名称
|
||||||
|
stream: true, // 是否启用流式响应
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 创建一个Fetch请求,用于与后端进行通信
|
||||||
|
const signal = this.controller.signal;
|
||||||
|
const response = await fetch('/api/chat/knowledge_base_chat', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(params), // 将请求参数转换为JSON字符串
|
||||||
|
signal: signal, // 将中止信号添加到请求中
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`); // 如果请求失败,抛出错误
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body.getReader(); // 获取响应体的阅读器
|
||||||
|
const decoder = new TextDecoder(); // 创建一个TextDecoder用于将二进制数据解码为字符串
|
||||||
|
|
||||||
|
// 清空最后一个回答的内容,准备接收新的回答
|
||||||
|
this.answerList[this.answerList.length - 1].answer = "";
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const {done, value} = await reader.read(); // 读取流中的数据
|
||||||
|
if (done) break; // 如果数据读取完成,跳出循环
|
||||||
|
|
||||||
|
const decodedValue = decoder.decode(value); // 解码读取到的数据
|
||||||
|
|
||||||
|
// 分割数据,处理每个独立的消息
|
||||||
|
const messages = decodedValue.split('}{').map((msg, index, array) => {
|
||||||
|
if (index !== 0) msg = '{' + msg;
|
||||||
|
if (index !== array.length - 1) msg += '}';
|
||||||
|
return msg;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 解析并处理每个消息
|
||||||
|
messages.forEach((msg) => {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(msg);
|
||||||
|
if (json.answer) {
|
||||||
|
this.answerList[this.answerList.length - 1].answer += this.escapeHtml(json.answer); // 将解析出的回答内容添加到最后一个回答中
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('JSON parse error:', e); // 如果解析出错,输出错误信息
|
||||||
}
|
}
|
||||||
// 处理每个数据块
|
|
||||||
console.log(new TextDecoder("utf-8").decode(value));
|
|
||||||
// 继续读取
|
|
||||||
read();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
read();
|
// 将最终的问答数据插入到数据库中
|
||||||
}).catch(error => {
|
insertQuestionAnswer(this.answerList[this.answerList.length - 1]).then(res => {
|
||||||
console.error('Error:', error);
|
this.isAncestor = false;
|
||||||
});
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fetch error:', error); // 捕获请求错误并输出
|
||||||
|
}
|
||||||
|
},
|
||||||
|
escapeHtml(str) {
|
||||||
|
// 使用正则表达式转义特殊字符
|
||||||
|
return str.replace(/[&<>"']/g, (match) => {
|
||||||
|
switch (match) {
|
||||||
|
case '&':
|
||||||
|
return '&';
|
||||||
|
case '<':
|
||||||
|
return '<';
|
||||||
|
case '>':
|
||||||
|
return '>';
|
||||||
|
case '"':
|
||||||
|
return '"';
|
||||||
|
case "'":
|
||||||
|
return ''';
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
.main {
|
.main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
#main {
|
#main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {updateFace} from '@/api/updateFace/updateFace'
|
import {updateFace} from '@/api/updateFace/updateFace'
|
||||||
|
import midPic from "@/views/updateFace/midPic.vue";
|
||||||
|
import faceListShowPic from "@/views/updateFace/faceListShowPic.vue";
|
||||||
|
|
||||||
const validationRules = {
|
const validationRules = {
|
||||||
name: [
|
name: [
|
||||||
|
|
@ -98,6 +100,7 @@ export default {
|
||||||
watch: {
|
watch: {
|
||||||
value(val) {
|
value(val) {
|
||||||
this.visible = val;
|
this.visible = val;
|
||||||
|
this.$emit('visible-change', val);
|
||||||
if (val) {
|
if (val) {
|
||||||
this.resetParameters(); // 每次打开时清除参数
|
this.resetParameters(); // 每次打开时清除参数
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +145,9 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.$emit('input', false);
|
faceListShowPic.methods.getList();
|
||||||
|
this.visible = false;
|
||||||
|
this.$emit('input', this.visible);
|
||||||
},
|
},
|
||||||
confirm() {
|
confirm() {
|
||||||
this.close();
|
this.close();
|
||||||
|
|
@ -161,7 +166,7 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="body-container">
|
<div class="body-container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="face_img" v-for="(item, index) in faceList" :key="index">
|
<div class="face_img" v-for="(item, index) in faceList" :key="index">
|
||||||
<img :src="item.faceAddress" class="face_img" alt="">/>
|
<img :src="'http://127.0.0.1:9300/'+item.faceAddress" class="face_img" alt="">/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -37,7 +37,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
/* 隐藏滚动条 */
|
/* 隐藏滚动条 */
|
||||||
.content::-webkit-scrollbar {
|
.content::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
<div class="bottom-right-content">
|
<div class="bottom-right-content">
|
||||||
<img
|
<img
|
||||||
v-if="faceUrl"
|
v-if="faceUrl"
|
||||||
:src="faceUrl"
|
:src="'http://127.0.0.1:9300/'+faceUrl"
|
||||||
class="avatar"
|
class="avatar"
|
||||||
alt="Avatar"
|
alt="Avatar"
|
||||||
/>
|
/>
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<addFace v-model="showModal" title="添加人脸" width="500px" @confirm="onConfirm">
|
<addFace v-model="showModal" title="添加人脸" width="500px" @visible-change="handleVisibleChange">
|
||||||
<p>这是弹窗的内容。</p>
|
<p>这是弹窗的内容。</p>
|
||||||
</addFace>
|
</addFace>
|
||||||
-->
|
-->
|
||||||
|
|
@ -101,10 +101,9 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
showModal(val) {
|
showModal(val) {
|
||||||
if (!val){
|
/* if (!val) {
|
||||||
faceListShowPic.methods.getList();
|
faceListShowPic.methods.getList();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -125,10 +124,9 @@ export default {
|
||||||
},
|
},
|
||||||
update() {
|
update() {
|
||||||
this.showModal = true
|
this.showModal = true
|
||||||
|
|
||||||
},
|
},
|
||||||
onConfirm() {
|
handleVisibleChange(newVal) {
|
||||||
|
this.showModal = newVal;
|
||||||
},
|
},
|
||||||
selectFile() {
|
selectFile() {
|
||||||
this.$refs.fileInput.click();
|
this.$refs.fileInput.click();
|
||||||
|
|
@ -144,7 +142,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
|
|
||||||
@keyframes moveandflash {
|
@keyframes moveandflash {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
#main {
|
#main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ module.exports = {
|
||||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/dev-api/api": {
|
"/api": {
|
||||||
"target": "http://192.168.0.21:17861",
|
"target": "http://192.168.0.21:17861",
|
||||||
//设置允许跨域——此处我经过测试发现可有可无
|
//设置允许跨域——此处我经过测试发现可有可无
|
||||||
"changeOrigin": true,
|
"changeOrigin": true,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue