|
@@ -1,28 +1,28 @@
|
|
|
// AI助手
|
|
|
-var cmAiMixins = function () {
|
|
|
+var cmAiMixins = function() {
|
|
|
return {
|
|
|
data() {
|
|
|
return {
|
|
|
isAiDrawer: false,
|
|
|
isLoading: false,
|
|
|
- chatParams:{
|
|
|
- userId:'',
|
|
|
- question:''
|
|
|
+ chatParams: {
|
|
|
+ userId: '',
|
|
|
+ question: ''
|
|
|
},
|
|
|
- chatHistoryParams:{
|
|
|
- userId:'',
|
|
|
- pageNum:1,
|
|
|
- pageSize:10
|
|
|
+ chatHistoryParams: {
|
|
|
+ userId: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10
|
|
|
},
|
|
|
- chatHistory:[],
|
|
|
- questionTextarea:'',
|
|
|
- probeChatId:0,
|
|
|
- probeIndex:0,
|
|
|
- clubName:''
|
|
|
+ chatHistory: [],
|
|
|
+ questionTextarea: '',
|
|
|
+ probeChatId: 0,
|
|
|
+ probeIndex: 0,
|
|
|
+ clubName: ''
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
- disabled(){
|
|
|
+ disabled() {
|
|
|
return !this.probeIndex
|
|
|
}
|
|
|
},
|
|
@@ -36,15 +36,16 @@ var cmAiMixins = function () {
|
|
|
this.isAiDrawer = false
|
|
|
done();
|
|
|
})
|
|
|
- .catch(_ => {});
|
|
|
+ .catch(_ => {
|
|
|
+ });
|
|
|
},
|
|
|
// 显示弹窗
|
|
|
- handleShowAiDrawer(){
|
|
|
+ handleShowAiDrawer() {
|
|
|
this.isAiDrawer = true
|
|
|
- setTimeout(()=>{
|
|
|
+ setTimeout(() => {
|
|
|
this.handleCreatedInfoHtml()
|
|
|
- },250)
|
|
|
- if(globalUserData){
|
|
|
+ }, 250)
|
|
|
+ if (globalUserData) {
|
|
|
this.clubName = globalUserData.name
|
|
|
this.chatParams.userId = this.chatHistoryParams.userId = globalUserData.userId;
|
|
|
this.chatParams.question = ''
|
|
@@ -52,16 +53,19 @@ var cmAiMixins = function () {
|
|
|
}
|
|
|
},
|
|
|
//新建对话
|
|
|
- handleCreatedChat(){
|
|
|
- if(this.isLoading){ return; }
|
|
|
+ handleCreatedChat() {
|
|
|
+ if (this.isLoading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
const answerContent = document.getElementById('cm_ai_answer')
|
|
|
answerContent.innerHTML = ''
|
|
|
this.probeIndex = 0
|
|
|
+ this.probeChatId = ''
|
|
|
this.questionTextarea = ''
|
|
|
this.chatParams.question = ''
|
|
|
},
|
|
|
// 检查是否按下了回车键执行AI搜索
|
|
|
- handleKeyDown(event){
|
|
|
+ handleKeyDown(event) {
|
|
|
if (event.key === 'Enter') {
|
|
|
// 阻止默认的换行行为(可选,根据你的需求来决定是否需要)
|
|
|
event.preventDefault();
|
|
@@ -71,60 +75,61 @@ var cmAiMixins = function () {
|
|
|
}
|
|
|
},
|
|
|
// 发送按钮点击事件
|
|
|
- handleAskQuestion(){
|
|
|
+ handleAskQuestion() {
|
|
|
const _this = this;
|
|
|
- if(!globalUserData){
|
|
|
+ if (!globalUserData) {
|
|
|
window.location.href = '/login.html'
|
|
|
return
|
|
|
}
|
|
|
this.chatParams.question = this.questionTextarea
|
|
|
- if(this.isLoading){ return; }
|
|
|
- if (!this.chatParams.question){
|
|
|
- CAIMEI.dialog('请输入内容',false)
|
|
|
+ if (this.isLoading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!this.chatParams.question) {
|
|
|
+ CAIMEI.dialog('请输入内容', false)
|
|
|
return
|
|
|
}
|
|
|
// 用于显示AI回答的DOM元素
|
|
|
const answerContent = document.getElementById('cm_ai_answer')
|
|
|
- this.handleCreateUserHtml(this.chatParams.question,answerContent)
|
|
|
+ this.handleCreateUserHtml(this.chatParams.question, answerContent)
|
|
|
this.isLoading = true
|
|
|
- console.log('isLoading',this.isLoading)
|
|
|
+ console.log('isLoading', this.isLoading)
|
|
|
this.handleCreateChartHtml(answerContent)
|
|
|
},
|
|
|
// 初始化
|
|
|
- handleCreatedInfoHtml(){
|
|
|
+ handleCreatedInfoHtml() {
|
|
|
const answerContent = document.getElementById('cm_ai_answer')
|
|
|
// 创建一个新的div元素,并设置其类名为'cm_ai_answer info'
|
|
|
const answerElement = document.createElement('div');
|
|
|
answerElement.className = 'cm_ai_answer info';
|
|
|
// 创建子元素,显示欢迎语
|
|
|
- const contentInfoStr =`<div class="cm_ai_html info"><h1>Hi,我是采美Ai助手</h1>我是您的Ai助手,欢迎向我提出您的疑问,我会根据你给出的问题提供相对应的回答~</div>`
|
|
|
+ const contentInfoStr = `<div class="cm_ai_html info"><h1>Hi,我是采美Ai助手</h1>我是您的Ai助手,欢迎向我提出您的疑问,我会根据你给出的问题提供相对应的回答~</div>`
|
|
|
answerElement.innerHTML += contentInfoStr
|
|
|
// 最后,将answerElement添加到页面的某个现有元素中,例如body
|
|
|
answerContent.appendChild(answerElement);
|
|
|
},
|
|
|
// 创建用户html
|
|
|
- handleCreateUserHtml(question,answerContent){
|
|
|
+ handleCreateUserHtml(question, answerContent) {
|
|
|
// 创建一个新的div元素,并设置其类名为'cm_ai_answer'
|
|
|
const answerElement = document.createElement('div');
|
|
|
answerElement.className = 'cm_ai_answer user';
|
|
|
// 创建第一个子元素,包含图标
|
|
|
- const iconDivStr ='<div class="cm_ai_html_icon user"><img src="/img/base/icon-aiUser@2x.png"></div>'
|
|
|
+ const iconDivStr = '<div class="cm_ai_html_icon user"><img src="/img/base/icon-aiUser@2x.png"></div>'
|
|
|
// 创建第二个子元素,用于显示内容
|
|
|
- const contentUserStr =`<div class="cm_ai_html user">${question}</div>`
|
|
|
+ const contentUserStr = `<div class="cm_ai_html user">${question}</div>`
|
|
|
answerElement.innerHTML += iconDivStr
|
|
|
answerElement.innerHTML += contentUserStr
|
|
|
// 最后,将answerElement添加到页面的某个现有元素中,例如body
|
|
|
answerContent.appendChild(answerElement);
|
|
|
},
|
|
|
// 生成
|
|
|
- handleCreateChartHtml(answerContent){
|
|
|
- const _this = this;
|
|
|
+ handleCreateChartHtml(answerContent) {
|
|
|
// 创建一个新的div元素,并设置其类名为'cm_ai_answer'
|
|
|
const answerElement = document.createElement('div');
|
|
|
answerElement.className = 'cm_ai_answer chat';
|
|
|
// 创建第一个子元素,包含图标
|
|
|
- const iconDivStr ='<div class="cm_ai_html_icon"><img src="/img/base/icon-ai@1x.png"></div>'
|
|
|
- const loadingImgStr ='<img class="cm_ai_html_loading" src="/img/base/loading.gif">'
|
|
|
+ const iconDivStr = '<div class="cm_ai_html_icon"><img src="/img/base/icon-ai@1x.png"></div>'
|
|
|
+ const loadingImgStr = '<div class="cm_ai_loading">正在分析,请您稍作等待<img class="cm_ai_html_loading" src="/img/base/loading.gif"></div>'
|
|
|
// 创建第二个子元素,用于显示内容
|
|
|
const contentHtml = document.createElement('div');
|
|
|
contentHtml.className = 'cm_ai_html';
|
|
@@ -135,61 +140,85 @@ var cmAiMixins = function () {
|
|
|
answerElement.appendChild(contentHtml);
|
|
|
// 最后,将answerElement添加到页面的某个现有元素中,例如body
|
|
|
answerContent.appendChild(answerElement);
|
|
|
+ // 滚动到容器底部(如果内容超出了可视区域)
|
|
|
+ answerContent.scrollTop = answerContent.scrollHeight;
|
|
|
+ this.handleWorkerPrev(contentHtml, answerContent)
|
|
|
+ },
|
|
|
+ // worker处理页面卡顿
|
|
|
+ handleWorkerPrev(contentHtml, answerContent) {
|
|
|
const myWorker = new Worker('/js/caimei-chat/worker.js');
|
|
|
- console.log('myWorker',myWorker)
|
|
|
- // 定义一个包含自定义参数的对象
|
|
|
+ console.log('probeChatId',this.probeChatId)
|
|
|
+ const NODE_ENV_BASE_URL = $("#coreServer").val()
|
|
|
const customData = {
|
|
|
- key1: this.chatParams,
|
|
|
- key2: PublicApi,
|
|
|
+ url: this.probeIndex === 0 ? `${NODE_ENV_BASE_URL}/user/chat/new/chat` : `${NODE_ENV_BASE_URL}/user/chat/second/chat`,
|
|
|
+ params: this.probeIndex === 0 ? this.chatParams : { chatId: this.probeChatId, ...this.chatParams},
|
|
|
};
|
|
|
// 向 Worker 发送数据
|
|
|
myWorker.postMessage(customData);
|
|
|
// 监听来自 worker 的消息
|
|
|
- myWorker.onmessage = (event)=> {
|
|
|
- console.log('event',event)
|
|
|
- }
|
|
|
- setTimeout(()=>{
|
|
|
- if(this.probeIndex === 0){
|
|
|
- _this.handleGetUserNewChats(contentHtml,answerContent)
|
|
|
- }else{
|
|
|
- _this.handleGetUserSecondChat(contentHtml,answerContent)
|
|
|
+ myWorker.onmessage = async (event) => {
|
|
|
+ console.log('event', event)
|
|
|
+ const data = event.data
|
|
|
+ if (data.code === 0) {
|
|
|
+ if (this.probeIndex === 0) {
|
|
|
+ this.questionTextarea = ''
|
|
|
+ this.probeChatId = data.data.chatId
|
|
|
+ console.log('probeChatId',this.probeChatId)
|
|
|
+ this.handleResponseHtml(data.data, contentHtml, answerContent)
|
|
|
+ await this.getChatHistory()
|
|
|
+ } else {
|
|
|
+ this.questionTextarea = ''
|
|
|
+ this.handleResponseHtml(data.data, contentHtml, answerContent)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.questionTextarea = ''
|
|
|
+ this.handleErrorHtml(data.code,this.chatParams.question, contentHtml, answerContent)
|
|
|
}
|
|
|
- },500)
|
|
|
- },
|
|
|
- // 初次调用
|
|
|
- async handleGetUserNewChats(contentHtml,answerContent){
|
|
|
- try {
|
|
|
- this.questionTextarea = ''
|
|
|
- const data = await this.getUserNewChats(this.chatParams)
|
|
|
- this.probeChatId = data.chatId
|
|
|
- this.handleResponseHtml(data,contentHtml,answerContent)
|
|
|
- await this.getChatHistory()
|
|
|
- } catch (error) {
|
|
|
- console.log('Error fetching new chats:', error);
|
|
|
}
|
|
|
},
|
|
|
- // 调用追问
|
|
|
- async handleGetUserSecondChat(contentHtml,answerContent){
|
|
|
- try {
|
|
|
- this.questionTextarea = ''
|
|
|
- const data = await this.getUserSecondChat({chatId:this.probeChatId,...this.chatParams})
|
|
|
- this.handleResponseHtml(data,contentHtml,answerContent)
|
|
|
- } catch (error) {
|
|
|
- console.log('Error fetching new chats:', error);
|
|
|
+ // 处理没有查询到内容
|
|
|
+ handleErrorHtml(code, question, contentHtml, answerContent) {
|
|
|
+ const _this = this;
|
|
|
+ const msgMap = {
|
|
|
+ '-1':`您好,目前没有找到与${question}相关的信息,可以换个说法试试。`,
|
|
|
+ '-2':`您的此次对话已超出对话轮次上限,可以刷新页面或新建对话重试。`
|
|
|
}
|
|
|
+ document.querySelector('div.cm_ai_loading').remove()
|
|
|
+ // 打字函数
|
|
|
+ let currentIndex = 0
|
|
|
+ const speed = 30
|
|
|
+ const typeEffect = () => {
|
|
|
+ // 如果已经显示完所有字符,则停止
|
|
|
+ if (currentIndex < msgMap[code].length) {
|
|
|
+ // 逐个字符添加到打字效果的元素中
|
|
|
+ contentHtml.innerHTML += msgMap[code].charAt(currentIndex)
|
|
|
+ // 更新索引
|
|
|
+ currentIndex++
|
|
|
+ // 递归调用,直到显示完所有字符
|
|
|
+ setTimeout(typeEffect, speed)
|
|
|
+ // 滚动到容器底部(如果内容超出了可视区域)
|
|
|
+ answerContent.scrollTop = answerContent.scrollHeight;
|
|
|
+ } else {
|
|
|
+ _this.isLoading = false
|
|
|
+ // 滚动到容器底部(如果内容超出了可视区域)
|
|
|
+ answerContent.scrollTop = answerContent.scrollHeight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 开始打字效果
|
|
|
+ typeEffect()
|
|
|
},
|
|
|
// 数据显示
|
|
|
- handleResponseHtml(data,contentHtml,answerContent){
|
|
|
+ handleResponseHtml(data, contentHtml, answerContent) {
|
|
|
const _this = this;
|
|
|
// 替换换行符 ,替换加粗部分
|
|
|
const aiResponsText = data.result.replace(/\\n\\n/g, '').replace(/\* \*\*([^<]+?)\*\*/g, '');
|
|
|
// console.log('aiResponsText',aiResponsText)
|
|
|
// console.log('search_info',search_results)
|
|
|
- document.querySelector('img.cm_ai_html_loading').remove()
|
|
|
+ document.querySelector('div.cm_ai_loading').remove()
|
|
|
// 打字函数
|
|
|
let currentIndex = 0
|
|
|
const speed = 30
|
|
|
- function typeEffect() {
|
|
|
+ const typeEffect = () => {
|
|
|
// 如果已经显示完所有字符,则停止
|
|
|
if (currentIndex < aiResponsText.length) {
|
|
|
// 逐个字符添加到打字效果的元素中
|
|
@@ -200,10 +229,10 @@ var cmAiMixins = function () {
|
|
|
setTimeout(typeEffect, speed)
|
|
|
// 滚动到容器底部(如果内容超出了可视区域)
|
|
|
answerContent.scrollTop = answerContent.scrollHeight;
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
// 如果有推荐信息源的话执行
|
|
|
- if(data.search_info.search_results){
|
|
|
- _this.handleCreateChartLink(contentHtml,data.search_info.search_results)
|
|
|
+ if (data.search_info.search_results) {
|
|
|
+ _this.handleCreateChartLink(contentHtml, data.search_info.search_results)
|
|
|
}
|
|
|
_this.probeIndex++
|
|
|
_this.isLoading = false
|
|
@@ -215,7 +244,7 @@ var cmAiMixins = function () {
|
|
|
typeEffect()
|
|
|
},
|
|
|
// 参考信息源渲染
|
|
|
- handleCreateChartLink(contentHtml,search_results){
|
|
|
+ handleCreateChartLink(contentHtml, search_results) {
|
|
|
const contentLink = document.createElement('div')
|
|
|
contentLink.className = 'cm_ai_link'
|
|
|
// 创建第二个子元素,用于显示内容
|
|
@@ -230,22 +259,24 @@ var cmAiMixins = function () {
|
|
|
});
|
|
|
},
|
|
|
// 查询记录
|
|
|
- async getChatHistory(){
|
|
|
+ async getChatHistory() {
|
|
|
const data = await this.userNewChatHistory(this.chatHistoryParams)
|
|
|
- console.log('chatHistory',data)
|
|
|
+ console.log('chatHistory', data)
|
|
|
this.chatHistory = data
|
|
|
},
|
|
|
// 查询详情
|
|
|
- async handleChatDetail(chatId){
|
|
|
- try{
|
|
|
- const list = await this.userNewChatDetail({ userId:this.chatParams.userId,chatId:chatId })
|
|
|
+ async handleChatDetail(chatId) {
|
|
|
+ try {
|
|
|
+ this.probeIndex = 1
|
|
|
+ this.probeChatId = chatId
|
|
|
+ const list = await this.userNewChatDetail({userId: this.chatParams.userId, chatId: chatId})
|
|
|
this.handleCreateDetailHtml(list)
|
|
|
} catch (error) {
|
|
|
console.log('Error fetching new chats:', error);
|
|
|
}
|
|
|
},
|
|
|
// 渲染记录详情html
|
|
|
- handleCreateDetailHtml(list){
|
|
|
+ handleCreateDetailHtml(list) {
|
|
|
// console.log('Detail',list)
|
|
|
const answerContent = document.getElementById('cm_ai_answer')
|
|
|
answerContent.innerHTML = ''
|
|
@@ -262,7 +293,6 @@ var cmAiMixins = function () {
|
|
|
iconSrc = '/img/base/icon-ai@1x.png';
|
|
|
className = 'chat'; // 如果不需要特别的类名,这里可以留空
|
|
|
}
|
|
|
-
|
|
|
// 拼接 HTML 字符串
|
|
|
htmlContent += `<div class="cm_ai_answer ${className}"><div class="cm_ai_html_icon ${className}"><img src="${iconSrc}"></div>
|
|
|
<div class="cm_ai_html ${className}">${item.message}</div></div>`;
|
|
@@ -272,9 +302,9 @@ var cmAiMixins = function () {
|
|
|
answerContent.scrollTop = answerContent.scrollHeight;
|
|
|
},
|
|
|
// 查询详情
|
|
|
- userNewChatDetail(params){// 查询详情
|
|
|
+ userNewChatDetail(params) {// 查询详情
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- PublicApi.userNewChatDetail(params, function(response) {
|
|
|
+ PublicApi.userNewChatDetail(params, (response) => {
|
|
|
if (response.code === 0) {
|
|
|
resolve(response.data)
|
|
|
} else {
|
|
@@ -284,9 +314,9 @@ var cmAiMixins = function () {
|
|
|
});
|
|
|
},
|
|
|
// 查询记录
|
|
|
- userNewChatHistory(params){
|
|
|
+ userNewChatHistory(params) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- PublicApi.userNewChatHistory(params, function(response) {
|
|
|
+ PublicApi.userNewChatHistory(params, (response) => {
|
|
|
if (response.code === 0) {
|
|
|
resolve(response.data)
|
|
|
} else {
|
|
@@ -296,9 +326,9 @@ var cmAiMixins = function () {
|
|
|
});
|
|
|
},
|
|
|
// 查询获取问题结果
|
|
|
- getUserNewChats(params){
|
|
|
+ getUserNewChats(params) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- PublicApi.userNewChat(params, function(response) {
|
|
|
+ PublicApi.userNewChat(params, (response) => {
|
|
|
if (response.code === 0) {
|
|
|
resolve(response.data)
|
|
|
} else {
|
|
@@ -308,9 +338,9 @@ var cmAiMixins = function () {
|
|
|
});
|
|
|
},
|
|
|
// 追问
|
|
|
- getUserSecondChat(params){
|
|
|
+ getUserSecondChat(params) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- PublicApi.userSecondChat(params, function(response) {
|
|
|
+ PublicApi.userSecondChat(params, (response) => {
|
|
|
if (response.code === 0) {
|
|
|
resolve(response.data)
|
|
|
} else {
|