kefu/static/templates/default/aigc.html

364 lines
16 KiB
HTML
Raw Permalink Normal View History

2024-12-10 02:50:12 +00:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>智能GPT创作系统</title>
<link rel="stylesheet" href="/static/cdn/element-ui/2.15.7/theme-chalk/index.min.css">
<script src="/static/cdn/vue/2.6.11/vue.min.js"></script>
<script src="/static/cdn/element-ui/2.15.7/index.js"></script>
<script src="/static/cdn/jquery/3.6.0/jquery.min.js"></script>
<script src="/static/cdn/jquery/jquery.qrcode.min.js"></script>
<script src="/static/js/functions.js"></script>
<script src="/static/js/chat-lang.js?v=1.0.1"></script>
<link rel="stylesheet" href="/static/css/aigc.css">
</head>
<body>
<div id="app">
<template>
<div class="chatPannel">
<div class="newChat" @click="collect_id=0;msgList=[]">
<img src="/static/images/openailogo.svg" />新聊天</div>
<div class="fileList">
<div @click="selectCollect(item.id)" class="fileTitle" v-bind:class="{'active': item.id==collect_id}" v-for="(item,index) in collectList" :title="item.title">
<i class="el-icon-chat-square"></i><{truncateString(item.title)}></div>
</div>
<div class="fileTitle" @click="cleanCollect()">
<i class="el-icon-delete"></i>
<span style="margin-left: 5px">清空聊天</span>
</div>
</div>
<div class="chatRight">
<div class="chatHeader">
模型: <{bigModel}>
</div>
<div style="display: flex;">
<div class="bigModelType">
<div @click="selectBigModel('gpt-3.5-turbo')" class="bigModelBtn " v-bind:class="{'active': bigModel=='gpt-3.5-turbo'}">GPT-3.5 Turbo</div>
<div @click="selectBigModel('gpt-4o')" class="bigModelBtn" v-bind:class="{'active': bigModel=='gpt-4o'}">GPT-4o</div>
<div @click="selectBigModel('gpt-4-turbo')" class="bigModelBtn" v-bind:class="{'active': bigModel=='gpt-4-turbo'}">GPT-4 Turbo</div>
<div @click="selectBigModel('gpt-4')" class="bigModelBtn" v-bind:class="{'active': bigModel=='gpt-4'}">GPT-4</div>
<div style="display: none" @click="selectBigModel('ERNIE-Bot-turbo')" class="bigModelBtn" v-bind:class="{'active': bigModel=='ERNIE-Bot-turbo'}">文心千帆</div>
</div>
</div>
<div class="chatpdfBox">
<div class="chatpdfLine">
<div v-show="collect_id==0">
<div style="text-align: center;margin:200px 0px 80px 0px">
<img src="/static/images/openailogo.svg" width="50px"/>
</div>
<h1>智能GPT创作系统</h1>
<div class="introBlock">
<div class="introBlockTitle">
<svg stroke="currentColor" fill="none" stroke-width="1.5" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-6 w-6" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>
示例
</div>
<div class="introBlockTitle">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="round" stroke="currentColor" aria-hidden="true" class="h-6 w-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z"></path></svg>
技术支持
</div>
<div class="introBlockTitle">
<svg stroke="currentColor" fill="none" stroke-width="1.5" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-6 w-6" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
限制
</div>
<div class="introBlockItem" @click="askContent='请详细解释如何使用chatgpt'">
“请详细解释如何使用chatgpt” →
</div>
<div class="introBlockItem" @click="askContent='如何实现知识库Embedding增强GPT'">
如何实现知识库Embedding 增强GPT
</div>
<div class="introBlockItem" @click="askContent='如何选择智能客服系统'">
如何选择智能客服系统
</div>
</div>
</div>
<div class="chatpdfRow " v-bind:class="{'chatpdfAsk': item.type=='ask'}" v-for="(item,index) in msgList">
<div class="chatScoll">
<el-avatar shape="square" class="chatAvatar" :size="35" :src="item.avatar"></el-avatar>
<div class="chatpdfContent" v-html="markdownHtml(item.content)"></div>
</div>
</div>
</div>
</div>
<div class="chatpdfArea">
<textarea @keydown.prevent.enter="sendAsk" v-model="askContent" placeholder="给AI发送消息"></textarea>
<svg @click="sendAsk" v-bind:class="{'active': !isSend && askContent!=''}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" class="h-4 w-4 m-1 md:m-0" stroke-width="1"><path d="M.5 1.163A1 1 0 0 1 1.97.28l12.868 6.837a1 1 0 0 1 0 1.766L1.969 15.72A1 1 0 0 1 .5 14.836V10.33a1 1 0 0 1 .816-.983L8.5 8 1.316 6.653A1 1 0 0 1 .5 5.67V1.163Z" fill="currentColor"></path></svg>
</div>
<el-backtop target=".chatpdfBox"></el-backtop>
</div>
</template>
</div>
</body>
<!-- 引入highlight.js的CSS样式 -->
<link rel="stylesheet" href="/static/js/highlight/styles/default.css">
<script src="/static/js/highlight/highlight.pack.js"></script>
<!-- 引入markdown-it的库 -->
<script src="/static/js/markdown-it.min.js"></script>
<style>
pre.hljs {
border-radius: 5px;
position: relative;
}
pre.hljs ol {
list-style: decimal;
margin: 0px;
margin-left: 40px;
padding: 0;
}
pre.hljs li {
list-style: decimal-leading-zero;
position: relative;
padding-left: 10px;
}
pre.hljs .line-num {
position: absolute;
left: -40px;
top: 0;
width: 40px;
height: 100%;
border-right: 1px solid #ddd;
}
pre.hljs code{
padding: unset;
color: unset;
}
</style>
<script>
const collectName="";
new Vue({
el: '#app',
delimiters:["<{","}>"],
data: {
avatar:"",
aiAvatar:"/static/images/openailogo.svg",
email:"",
nickname:"",
collect_id:0,
loading:null,
askContent:"",
msgList:[
],
collectList:[],
bigModel:"gpt-3.5-turbo",
markdownIt:"",
isSend:false,
},
methods: {
kefuInfo() {
let _this = this;
sendAjax("/kefu/kefuinfo","get",{},function (data) {
if (data.code != 200) {
window.location.href = "/ironMan/signInx";
} else {
let result = data.result;
_this.avatar=result.avator;
_this.email=result.email;
_this.nickname=result.nickname;
_this.getCollectList();
}
});
},
trim(str, char) {
if (char) {
str=str.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '');
}
return str.replace(/^\s+|\s+$/g, '');
},
sendAsk(){
if(this.askContent=="" ||this.isSend) return;
let _this=this;
let msg={
'type':'ask',
'content':this.askContent,
'avatar':this.avatar
}
this.msgList.push(msg);
let data=JSON.stringify(this.msgList);
localStorage.setItem("data_"+this.collect,data);
this.scrollBottom();
this.SaveChatStream(this.askContent,'ask',function(){
_this.getReplyFromApi();
});
},
getReplyFromApi(){
let _this=this;
_this.isSend=true;
let msg={
'type':'answer',
'avatar':this.aiAvatar,
'content':"正在为你生成答案(开发中)...",
}
_this.msgList.push(msg);
let result="";
var xhr = new XMLHttpRequest();
let data={
content:_this.askContent,
model:_this.bigModel,
collect_id:_this.collect_id,
}
let postData=Object.keys(data)
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
.join("&");
xhr.open("POST", "/kefu/chatStream");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("token", localStorage.getItem("token"));
xhr.onprogress = function (event) {
result=event.currentTarget.responseText;
_this.msgList[_this.msgList.length - 1].content =result;
_this.scrollBottom();
};
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
_this.isSend=false;
_this.SaveChatStream(result,"answer");
_this.scrollBottom();
}
};
xhr.send(postData);
this.askContent="";
},
//保存消息记录
SaveChatStream(content,msgType,callback){
let _this = this;
let data={
collect_id:this.collect_id,
content:content,
kefu_avatar:this.avatar,
ai_avatar:this.aiAvatar,
msg_type:msgType
}
sendAjax("/kefu/saveChatStream","POST",data,function (ret) {
_this.collect_id=ret.result.collect_id;
let flag=false;
for(let i in _this.collectList){
if(_this.collectList[i].id==_this.collect_id){
flag=true;
break;
}
}
if(!flag){
_this.collectList.unshift({id:_this.collect_id,title:content})
}
if (callback) callback();
});
},
//截取字符
truncateString(str){
return truncateString(str,13);
},
//获取集合列表
getCollectList(){
let _this = this;
sendAjax("/kefu/chatCollects","GET",{},function (ret) {
_this.collectList=ret.result;
});
},
//选择集合
selectCollect(collectId){
let _this=this;
this.collect_id=collectId;
this.msgList=[];
sendAjax("/kefu/chatSessions","GET",{collect_id:collectId},function (ret) {
let collects=ret.result;
for(let i in collects){
let item=collects[i];
let element={type:item.msg_type,content:item.content,avatar:""}
if (item.msg_type=='ask'){
element.avatar=item.kefu_avatar;
}else{
element.avatar=item.ai_avatar;
}
_this.msgList.push(element);
}
_this.scrollBottom();
});
},
//清空集合
cleanCollect(){
let _this = this;
sendAjax("/kefu/cleanChatCollects","GET",{},function (ret) {
_this.collectList=[];
_this.collect_id=0;
});
},
//选择大模型
selectBigModel(name){
let _this=this;
_this.bigModel=name;
if(name=='ERNIE-Bot-turbo'){
_this.aiAvatar="/static/images/ERNIE.png";
}else if(name=='gpt-4'){
_this.aiAvatar="/static/images/gpt4.png";
}else {
_this.aiAvatar="/static/images/openailogo.svg";
}
},
//滚动到底部
scrollBottom:function(){
var _this=this;
this.$nextTick(function(){
var container = _this.$el.querySelector(".chatpdfBox");
container.scrollTop = 999999999;
});
},
//解析markdown
markdownHtml(str){
var result = this.markdownIt.render(str);
return result;
},
},
mounted:function(){
},
created: function () {
this.kefuInfo();
// 配置highlight.js
hljs.configure({
tabReplace: ' ', // 使用两个空格作为缩进
});
this.markdownIt=window.markdownit({
html: true,
linkify: true,
typographer: true,
highlight: function (str, lang) {
// 此处判断是否有添加代码语言
if (lang && hljs.getLanguage(lang)) {
try {
// 得到经过highlight.js之后的html代码
const preCode = hljs.highlight(lang, str, true).value
// 以换行进行分割
const lines = preCode.split(/\n/).slice(0, -1)
// 添加自定义行号
let html = lines.map((item, index) => {
return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item + '</li>'
}).join('')
html = '<ol>' + html + '</ol>'
return '<pre class="hljs"><code>' +
html +
'</code></pre>'
} catch (__) {}
}
// // 未添加代码语言,此处与上面同理
// const preCode = str;
// const lines = preCode.split(/\n/).slice(0, -1)
// let html = lines.map((item, index) => {
// return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item + '</li>'
// }).join('')
// html = '<ol>' + html + '</ol>'
// return '<pre class="hljs"><code>' +
// html +
// '</code></pre>'
}
});
}
})
</script>
</html>