现在基于gpt做自己项目的问答机器人,效果非常的好。可以把自己的文档上传上去,让机器人根据文档来进行回答。
想要实现智能AI问答功能,现在大部分都是基于向量数据库的形式。
整体的流程就是:上传文档===>openai向量接口 ====> 存入向量数据库
访客咨询: 咨询问题 ====> openai向量接口 ====>搜索向量数据库 ====> 组织prompt 到 openai的chat接口
下面的源码是前端逻辑,实现的界面以及问答的聊天对话效果,发送回复以及流式输出
效果图的前端源码
<template>
<div class="chatpdf">
<div class="pannel">
<div class="fileList">
<div class="fileTitle" v-bind:class="{'active': collect==item.name}" @click="selectCollect(item.name)" v-for="(item,index) in collects">
<svg t="1682317088056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1403" width="16" height="16"><path d="M512 64c259.2 0 469.333333 200.576 469.333333 448s-210.133333 448-469.333333 448a484.48 484.48 0 0 1-232.725333-58.88l-116.394667 50.645333a42.666667 42.666667 0 0 1-58.517333-49.002666l29.76-125.013334C76.629333 703.402667 42.666667 611.477333 42.666667 512 42.666667 264.576 252.8 64 512 64z m0 64C287.488 128 106.666667 300.586667 106.666667 512c0 79.573333 25.557333 155.434667 72.554666 219.285333l5.525334 7.317334 18.709333 24.192-26.965333 113.237333 105.984-46.08 27.477333 15.018667C370.858667 878.229333 439.978667 896 512 896c224.512 0 405.333333-172.586667 405.333333-384S736.512 128 512 128z m-157.696 341.333333a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z m159.018667 0a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z m158.997333 0a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z" fill="#ffffff" p-id="1404"></path></svg>
{{item.name}}</div>
</div>
</div>
<div class="chatpdfBox">
<div class="chatpdfLine">
<div class="chatpdfLineScroll">
<h1>欢迎使用知识库AI</h1>
<h2>由 AI 支持的网页版 Copilot</h2>
<div class="chatpdfRow " v-bind:class="{'chatpdfAsk': item.type=='ask'}" v-for="(item,index) in msgList">
<div class="chatpdfContent" v-html="html(item.content)"></div>
</div>
</div>
</div>
<div class="chatpdfArea">
<button @click="clearHistory">
<svg t="1682398861245" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1371" width="20" height="20"><path d="M883.2 403.2l-147.2-44.8 57.6-224c0-6.4 0-19.2-6.4-25.6-6.4-6.4-12.8-12.8-19.2-12.8L627.2 57.6c-6.4 0-19.2 0-25.6 0C595.2 70.4 588.8 76.8 588.8 83.2L524.8 300.8 358.4 256c-6.4 0-19.2 0-25.6 0S320 275.2 320 281.6l-89.6 320C211.2 684.8 128 768 128 768c-6.4 6.4-12.8 19.2-6.4 32 0 12.8 12.8 19.2 25.6 25.6l524.8 140.8c0 0 6.4 0 6.4 0 6.4 0 19.2-6.4 25.6-12.8 6.4-6.4 83.2-89.6 115.2-179.2 32-83.2 89.6-326.4 89.6-332.8C908.8 422.4 896 409.6 883.2 403.2zM755.2 748.8c-25.6 57.6-70.4 115.2-89.6 147.2l-70.4-19.2c32-38.4 70.4-96 89.6-160 6.4-19.2-6.4-32-25.6-38.4-19.2-6.4-32 6.4-38.4 25.6-19.2 70.4-76.8 134.4-96 153.6l-57.6-12.8c32-38.4 70.4-96 83.2-153.6 6.4-19.2-6.4-32-25.6-38.4-19.2-6.4-32 6.4-38.4 25.6-19.2 64-70.4 128-89.6 153.6l-64-19.2c32-38.4 70.4-96 89.6-153.6 6.4-19.2-6.4-32-25.6-38.4C384 608 364.8 620.8 364.8 633.6c-19.2 64-70.4 128-96 153.6l-57.6-19.2c32-38.4 70.4-96 83.2-153.6l76.8-294.4 166.4 44.8c6.4 0 19.2 0 25.6 0C569.6 364.8 576 358.4 582.4 352L640 128l83.2 19.2-57.6 224c-6.4 19.2 6.4 32 19.2 38.4L832 454.4C819.2 524.8 780.8 691.2 755.2 748.8z" p-id="1372" fill="#ffffff"></path><path d="M364.8 473.6C364.8 492.8 371.2 505.6 390.4 512l339.2 96c0 0 6.4 0 6.4 0 12.8 0 25.6-6.4 32-25.6 6.4-19.2-6.4-32-19.2-38.4L409.6 448C390.4 448 371.2 454.4 364.8 473.6z" p-id="1373" fill="#ffffff"></path>
</svg>
</button>
<textarea @keydown.prevent.enter="sendAsk" v-model="askContent"></textarea>
</div>
</div>
</div>
</template>
<script>
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import 'highlight.js/styles/monokai-sublime.css';
export default {
name: 'ChatPage',
data() {
return {
apiPost:"http://127.0.0.1:8083",
collects:[],
collect:"test",
askContent:"",
msgList:[
{type:"ask",content:"自建私有数据知识库 · 与知识库AI聊天"},
{type:"answer",content:"我是知识库机器人,一个专门响应人类指令的大模型"},
],
}
},
methods: {
sendAsk(){
if(this.askContent=="") return;
let msg={
'type':'ask',
'content':this.askContent,
}
this.msgList.push(msg);
let data=JSON.stringify(this.msgList);
localStorage.setItem("data_"+this.collect,data);
this.scrollBottom();
this.getReplyFromApi();
},
selectCollect(name){
this.collect=name;
this.msgList=[];
this.getHistory();
},
getCollects(){
let _this=this;
fetch(this.apiPost+'/collects', {
method: 'get',
})
.then((response) => response.json())
.then((response) => {
console.log(response);
_this.collects=response.result.collections;
})
},
getReplyFromApi(){
let _this=this;
let msg={
'type':'answer',
'content':"正在为你生成答案...",
}
_this.msgList.push(msg);
let i=0;
var xhr = new XMLHttpRequest();
xhr.open("GET", this.apiPost+"/"+this.collect+"/searchStream?keywords="+_this.askContent);
xhr.setRequestHeader("Content-Type", "text/html");
xhr.onprogress = function(event) {
console.log(i,event.currentTarget.responseText);
_this.msgList[_this.msgList.length-1].content=event.currentTarget.responseText;
_this.scrollBottom();
};
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
let data=JSON.stringify(this.msgList);
localStorage.setItem("data_"+this.collect,data);
}
};
xhr.send();
this.askContent="";
},
getHistory(name){
let str=localStorage.getItem("data_"+this.collect);
if(!str) return;
let data=JSON.parse(str);
this.msgList=data;
},
//滚动到底部
scrollBottom:function(){
var _this=this;
this.$nextTick(function(){
var container = _this.$el.querySelector(".chatpdfLine");
container.scrollTop = 999999999;
});
},
html(sourceStr) {
const md = new MarkdownIt({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return '<pre class="hljs"><code>' +
hljs.highlight(lang, str, true).value +
'</code></pre>';
} catch (__) {}
}
return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
}
});
return md.render(sourceStr);
},
clearHistory(){
localStorage.removeItem("data_"+this.collect);
this.msgList=[];
},
getQuery(key) {
// 获取所有参数
var query = window.location.search.substring(1);
var hash = window.location.hash.substring(1);
// 如果锚点后面有参数,把锚点后面的参数加入到search参数中
if(hash.indexOf("?") > -1){
query += "&" + hash.split("?")[1];
}
var key_values = query.split("&");
var params = {};
// 遍历参数并存入params对象
key_values.map(function (key_val){
var key_val_arr = key_val.split("=");
params[key_val_arr[0]] = key_val_arr[1];
});
// 如果找到了key对应的参数,返回对应值
if(typeof params[key]!="undefined"){
return params[key];
}
// 如果没找到,返回空字符串
return "";
}
},
mounted: function () {
let collect=this.getQuery("collect");
if(collect){
this.collect=collect;
}
this.getCollects();
this.getHistory();
}
}
</script>
<style>
.chatpdf{
display: flex;
height: 100vh;
flex-direction: row;
}
.chatpdf .pannel{
width: 255px;
background-color: rgb(0, 21, 41);
display: none;
}
.chatpdfBox{
display: flex;
flex-direction: column;
flex: 1;
background: linear-gradient(to bottom right,#dbe6fb, #f3f4f8);
background-size: cover;
background-attachment: fixed;
}
.chatpdfHeader{
font-size: 18px;
padding: 10px;
text-align: center;
width: 100%;
}
.chatpdfLine{
flex: 1;
width: 100%;
overflow-y: auto;
}
.chatpdfLine h1{
color: #111111;
text-align: center;
margin-top: 80px;
margin-bottom: 20px;
font-size: 36px;
}
.chatpdfLine h2{
color: #1e1e1e;
text-align: center;
font-size: 20px;
font-weight: 400;
}
.chatpdfLineScroll{
max-width: 1000px;
margin: 0 auto;
}
.chatpdfRow{
margin: 20px 10px;
display: flex;
}
.chatpdfAsk{
justify-content: flex-end;
}
.chatpdfContent{
line-height: 23px;
display: inline-block;
border-radius: 8px;
padding: 12px 15px;
max-width: 700px;
background: rgba(255, 255, 255, 0.6);
font-size: 14px;
box-shadow: 0px 0.3px 0.9px rgba(0, 0, 0, 0.12), 0px 1.6px 3.6px rgba(0, 0, 0, 0.16);
}
.chatpdfAsk .chatpdfContent{
background: linear-gradient(90deg, #2870EA 10.79%, #1B4AEF 87.08%);;
color: #fff;
}
.chatpdfContent pre{
padding: 10px;
}
.chatpdfArea{
display: flex;
margin-bottom: 10px;
max-width: 1000px;
margin: 0 auto;
width: 98%;
margin-bottom: 15px;
transition: all 0.3s,height 0s;
}
.chatpdfArea textarea{
flex: 1;
border: none;
resize: none;
outline: none;
padding: 0px 5px;
height: 40px;
line-height: 35px;
color: #404040;
border-radius: 10px;
box-shadow: 0px 0.3px 0.9px rgba(0, 0, 0, 0.12), 0px 1.6px 3.6px rgba(0, 0, 0, 0.08);
}
.chatpdfArea:hover{
border-color: #4096ff;
}
.chatpdfArea button{
height: 40px;
color: #fff;
background: linear-gradient(90deg, #1B4AEF 10.79%, #2870EA 87.08%);
box-shadow: 0 2px 0 rgba(5, 145, 255, 0.1);
border: none;
padding: 0 20px;
border-radius: 15px;
cursor: pointer;
box-shadow: 0px 0.3px 0.9px rgba(0, 0, 0, 0.12), 0px 1.6px 3.6px rgba(0, 0, 0, 0.08);
margin-right: 10px;
}
.chatpdfArea button:hover{
background-color: #388aff;
}
.chatpdf .fileTitle{
background-color: #1677ff;
color: #fff;
border-radius: 8px;
padding: 10px;
margin: 10px;
font-size: 14px;
cursor: pointer;
display: flex;
}
.chatpdf .fileTitle svg{
margin-right: 5px;
}
.chatpdf .fileTitle.active{
background-color: #66a6ff;
}
@media (max-width: 768px) {
.pannel{
display: none;
}
}
</style>
所有评论(0)