现在基于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>