feat: chat log
This commit is contained in:
parent
fa818fc6e8
commit
e9527bdd2b
@ -3,7 +3,6 @@ import { get, post, postStream, del, put, request, download, exportFile } from '
|
|||||||
import type { pageRequest } from '@/api/type/common'
|
import type { pageRequest } from '@/api/type/common'
|
||||||
import type { ApplicationFormType } from '@/api/type/application'
|
import type { ApplicationFormType } from '@/api/type/application'
|
||||||
import { type Ref } from 'vue'
|
import { type Ref } from 'vue'
|
||||||
import type { FormField } from '@/components/dynamics-form/type'
|
|
||||||
|
|
||||||
const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application'
|
const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application'
|
||||||
|
|
||||||
|
|||||||
200
ui/src/api/application/chat-log.ts
Normal file
200
ui/src/api/application/chat-log.ts
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { Result } from '@/request/Result'
|
||||||
|
import {
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
exportExcelPost,
|
||||||
|
postStream,
|
||||||
|
del,
|
||||||
|
put,
|
||||||
|
request,
|
||||||
|
download,
|
||||||
|
exportFile,
|
||||||
|
} from '@/request/index'
|
||||||
|
import type { pageRequest } from '@/api/type/common'
|
||||||
|
import type { ApplicationFormType } from '@/api/type/application'
|
||||||
|
import { type Ref } from 'vue'
|
||||||
|
|
||||||
|
const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application'
|
||||||
|
/**
|
||||||
|
* 对话记录提交至知识库
|
||||||
|
* @param data
|
||||||
|
* @param loading
|
||||||
|
* @param application_id
|
||||||
|
* @param knowledge_id
|
||||||
|
*/
|
||||||
|
|
||||||
|
const postChatLogAddKnowledge: (
|
||||||
|
application_id: string,
|
||||||
|
data: any,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (application_id, data, loading) => {
|
||||||
|
return post(`${prefix}/${application_id}/add_knowledge`, data, undefined, loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话日志
|
||||||
|
* @param 参数
|
||||||
|
* application_id
|
||||||
|
* param {
|
||||||
|
"start_time": "string",
|
||||||
|
"end_time": "string",
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const getChatLog: (
|
||||||
|
application_id: String,
|
||||||
|
page: pageRequest,
|
||||||
|
param: any,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (application_id, page, param, loading) => {
|
||||||
|
return get(
|
||||||
|
`${prefix}/${application_id}/chat/${page.current_page}/${page.page_size}`,
|
||||||
|
param,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得对话日志记录
|
||||||
|
* @param 参数
|
||||||
|
* application_id, chart_id,order_asc
|
||||||
|
*/
|
||||||
|
const getChatRecordLog: (
|
||||||
|
application_id: String,
|
||||||
|
chart_id: String,
|
||||||
|
page: pageRequest,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
order_asc?: boolean,
|
||||||
|
) => Promise<Result<any>> = (application_id, chart_id, page, loading, order_asc) => {
|
||||||
|
return get(
|
||||||
|
`${prefix}/${application_id}/chat/${chart_id}/chat_record/${page.current_page}/${page.page_size}`,
|
||||||
|
{ order_asc: order_asc !== undefined ? order_asc : true },
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取标注段落列表信息
|
||||||
|
* @param 参数
|
||||||
|
* application_id, chart_id, chart_record_id, knowledge_id, document_id
|
||||||
|
*/
|
||||||
|
const getMarkChatRecord: (
|
||||||
|
application_id: String,
|
||||||
|
chart_id: String,
|
||||||
|
chart_record_id: String,
|
||||||
|
knowledge_id: String,
|
||||||
|
document_id: String,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (
|
||||||
|
application_id,
|
||||||
|
chart_id,
|
||||||
|
chart_record_id,
|
||||||
|
knowledge_id,
|
||||||
|
document_id,
|
||||||
|
loading,
|
||||||
|
) => {
|
||||||
|
return get(
|
||||||
|
`${prefix}/${application_id}/chat/${chart_id}/chat_record/${chart_record_id}/knowledge/${knowledge_id}/document/${document_id}/improve`,
|
||||||
|
undefined,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改日志记录内容
|
||||||
|
* @param 参数
|
||||||
|
* application_id, chart_id, chart_record_id, knowledge_id, document_id
|
||||||
|
* data {
|
||||||
|
"title": "string",
|
||||||
|
"content": "string",
|
||||||
|
"problem_text": "string"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const putChatRecordLog: (
|
||||||
|
application_id: String,
|
||||||
|
chart_id: String,
|
||||||
|
chart_record_id: String,
|
||||||
|
knowledge_id: String,
|
||||||
|
document_id: String,
|
||||||
|
data: any,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (
|
||||||
|
application_id,
|
||||||
|
chart_id,
|
||||||
|
chart_record_id,
|
||||||
|
knowledge_id,
|
||||||
|
document_id,
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
) => {
|
||||||
|
return put(
|
||||||
|
`${prefix}/${application_id}/chat/${chart_id}/chat_record/${chart_record_id}/dataset/${knowledge_id}/document/${document_id}/improve`,
|
||||||
|
data,
|
||||||
|
undefined,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标注
|
||||||
|
* @param 参数
|
||||||
|
* application_id, chart_id, chart_record_id, dataset_id, document_id,paragraph_id
|
||||||
|
*/
|
||||||
|
const delMarkChatRecord: (
|
||||||
|
application_id: String,
|
||||||
|
chart_id: String,
|
||||||
|
chart_record_id: String,
|
||||||
|
knowledge_id: String,
|
||||||
|
document_id: String,
|
||||||
|
paragraph_id: String,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (
|
||||||
|
application_id,
|
||||||
|
chart_id,
|
||||||
|
chart_record_id,
|
||||||
|
knowledge_id,
|
||||||
|
document_id,
|
||||||
|
paragraph_id,
|
||||||
|
loading,
|
||||||
|
) => {
|
||||||
|
return del(
|
||||||
|
`${prefix}/${application_id}/chat/${chart_id}/chat_record/${chart_record_id}/knowledge/${knowledge_id}/document/${document_id}/paragraph/${paragraph_id}/improve`,
|
||||||
|
undefined,
|
||||||
|
{},
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出对话日志
|
||||||
|
* @param 参数
|
||||||
|
* application_id
|
||||||
|
* param {
|
||||||
|
"start_time": "string",
|
||||||
|
"end_time": "string",
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const postExportChatLog: (
|
||||||
|
application_id: string,
|
||||||
|
application_name: string,
|
||||||
|
param: any,
|
||||||
|
data: any,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => void = (application_id, application_name, param, data, loading) => {
|
||||||
|
exportExcelPost(
|
||||||
|
application_name + '.xlsx',
|
||||||
|
`${prefix}/${application_id}/chat/export`,
|
||||||
|
param,
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
postChatLogAddKnowledge,
|
||||||
|
getChatLog,
|
||||||
|
getChatRecordLog,
|
||||||
|
getMarkChatRecord,
|
||||||
|
putChatRecordLog,
|
||||||
|
delMarkChatRecord,
|
||||||
|
postExportChatLog,
|
||||||
|
}
|
||||||
@ -22,10 +22,10 @@ export default {
|
|||||||
mark: 'Marks',
|
mark: 'Marks',
|
||||||
recenTimes: 'Last Chat Time'
|
recenTimes: 'Last Chat Time'
|
||||||
},
|
},
|
||||||
addToDataset: 'Add to Knowledge',
|
addToKnowledge: 'Add to Knowledge',
|
||||||
daysText: 'Days ago',
|
daysText: 'Days ago',
|
||||||
selectDataset: 'Select Knowledge',
|
selectKnowledge: 'Select Knowledge',
|
||||||
selectDatasetPlaceholder: 'Please select a knowledge',
|
selectKnowledgePlaceholder: 'Please select a knowledge',
|
||||||
saveToDocument: 'Save to Document',
|
saveToDocument: 'Save to Document',
|
||||||
documentPlaceholder: 'Please select a document',
|
documentPlaceholder: 'Please select a document',
|
||||||
editContent: 'Edit Content',
|
editContent: 'Edit Content',
|
||||||
@ -12,7 +12,7 @@ import model from './model'
|
|||||||
import document from './document'
|
import document from './document'
|
||||||
import paragraph from './paragraph'
|
import paragraph from './paragraph'
|
||||||
import problem from './problem'
|
import problem from './problem'
|
||||||
import log from './log'
|
import chatLog from './chat-log'
|
||||||
import applicationWorkflow from './application-workflow'
|
import applicationWorkflow from './application-workflow'
|
||||||
import login from './login'
|
import login from './login'
|
||||||
import operateLog from './operate-log'
|
import operateLog from './operate-log'
|
||||||
@ -31,7 +31,7 @@ export default {
|
|||||||
document,
|
document,
|
||||||
paragraph,
|
paragraph,
|
||||||
problem,
|
problem,
|
||||||
log,
|
chatLog,
|
||||||
login,
|
login,
|
||||||
operateLog,
|
operateLog,
|
||||||
role
|
role
|
||||||
|
|||||||
@ -22,10 +22,10 @@ export default {
|
|||||||
mark: '改进标注',
|
mark: '改进标注',
|
||||||
recenTimes: '最近对话时间'
|
recenTimes: '最近对话时间'
|
||||||
},
|
},
|
||||||
addToDataset: '添加至知识库',
|
addToKnowledge: '添加至知识库',
|
||||||
daysText: '天之前的对话记录',
|
daysText: '天之前的对话记录',
|
||||||
selectDataset: '选择知识库',
|
selectKnowledge: '选择知识库',
|
||||||
selectDatasetPlaceholder: '请选择知识库',
|
selectKnowledgePlaceholder: '请选择知识库',
|
||||||
saveToDocument: '保存至文档',
|
saveToDocument: '保存至文档',
|
||||||
documentPlaceholder: '请选择文档',
|
documentPlaceholder: '请选择文档',
|
||||||
editContent: '修改内容',
|
editContent: '修改内容',
|
||||||
@ -12,7 +12,7 @@ import problem from './problem'
|
|||||||
import applicationOverview from './application-overview'
|
import applicationOverview from './application-overview'
|
||||||
import applicationWorkflow from './application-workflow'
|
import applicationWorkflow from './application-workflow'
|
||||||
import paragraph from './paragraph'
|
import paragraph from './paragraph'
|
||||||
import log from './log'
|
import chatLog from './chat-log'
|
||||||
// import notFound from './404'
|
// import notFound from './404'
|
||||||
|
|
||||||
// import operateLog from './operate-log'
|
// import operateLog from './operate-log'
|
||||||
@ -31,7 +31,7 @@ export default {
|
|||||||
applicationOverview,
|
applicationOverview,
|
||||||
applicationWorkflow,
|
applicationWorkflow,
|
||||||
paragraph,
|
paragraph,
|
||||||
log,
|
chatLog,
|
||||||
// notFound,
|
// notFound,
|
||||||
|
|
||||||
// operateLog
|
// operateLog
|
||||||
|
|||||||
@ -22,10 +22,10 @@ export default {
|
|||||||
mark: '改進標註',
|
mark: '改進標註',
|
||||||
recenTimes: '最近對話時間'
|
recenTimes: '最近對話時間'
|
||||||
},
|
},
|
||||||
addToDataset: '添加至知識庫',
|
addToKnowledge: '添加至知識庫',
|
||||||
daysText: '天之前的對話記錄',
|
daysText: '天之前的對話記錄',
|
||||||
selectDataset: '選擇知識庫',
|
selectKnowledge: '選擇知識庫',
|
||||||
selectDatasetPlaceholder: '請選擇知識庫',
|
selectKnowledgePlaceholder: '請選擇知識庫',
|
||||||
saveToDocument: '保存至文件',
|
saveToDocument: '保存至文件',
|
||||||
documentPlaceholder: '請選擇文件',
|
documentPlaceholder: '請選擇文件',
|
||||||
editContent: '修改內容',
|
editContent: '修改內容',
|
||||||
@ -12,7 +12,7 @@ import model from './model'
|
|||||||
import document from './document'
|
import document from './document'
|
||||||
import paragraph from './paragraph'
|
import paragraph from './paragraph'
|
||||||
import problem from './problem'
|
import problem from './problem'
|
||||||
import log from './log'
|
import chatLog from './chat-log'
|
||||||
import applicationWorkflow from './application-workflow'
|
import applicationWorkflow from './application-workflow'
|
||||||
import login from './login'
|
import login from './login'
|
||||||
import operateLog from './operate-log'
|
import operateLog from './operate-log'
|
||||||
@ -31,7 +31,7 @@ export default {
|
|||||||
document,
|
document,
|
||||||
paragraph,
|
paragraph,
|
||||||
problem,
|
problem,
|
||||||
log,
|
chatLog,
|
||||||
login,
|
login,
|
||||||
operateLog,
|
operateLog,
|
||||||
role
|
role
|
||||||
|
|||||||
@ -57,19 +57,19 @@ const ApplicationDetailRouter = {
|
|||||||
},
|
},
|
||||||
component: () => import('@/views/hit-test/index.vue'),
|
component: () => import('@/views/hit-test/index.vue'),
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// path: 'log',
|
path: 'chat-log',
|
||||||
// name: 'Log',
|
name: 'ChatLog',
|
||||||
// meta: {
|
meta: {
|
||||||
// icon: 'app-document',
|
icon: 'app-document',
|
||||||
// iconActive: 'app-document-active',
|
iconActive: 'app-document-active',
|
||||||
// title: 'views.log.title',
|
title: 'views.chatLog.title',
|
||||||
// active: 'log',
|
active: 'log',
|
||||||
// parentPath: '/application/:id/:type',
|
parentPath: '/application/:id/:type',
|
||||||
// parentName: 'ApplicationDetail'
|
parentName: 'ApplicationDetail'
|
||||||
// },
|
},
|
||||||
// component: () => import('@/views/log/index.vue')
|
component: () => import('@/views/chat-log/index.vue')
|
||||||
// }
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import useProblemStore from './modules/problem'
|
|||||||
import useParagraphStore from './modules/paragraph'
|
import useParagraphStore from './modules/paragraph'
|
||||||
import useDocumentStore from './modules/document'
|
import useDocumentStore from './modules/document'
|
||||||
import useApplicationStore from './modules/application'
|
import useApplicationStore from './modules/application'
|
||||||
|
import useChatLogStore from './modules/chat-log'
|
||||||
const useStore = () => ({
|
const useStore = () => ({
|
||||||
common: useCommonStore(),
|
common: useCommonStore(),
|
||||||
login: useLoginStore(),
|
login: useLoginStore(),
|
||||||
@ -24,6 +24,7 @@ const useStore = () => ({
|
|||||||
paragraph: useParagraphStore(),
|
paragraph: useParagraphStore(),
|
||||||
document: useDocumentStore(),
|
document: useDocumentStore(),
|
||||||
application: useApplicationStore(),
|
application: useApplicationStore(),
|
||||||
|
chatLog: useChatLogStore(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default useStore
|
export default useStore
|
||||||
|
|||||||
78
ui/src/stores/modules/chat-log.ts
Normal file
78
ui/src/stores/modules/chat-log.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import chatLogApi from '@/api/application/chat-log'
|
||||||
|
import { type Ref } from 'vue'
|
||||||
|
import type { pageRequest } from '@/api/type/common'
|
||||||
|
|
||||||
|
const useChatLogStore = defineStore('chatLog',{
|
||||||
|
state: () => ({}),
|
||||||
|
actions: {
|
||||||
|
async asyncGetChatLog(id: string, page: pageRequest, param: any, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chatLogApi
|
||||||
|
.getChatLog(id, page, param, loading)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async asyncChatRecordLog(
|
||||||
|
id: string,
|
||||||
|
chatId: string,
|
||||||
|
page: pageRequest,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
order_asc?: boolean
|
||||||
|
) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chatLogApi
|
||||||
|
.getChatRecordLog(id, chatId, page, loading, order_asc)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async asyncGetChatLogClient(id: string, page: pageRequest, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chatLogApi
|
||||||
|
.getChatLogClient(id, page, loading)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async asyncDelChatClientLog(id: string, chatId: string, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chatLogApi
|
||||||
|
.delChatClientLog(id, chatId, loading)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async asyncPutChatClientLog(id: string, chatId: string, data: any, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chatLogApi
|
||||||
|
.putChatClientLog(id, chatId, data, loading)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default useChatLogStore
|
||||||
@ -156,7 +156,7 @@
|
|||||||
<AppIcon iconName="app-operation" class="mr-4"></AppIcon>
|
<AppIcon iconName="app-operation" class="mr-4"></AppIcon>
|
||||||
{{ $t('common.paramSetting') }}
|
{{ $t('common.paramSetting') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" link @click="openDatasetDialog">
|
<el-button type="primary" link @click="openKnowledgeDialog">
|
||||||
<el-icon class="mr-4">
|
<el-icon class="mr-4">
|
||||||
<Plus />
|
<Plus />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -180,11 +180,11 @@
|
|||||||
v-for="(item, index) in applicationForm.knowledge_id_list"
|
v-for="(item, index) in applicationForm.knowledge_id_list"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<el-card class="relate-dataset-card border-r-4" shadow="never">
|
<el-card class="relate-knowledge-card border-r-4" shadow="never">
|
||||||
<div class="flex-between">
|
<div class="flex-between">
|
||||||
<div class="flex align-center" style="width: 80%">
|
<div class="flex align-center" style="width: 80%">
|
||||||
<el-avatar
|
<el-avatar
|
||||||
v-if="relatedObject(datasetList, item, 'id')?.type === '1'"
|
v-if="relatedObject(knowledgeList, item, 'id')?.type === '1'"
|
||||||
class="mr-8 avatar-purple"
|
class="mr-8 avatar-purple"
|
||||||
shape="square"
|
shape="square"
|
||||||
:size="32"
|
:size="32"
|
||||||
@ -196,7 +196,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
<el-avatar
|
<el-avatar
|
||||||
v-else-if="relatedObject(datasetList, item, 'id')?.type === '2'"
|
v-else-if="relatedObject(knowledgeList, item, 'id')?.type === '2'"
|
||||||
class="mr-8 avatar-purple"
|
class="mr-8 avatar-purple"
|
||||||
shape="square"
|
shape="square"
|
||||||
:size="32"
|
:size="32"
|
||||||
@ -218,12 +218,12 @@
|
|||||||
|
|
||||||
<span
|
<span
|
||||||
class="ellipsis cursor"
|
class="ellipsis cursor"
|
||||||
:title="relatedObject(datasetList, item, 'id')?.name"
|
:title="relatedObject(knowledgeList, item, 'id')?.name"
|
||||||
>
|
>
|
||||||
{{ relatedObject(datasetList, item, 'id')?.name }}</span
|
{{ relatedObject(knowledgeList, item, 'id')?.name }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-button text @click="removeDataset(item)">
|
<el-button text @click="removeKnowledge(item)">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Close />
|
<Close />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -470,12 +470,12 @@
|
|||||||
<AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshForm" />
|
<AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshForm" />
|
||||||
<TTSModeParamSettingDialog ref="TTSModeParamSettingDialogRef" @refresh="refreshTTSForm" />
|
<TTSModeParamSettingDialog ref="TTSModeParamSettingDialogRef" @refresh="refreshTTSForm" />
|
||||||
<ParamSettingDialog ref="ParamSettingDialogRef" @refresh="refreshParam" />
|
<ParamSettingDialog ref="ParamSettingDialogRef" @refresh="refreshParam" />
|
||||||
<AddDatasetDialog
|
<AddKnowledgeDialog
|
||||||
ref="AddDatasetDialogRef"
|
ref="AddKnowledgeDialogRef"
|
||||||
@addData="addDataset"
|
@addData="addKnowledge"
|
||||||
:data="datasetList"
|
:data="knowledgeList"
|
||||||
@refresh="refresh"
|
@refresh="refresh"
|
||||||
:loading="datasetLoading"
|
:loading="knowledgeLoading"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshIcon" />
|
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshIcon" />
|
||||||
@ -491,7 +491,7 @@ import { useRoute } from 'vue-router'
|
|||||||
import { groupBy } from 'lodash'
|
import { groupBy } from 'lodash'
|
||||||
import AIModeParamSettingDialog from './component/AIModeParamSettingDialog.vue'
|
import AIModeParamSettingDialog from './component/AIModeParamSettingDialog.vue'
|
||||||
import ParamSettingDialog from './component/ParamSettingDialog.vue'
|
import ParamSettingDialog from './component/ParamSettingDialog.vue'
|
||||||
import AddDatasetDialog from './component/AddDatasetDialog.vue'
|
import AddKnowledgeDialog from './component/AddKnowledgeDialog.vue'
|
||||||
import EditAvatarDialog from '@/views/application-overview/component/EditAvatarDialog.vue'
|
import EditAvatarDialog from '@/views/application-overview/component/EditAvatarDialog.vue'
|
||||||
import applicationApi from '@/api/application/application'
|
import applicationApi from '@/api/application/application'
|
||||||
import { isAppIcon } from '@/utils/common'
|
import { isAppIcon } from '@/utils/common'
|
||||||
@ -529,11 +529,11 @@ const TTSModeParamSettingDialogRef = ref<InstanceType<typeof TTSModeParamSetting
|
|||||||
const ParamSettingDialogRef = ref<InstanceType<typeof ParamSettingDialog>>()
|
const ParamSettingDialogRef = ref<InstanceType<typeof ParamSettingDialog>>()
|
||||||
|
|
||||||
const applicationFormRef = ref<FormInstance>()
|
const applicationFormRef = ref<FormInstance>()
|
||||||
const AddDatasetDialogRef = ref()
|
const AddKnowledgeDialogRef = ref()
|
||||||
const EditAvatarDialogRef = ref()
|
const EditAvatarDialogRef = ref()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const datasetLoading = ref(false)
|
const knowledgeLoading = ref(false)
|
||||||
const applicationForm = ref<ApplicationFormType>({
|
const applicationForm = ref<ApplicationFormType>({
|
||||||
name: '',
|
name: '',
|
||||||
desc: '',
|
desc: '',
|
||||||
@ -578,7 +578,7 @@ const rules = reactive<FormRules<ApplicationFormType>>({
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
const modelOptions = ref<any>(null)
|
const modelOptions = ref<any>(null)
|
||||||
const datasetList = ref([])
|
const knowledgeList = ref([])
|
||||||
const sttModelOptions = ref<any>(null)
|
const sttModelOptions = ref<any>(null)
|
||||||
const ttsModelOptions = ref<any>(null)
|
const ttsModelOptions = ref<any>(null)
|
||||||
const showEditIcon = ref(false)
|
const showEditIcon = ref(false)
|
||||||
@ -660,7 +660,7 @@ function refreshTTSForm(data: any) {
|
|||||||
applicationForm.value.tts_model_params_setting = data
|
applicationForm.value.tts_model_params_setting = data
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeDataset(id: any) {
|
function removeKnowledge(id: any) {
|
||||||
if (applicationForm.value.knowledge_id_list) {
|
if (applicationForm.value.knowledge_id_list) {
|
||||||
applicationForm.value.knowledge_id_list.splice(
|
applicationForm.value.knowledge_id_list.splice(
|
||||||
applicationForm.value.knowledge_id_list.indexOf(id),
|
applicationForm.value.knowledge_id_list.indexOf(id),
|
||||||
@ -669,12 +669,12 @@ function removeDataset(id: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDataset(val: Array<string>) {
|
function addKnowledge(val: Array<string>) {
|
||||||
applicationForm.value.knowledge_id_list = val
|
applicationForm.value.knowledge_id_list = val
|
||||||
}
|
}
|
||||||
|
|
||||||
function openDatasetDialog() {
|
function openKnowledgeDialog() {
|
||||||
AddDatasetDialogRef.value.open(applicationForm.value.knowledge_id_list)
|
AddKnowledgeDialogRef.value.open(applicationForm.value.knowledge_id_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDetail() {
|
function getDetail() {
|
||||||
@ -692,9 +692,9 @@ function getDetail() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataset() {
|
function getKnowledge() {
|
||||||
application.asyncGetApplicationDataset(id, datasetLoading).then((res: any) => {
|
application.asyncGetApplicationKnowledge(id, knowledgeLoading).then((res: any) => {
|
||||||
datasetList.value = res.data
|
knowledgeList.value = res.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,12 +766,12 @@ function refreshIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
getDataset()
|
getKnowledge()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// getModel()
|
// getModel()
|
||||||
// getDataset()
|
// getKnowledge()
|
||||||
// getDetail()
|
// getDetail()
|
||||||
// getSTTModel()
|
// getSTTModel()
|
||||||
// getTTSModel()
|
// getTTSModel()
|
||||||
@ -779,7 +779,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.application-setting {
|
.application-setting {
|
||||||
.relate-dataset-card {
|
.relate-knowledge-card {
|
||||||
color: var(--app-text-color);
|
color: var(--app-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
166
ui/src/views/chat-log/component/ChatRecordDrawer.vue
Normal file
166
ui/src/views/chat-log/component/ChatRecordDrawer.vue
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer v-model="visible" size="60%" @close="closeHandle" class="chat-record-drawer">
|
||||||
|
<template #header>
|
||||||
|
<h4 class="single-line">{{ currentAbstract }}</h4>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-loading="paginationConfig.current_page === 1 && loading"
|
||||||
|
class="h-full"
|
||||||
|
style="padding: 24px 0"
|
||||||
|
>
|
||||||
|
<AiChat
|
||||||
|
ref="AiChatRef"
|
||||||
|
:application-details="application"
|
||||||
|
type="log"
|
||||||
|
:record="recordList"
|
||||||
|
@scroll="handleScroll"
|
||||||
|
>
|
||||||
|
</AiChat>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<el-button @click="pre" :disabled="pre_disable || loading">{{
|
||||||
|
$t('views.log.buttons.prev')
|
||||||
|
}}</el-button>
|
||||||
|
<el-button @click="next" :disabled="next_disable || loading">{{
|
||||||
|
$t('views.log.buttons.next')
|
||||||
|
}}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, watch, nextTick } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { type ApplicationFormType, type chatType } from '@/api/type/application'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
const AiChatRef = ref()
|
||||||
|
const { log } = useStore()
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
/**
|
||||||
|
* 应用信息
|
||||||
|
*/
|
||||||
|
application?: ApplicationFormType
|
||||||
|
/**
|
||||||
|
* 对话 记录id
|
||||||
|
*/
|
||||||
|
chatId: string
|
||||||
|
currentAbstract: string
|
||||||
|
/**
|
||||||
|
* 下一条
|
||||||
|
*/
|
||||||
|
next: () => void
|
||||||
|
/**
|
||||||
|
* 上一条
|
||||||
|
*/
|
||||||
|
pre: () => void
|
||||||
|
|
||||||
|
pre_disable: boolean
|
||||||
|
|
||||||
|
next_disable: boolean
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:chatId', 'update:currentAbstract', 'refresh'])
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const {
|
||||||
|
params: { id }
|
||||||
|
} = route
|
||||||
|
const loading = ref(false)
|
||||||
|
const visible = ref(false)
|
||||||
|
const recordList = ref<chatType[]>([])
|
||||||
|
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
current_page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
function closeHandle() {
|
||||||
|
recordList.value = []
|
||||||
|
paginationConfig.total = 0
|
||||||
|
paginationConfig.current_page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChatRecord() {
|
||||||
|
return log
|
||||||
|
.asyncChatRecordLog(id as string, props.chatId, paginationConfig, loading)
|
||||||
|
.then((res: any) => {
|
||||||
|
paginationConfig.total = res.data.total
|
||||||
|
const list = res.data.records
|
||||||
|
recordList.value = [...list, ...recordList.value].sort((a, b) =>
|
||||||
|
a.create_time.localeCompare(b.create_time)
|
||||||
|
)
|
||||||
|
if (paginationConfig.current_page === 1) {
|
||||||
|
nextTick(() => {
|
||||||
|
// 将滚动条滚动到最下面
|
||||||
|
AiChatRef.value.setScrollBottom()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.chatId,
|
||||||
|
() => {
|
||||||
|
recordList.value = []
|
||||||
|
paginationConfig.total = 0
|
||||||
|
paginationConfig.current_page = 1
|
||||||
|
if (props.chatId) {
|
||||||
|
getChatRecord()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(visible, (bool) => {
|
||||||
|
if (!bool) {
|
||||||
|
emit('update:chatId', '')
|
||||||
|
emit('update:currentAbstract', '')
|
||||||
|
emit('refresh')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleScroll(event: any) {
|
||||||
|
if (
|
||||||
|
props.chatId !== 'new' &&
|
||||||
|
event.scrollTop === 0 &&
|
||||||
|
paginationConfig.total > recordList.value.length
|
||||||
|
) {
|
||||||
|
const history_height = event.dialogScrollbar.offsetHeight
|
||||||
|
paginationConfig.current_page += 1
|
||||||
|
getChatRecord().then(() => {
|
||||||
|
event.scrollDiv.setScrollTop(event.dialogScrollbar.offsetHeight - history_height)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = () => {
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.single-line {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-record-drawer {
|
||||||
|
.el-drawer__body {
|
||||||
|
background: var(--app-layout-bg-color);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-divider__text) {
|
||||||
|
background: var(--app-layout-bg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
307
ui/src/views/chat-log/component/EditContentDialog.vue
Normal file
307
ui/src/views/chat-log/component/EditContentDialog.vue
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:title="$t('views.log.editContent')"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
width="600"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
label-position="top"
|
||||||
|
require-asterisk-position="right"
|
||||||
|
:rules="rules"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item :label="$t('views.paragraph.relatedProblem.title')">
|
||||||
|
<el-input
|
||||||
|
v-model="form.problem_text"
|
||||||
|
:placeholder="$t('views.paragraph.relatedProblem.title')"
|
||||||
|
maxlength="256"
|
||||||
|
show-word-limit
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('common.content')" prop="content">
|
||||||
|
<MdEditor
|
||||||
|
v-model="form.content"
|
||||||
|
:placeholder="$t('views.log.form.content.placeholder')"
|
||||||
|
:maxLength="100000"
|
||||||
|
:preview="false"
|
||||||
|
:toolbars="toolbars"
|
||||||
|
style="height: 300px"
|
||||||
|
@onUploadImg="onUploadImg"
|
||||||
|
:footers="footers"
|
||||||
|
>
|
||||||
|
<template #defFooters>
|
||||||
|
<span style="margin-left: -6px">/ 100000</span>
|
||||||
|
</template>
|
||||||
|
</MdEditor>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('common.title')">
|
||||||
|
<el-input
|
||||||
|
show-word-limit
|
||||||
|
v-model="form.title"
|
||||||
|
:placeholder="$t('views.log.form.title.placeholder')"
|
||||||
|
maxlength="256"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('views.log.selectDataset')" prop="dataset_id">
|
||||||
|
<el-select
|
||||||
|
v-model="form.dataset_id"
|
||||||
|
filterable
|
||||||
|
:placeholder="$t('views.log.selectDatasetPlaceholder')"
|
||||||
|
:loading="optionLoading"
|
||||||
|
@change="changeDataset"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in datasetList" :key="item.id" :label="item.name" :value="item.id">
|
||||||
|
<span class="flex align-center">
|
||||||
|
<AppAvatar
|
||||||
|
v-if="!item.dataset_id && item.type === '1'"
|
||||||
|
class="mr-12 avatar-purple"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
>
|
||||||
|
<img src="@/assets/icon_web.svg" style="width: 58%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
<AppAvatar
|
||||||
|
v-else-if="!item.dataset_id && item.type === '2'"
|
||||||
|
class="mr-8 avatar-purple"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
style="background: none"
|
||||||
|
>
|
||||||
|
<img src="@/assets/logo_lark.svg" style="width: 100%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
<AppAvatar
|
||||||
|
v-else-if="!item.dataset_id && item.type === '0'"
|
||||||
|
class="mr-12 avatar-blue"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
>
|
||||||
|
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('views.log.saveToDocument')" prop="document_id">
|
||||||
|
<el-select
|
||||||
|
v-model="form.document_id"
|
||||||
|
filterable
|
||||||
|
:placeholder="$t('views.log.documentPlaceholder')"
|
||||||
|
:loading="optionLoading"
|
||||||
|
@change="changeDocument"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in documentList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
|
||||||
|
<el-button type="primary" @click="submitForm(formRef)" :loading="loading">
|
||||||
|
{{ $t('common.save') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch, reactive } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import logApi from '@/api/log'
|
||||||
|
import imageApi from '@/api/image'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
import { t } from '@/locales'
|
||||||
|
const { application, document, user } = useStore()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const {
|
||||||
|
params: { id }
|
||||||
|
} = route as any
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh'])
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
const toolbars = [
|
||||||
|
'bold',
|
||||||
|
'underline',
|
||||||
|
'italic',
|
||||||
|
'-',
|
||||||
|
'title',
|
||||||
|
'strikeThrough',
|
||||||
|
'sub',
|
||||||
|
'sup',
|
||||||
|
'quote',
|
||||||
|
'unorderedList',
|
||||||
|
'orderedList',
|
||||||
|
'task',
|
||||||
|
'-',
|
||||||
|
'codeRow',
|
||||||
|
'code',
|
||||||
|
'link',
|
||||||
|
'image',
|
||||||
|
'table',
|
||||||
|
'mermaid',
|
||||||
|
'katex',
|
||||||
|
'-',
|
||||||
|
'revoke',
|
||||||
|
'next',
|
||||||
|
'=',
|
||||||
|
'pageFullscreen',
|
||||||
|
'preview',
|
||||||
|
'htmlPreview'
|
||||||
|
] as any[]
|
||||||
|
|
||||||
|
const footers = ['markdownTotal', 0, '=', 1, 'scrollSwitch']
|
||||||
|
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const form = ref<any>({
|
||||||
|
chat_id: '',
|
||||||
|
record_id: '',
|
||||||
|
problem_text: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
dataset_id: '',
|
||||||
|
document_id: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
content: [{ required: true, message: t('views.log.form.content.placeholder'), trigger: 'blur' }],
|
||||||
|
dataset_id: [
|
||||||
|
{ required: true, message: t('views.log.selectDatasetPlaceholder'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
document_id: [{ required: true, message: t('views.log.documentPlaceholder'), trigger: 'change' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const datasetList = ref<any[]>([])
|
||||||
|
const documentList = ref<any[]>([])
|
||||||
|
const optionLoading = ref(false)
|
||||||
|
|
||||||
|
watch(dialogVisible, (bool) => {
|
||||||
|
if (!bool) {
|
||||||
|
form.value = {
|
||||||
|
chat_id: '',
|
||||||
|
record_id: '',
|
||||||
|
problem_text: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
dataset_id: '',
|
||||||
|
document_id: ''
|
||||||
|
}
|
||||||
|
datasetList.value = []
|
||||||
|
documentList.value = []
|
||||||
|
formRef.value?.clearValidate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onUploadImg = async (files: any, callback: any) => {
|
||||||
|
const res = await Promise.all(
|
||||||
|
files.map((file: any) => {
|
||||||
|
return new Promise((rev, rej) => {
|
||||||
|
const fd = new FormData()
|
||||||
|
fd.append('file', file)
|
||||||
|
|
||||||
|
imageApi
|
||||||
|
.postImage(fd)
|
||||||
|
.then((res: any) => {
|
||||||
|
rev(res)
|
||||||
|
})
|
||||||
|
.catch((error) => rej(error))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
callback(res.map((item) => item.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDataset(dataset_id: string) {
|
||||||
|
localStorage.setItem(id + 'chat_dataset_id', dataset_id)
|
||||||
|
form.value.document_id = ''
|
||||||
|
getDocument(dataset_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDocument(document_id: string) {
|
||||||
|
localStorage.setItem(id + 'chat_document_id', document_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDocument(dataset_id: string) {
|
||||||
|
document.asyncGetAllDocument(dataset_id, loading).then((res: any) => {
|
||||||
|
documentList.value = res.data
|
||||||
|
if (localStorage.getItem(id + 'chat_document_id')) {
|
||||||
|
form.value.document_id = localStorage.getItem(id + 'chat_document_id') as string
|
||||||
|
}
|
||||||
|
if (!documentList.value.find((v) => v.id === form.value.document_id)) {
|
||||||
|
form.value.document_id = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDataset() {
|
||||||
|
application.asyncGetApplicationDataset(id, loading).then((res: any) => {
|
||||||
|
datasetList.value = res.data
|
||||||
|
if (localStorage.getItem(id + 'chat_dataset_id')) {
|
||||||
|
form.value.dataset_id = localStorage.getItem(id + 'chat_dataset_id') as string
|
||||||
|
if (!datasetList.value.find((v) => v.id === form.value.dataset_id)) {
|
||||||
|
form.value.dataset_id = ''
|
||||||
|
form.value.document_id = ''
|
||||||
|
} else {
|
||||||
|
getDocument(form.value.dataset_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = (data: any) => {
|
||||||
|
getDataset()
|
||||||
|
form.value.chat_id = data.chat_id
|
||||||
|
form.value.record_id = data.id
|
||||||
|
form.value.problem_text = data.problem_text ? data.problem_text.substring(0, 256) : ''
|
||||||
|
form.value.content = data.answer_text
|
||||||
|
formRef.value?.clearValidate()
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const obj = {
|
||||||
|
title: form.value.title,
|
||||||
|
content: form.value.content,
|
||||||
|
problem_text: form.value.problem_text
|
||||||
|
}
|
||||||
|
logApi
|
||||||
|
.putChatRecordLog(
|
||||||
|
id,
|
||||||
|
form.value.chat_id,
|
||||||
|
form.value.record_id,
|
||||||
|
form.value.dataset_id,
|
||||||
|
form.value.document_id,
|
||||||
|
obj,
|
||||||
|
loading
|
||||||
|
)
|
||||||
|
.then((res: any) => {
|
||||||
|
emit('refresh', res.data)
|
||||||
|
dialogVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
174
ui/src/views/chat-log/component/EditMarkDialog.vue
Normal file
174
ui/src/views/chat-log/component/EditMarkDialog.vue
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:title="$t('views.log.editMark')"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
width="600"
|
||||||
|
class="edit-mark-dialog"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<template #header="{ titleId, titleClass }">
|
||||||
|
<div class="flex-between">
|
||||||
|
<h4 :id="titleId" :class="titleClass">{{ $t('views.chatLog.editMark') }}</h4>
|
||||||
|
<div class="text-right">
|
||||||
|
<el-button text @click="isEdit = true" v-if="!isEdit">
|
||||||
|
<el-icon><EditPen /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button text style="margin-left: 4px" @click="deleteMark">
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-scrollbar>
|
||||||
|
<div style="min-height: 250px; max-height: 350px" v-loading="loading">
|
||||||
|
<el-form
|
||||||
|
v-if="isEdit"
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
label-position="top"
|
||||||
|
require-asterisk-position="right"
|
||||||
|
:rules="rules"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item prop="content">
|
||||||
|
<el-input
|
||||||
|
v-model="form.content"
|
||||||
|
:placeholder="$t('views.chatLog.form.content.placeholder')"
|
||||||
|
:maxlength="100000"
|
||||||
|
show-word-limit
|
||||||
|
:rows="15"
|
||||||
|
type="textarea"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span v-else class="pre-wrap">{{ form?.content }}</span>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer" v-if="isEdit">
|
||||||
|
<el-button @click.prevent="isEdit = false"> {{ $t('common.cancel') }} </el-button>
|
||||||
|
<el-button type="primary" @click="submit(formRef)" :loading="loading">
|
||||||
|
{{ $t('common.save') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch, reactive } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import chatLogApi from '@/api/application/chat-log'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
import { t } from '@/locales'
|
||||||
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const {
|
||||||
|
params: { id },
|
||||||
|
} = route as any
|
||||||
|
|
||||||
|
const { paragraph } = useStore()
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const form = ref<any>({})
|
||||||
|
const isEdit = ref(false)
|
||||||
|
const detail = ref<any>({})
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
content: [
|
||||||
|
{ required: true, message: t('views.chatLog.form.content.placeholder'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(dialogVisible, (bool) => {
|
||||||
|
if (!bool) {
|
||||||
|
form.value = {}
|
||||||
|
isEdit.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function deleteMark() {
|
||||||
|
chatLogApi
|
||||||
|
.delMarkChatRecord(
|
||||||
|
id as string,
|
||||||
|
detail.value.chat_id,
|
||||||
|
detail.value.id,
|
||||||
|
form.value.dataset,
|
||||||
|
form.value.document,
|
||||||
|
form.value.id,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
emit('refresh')
|
||||||
|
MsgSuccess(t('common.deleteSuccess'))
|
||||||
|
dialogVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMark(data: any) {
|
||||||
|
chatLogApi
|
||||||
|
.getMarkChatRecord(
|
||||||
|
id as string,
|
||||||
|
data.chat_id,
|
||||||
|
data.id,
|
||||||
|
data.dataset,
|
||||||
|
data.document,
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
form.value = res.data[0]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = (data: any) => {
|
||||||
|
detail.value = data
|
||||||
|
getMark(data)
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
const submit = async (formEl: FormInstance) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
paragraph
|
||||||
|
.asyncPutParagraph(
|
||||||
|
form.value.dataset,
|
||||||
|
form.value.document,
|
||||||
|
form.value.id,
|
||||||
|
{
|
||||||
|
content: form.value.content,
|
||||||
|
},
|
||||||
|
loading,
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.edit-mark-dialog {
|
||||||
|
.el-dialog__header.show-close {
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
.el-dialog__headerbtn {
|
||||||
|
top: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
662
ui/src/views/chat-log/index.vue
Normal file
662
ui/src/views/chat-log/index.vue
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
<template>
|
||||||
|
<LayoutContainer :header="$t('views.chatLog.title')">
|
||||||
|
<div class="p-24">
|
||||||
|
<div class="mb-16">
|
||||||
|
<el-select
|
||||||
|
v-model="history_day"
|
||||||
|
class="mr-12"
|
||||||
|
@change="changeDayHandle"
|
||||||
|
style="width: 180px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in dayOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-if="history_day === 'other'"
|
||||||
|
v-model="daterangeValue"
|
||||||
|
type="daterange"
|
||||||
|
:start-placeholder="$t('views.applicationOverview.monitor.startDatePlaceholder')"
|
||||||
|
:end-placeholder="$t('views.applicationOverview.monitor.endDatePlaceholder')"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
@change="changeDayRangeHandle"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="search"
|
||||||
|
@change="getList"
|
||||||
|
:placeholder="$t('common.search')"
|
||||||
|
prefix-icon="Search"
|
||||||
|
class="w-240"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<div style="display: flex; align-items: center" class="float-right">
|
||||||
|
<el-button @click="dialogVisible = true">{{
|
||||||
|
$t('views.chatLog.buttons.clearStrategy')
|
||||||
|
}}</el-button>
|
||||||
|
<el-button @click="exportLog">{{ $t('common.export') }}</el-button>
|
||||||
|
<el-button @click="openDocumentDialog" :disabled="multipleSelection.length === 0"
|
||||||
|
>{{ $t('views.chatLog.addToKnowledge') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<app-table
|
||||||
|
:data="tableData"
|
||||||
|
:pagination-config="paginationConfig"
|
||||||
|
@sizeChange="getList"
|
||||||
|
@changePage="getList"
|
||||||
|
@row-click="rowClickHandle"
|
||||||
|
v-loading="loading"
|
||||||
|
:row-class-name="setRowClass"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
class="log-table"
|
||||||
|
ref="multipleTableRef"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column
|
||||||
|
prop="abstract"
|
||||||
|
:label="$t('views.chatLog.table.abstract')"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="chat_record_count"
|
||||||
|
:label="$t('views.chatLog.table.chat_record_count')"
|
||||||
|
align="right"
|
||||||
|
/>
|
||||||
|
<el-table-column prop="star_num" align="right">
|
||||||
|
<template #header>
|
||||||
|
<div>
|
||||||
|
<span>{{ $t('views.chatLog.table.feedback.label') }}</span>
|
||||||
|
<el-popover :width="200" trigger="click" :visible="popoverVisible">
|
||||||
|
<template #reference>
|
||||||
|
<el-button
|
||||||
|
style="margin-top: -2px"
|
||||||
|
:type="filter.min_star || filter.min_trample ? 'primary' : ''"
|
||||||
|
link
|
||||||
|
@click="popoverVisible = !popoverVisible"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<Filter />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<div class="filter">
|
||||||
|
<div class="form-item mb-16">
|
||||||
|
<div @click.stop>
|
||||||
|
{{ $t('views.chatLog.table.feedback.star') }} >=
|
||||||
|
<el-input-number
|
||||||
|
v-model="filter.min_star"
|
||||||
|
:min="0"
|
||||||
|
:step="1"
|
||||||
|
:value-on-clear="0"
|
||||||
|
controls-position="right"
|
||||||
|
style="width: 80px"
|
||||||
|
size="small"
|
||||||
|
step-strictly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item mb-16">
|
||||||
|
<div @click.stop>
|
||||||
|
{{ $t('views.chatLog.table.feedback.trample') }} >=
|
||||||
|
<el-input-number
|
||||||
|
v-model="filter.min_trample"
|
||||||
|
:min="0"
|
||||||
|
:step="1"
|
||||||
|
:value-on-clear="0"
|
||||||
|
controls-position="right"
|
||||||
|
style="width: 80px"
|
||||||
|
size="small"
|
||||||
|
step-strictly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<el-button size="small" @click="filterChange('clear')">{{
|
||||||
|
$t('common.clear')
|
||||||
|
}}</el-button>
|
||||||
|
<el-button type="primary" @click="filterChange" size="small">{{
|
||||||
|
$t('common.confirm')
|
||||||
|
}}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="mr-8" v-if="!row.trample_num && !row.star_num"> - </span>
|
||||||
|
<span class="mr-8" v-else>
|
||||||
|
<span v-if="row.star_num">
|
||||||
|
<AppIcon iconName="app-like-color"></AppIcon>
|
||||||
|
{{ row.star_num }}
|
||||||
|
</span>
|
||||||
|
<span v-if="row.trample_num" class="ml-8">
|
||||||
|
<AppIcon iconName="app-oppose-color"></AppIcon>
|
||||||
|
{{ row.trample_num }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="mark_sum" :label="$t('views.chatLog.table.mark')" align="right" />
|
||||||
|
<el-table-column prop="asker" :label="$t('views.chatLog.table.user')">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.asker?.user_name }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('views.chatLog.table.recenTimes')" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ datetimeFormat(row.update_time) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</app-table>
|
||||||
|
</div>
|
||||||
|
<ChatRecordDrawer
|
||||||
|
:next="nextChatRecord"
|
||||||
|
:pre="preChatRecord"
|
||||||
|
ref="ChatRecordRef"
|
||||||
|
v-model:chatId="currentChatId"
|
||||||
|
v-model:currentAbstract="currentAbstract"
|
||||||
|
:application="detail"
|
||||||
|
:pre_disable="pre_disable"
|
||||||
|
:next_disable="next_disable"
|
||||||
|
@refresh="refresh"
|
||||||
|
/>
|
||||||
|
<el-dialog
|
||||||
|
:title="$t('views.chatLog.buttons.clearStrategy')"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
width="25%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<span>{{ $t('common.delete') }}</span>
|
||||||
|
<el-input-number
|
||||||
|
v-model="days"
|
||||||
|
controls-position="right"
|
||||||
|
:min="1"
|
||||||
|
:max="100000"
|
||||||
|
:value-on-clear="0"
|
||||||
|
step-strictly
|
||||||
|
style="width: 110px; margin-left: 8px; margin-right: 8px"
|
||||||
|
></el-input-number>
|
||||||
|
<span>{{ $t('views.chatLog.daysText') }}</span>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer" style="margin-top: 16px">
|
||||||
|
<el-button @click="dialogVisible = false">{{ $t('common.cancel') }} </el-button>
|
||||||
|
<el-button type="primary" @click="saveCleanTime">
|
||||||
|
{{ $t('common.save') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:title="$t('views.chatLog.addToKnowledge')"
|
||||||
|
v-model="documentDialogVisible"
|
||||||
|
width="50%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
label-position="top"
|
||||||
|
require-asterisk-position="right"
|
||||||
|
:rules="rules"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item :label="$t('views.chatLog.selectKnowledge')" prop="knowledge_id">
|
||||||
|
<el-select
|
||||||
|
v-model="form.knowledge_id"
|
||||||
|
filterable
|
||||||
|
:placeholder="$t('views.chatLog.selectKnowledgePlaceholder')"
|
||||||
|
:loading="optionLoading"
|
||||||
|
@change="changeKnowledge"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in knowledgeList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
<span class="flex align-center">
|
||||||
|
<AppAvatar
|
||||||
|
v-if="!item.knowledge_id && item.type === '1'"
|
||||||
|
class="mr-12 avatar-purple"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
>
|
||||||
|
<img src="@/assets/icon_web.svg" style="width: 58%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
<AppAvatar
|
||||||
|
v-else-if="!item.knowledge_id && item.type === '2'"
|
||||||
|
class="mr-12 avatar-purple"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
style="background: none"
|
||||||
|
>
|
||||||
|
<img src="@/assets/logo_lark.svg" style="width: 100%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
<AppAvatar
|
||||||
|
v-else-if="!item.knowledge_id && item.type === '0'"
|
||||||
|
class="mr-12 avatar-blue"
|
||||||
|
shape="square"
|
||||||
|
:size="24"
|
||||||
|
>
|
||||||
|
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('views.chatLog.saveToDocument')" prop="document_id">
|
||||||
|
<el-select
|
||||||
|
v-model="form.document_id"
|
||||||
|
filterable
|
||||||
|
:placeholder="$t('views.chatLog.documentPlaceholder')"
|
||||||
|
:loading="optionLoading"
|
||||||
|
@change="changeDocument"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in documentList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click.prevent="documentDialogVisible = false">
|
||||||
|
{{ $t('common.cancel') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm(formRef)" :loading="documentLoading">
|
||||||
|
{{ $t('common.save') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</LayoutContainer>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, type Ref, onMounted, reactive, computed } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
|
||||||
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||||
|
import chatLogApi from '@/api/application/chat-log'
|
||||||
|
import { beforeDay, datetimeFormat, nowDate } from '@/utils/time'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
import type { Dict } from '@/api/type/common'
|
||||||
|
import { t } from '@/locales'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { ElTable } from 'element-plus'
|
||||||
|
|
||||||
|
const { application, chatLog, document, user } = useStore()
|
||||||
|
const route = useRoute()
|
||||||
|
const {
|
||||||
|
params: { id },
|
||||||
|
} = route as any
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh'])
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
const dayOptions = [
|
||||||
|
{
|
||||||
|
value: 7,
|
||||||
|
// @ts-ignore
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.past7Days'), // 使用 t 方法来国际化显示文本
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 30,
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.past30Days'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 90,
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.past90Days'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 183,
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.past183Days'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'other',
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.other'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const daterangeValue = ref('')
|
||||||
|
// 提交日期时间
|
||||||
|
const daterange = ref({
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||||
|
const multipleSelection = ref<any[]>([])
|
||||||
|
|
||||||
|
const ChatRecordRef = ref()
|
||||||
|
const loading = ref(false)
|
||||||
|
const documentLoading = ref(false)
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
current_page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
total: 0,
|
||||||
|
})
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const documentDialogVisible = ref(false)
|
||||||
|
const days = ref<number>(180)
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const tableIndexMap = computed<Dict<number>>(() => {
|
||||||
|
return tableData.value
|
||||||
|
.map((row, index) => ({
|
||||||
|
[row.id]: index,
|
||||||
|
}))
|
||||||
|
.reduce((pre, next) => ({ ...pre, ...next }), {})
|
||||||
|
})
|
||||||
|
const history_day = ref<number | string>(7)
|
||||||
|
|
||||||
|
const search = ref('')
|
||||||
|
const detail = ref<any>(null)
|
||||||
|
|
||||||
|
const currentChatId = ref<string>('')
|
||||||
|
const currentAbstract = ref<string>('')
|
||||||
|
const popoverVisible = ref(false)
|
||||||
|
const defaultFilter = {
|
||||||
|
min_star: 0,
|
||||||
|
min_trample: 0,
|
||||||
|
comparer: 'and',
|
||||||
|
}
|
||||||
|
const filter = ref<any>({
|
||||||
|
min_star: 0,
|
||||||
|
min_trample: 0,
|
||||||
|
comparer: 'and',
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = ref<any>({
|
||||||
|
knowledge_id: '',
|
||||||
|
document_id: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
knowledge_id: [
|
||||||
|
{ required: true, message: t('views.chatLog.selectKnowledgePlaceholder'), trigger: 'change' },
|
||||||
|
],
|
||||||
|
document_id: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('views.chatLog.documentPlaceholder'),
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const optionLoading = ref(false)
|
||||||
|
const documentList = ref<any[]>([])
|
||||||
|
|
||||||
|
function filterChange(val: string) {
|
||||||
|
if (val === 'clear') {
|
||||||
|
filter.value = cloneDeep(defaultFilter)
|
||||||
|
}
|
||||||
|
getList()
|
||||||
|
popoverVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一页
|
||||||
|
*/
|
||||||
|
const nextChatRecord = () => {
|
||||||
|
let index = tableIndexMap.value[currentChatId.value] + 1
|
||||||
|
if (index >= tableData.value.length) {
|
||||||
|
if (
|
||||||
|
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
|
||||||
|
paginationConfig.total - 1
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paginationConfig.current_page = paginationConfig.current_page + 1
|
||||||
|
getList().then(() => {
|
||||||
|
index = 0
|
||||||
|
currentChatId.value = tableData.value[index].id
|
||||||
|
currentAbstract.value = tableData.value[index].abstract
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
currentChatId.value = tableData.value[index].id
|
||||||
|
currentAbstract.value = tableData.value[index].abstract
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const pre_disable = computed(() => {
|
||||||
|
let index = tableIndexMap.value[currentChatId.value] - 1
|
||||||
|
return index < 0 && paginationConfig.current_page <= 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const next_disable = computed(() => {
|
||||||
|
let index = tableIndexMap.value[currentChatId.value] + 1
|
||||||
|
return (
|
||||||
|
index >= tableData.value.length &&
|
||||||
|
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
|
||||||
|
paginationConfig.total - 1
|
||||||
|
)
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* 上一页
|
||||||
|
*/
|
||||||
|
const preChatRecord = () => {
|
||||||
|
let index = tableIndexMap.value[currentChatId.value] - 1
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
if (paginationConfig.current_page <= 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paginationConfig.current_page = paginationConfig.current_page - 1
|
||||||
|
getList().then(() => {
|
||||||
|
index = paginationConfig.page_size - 1
|
||||||
|
currentChatId.value = tableData.value[index].id
|
||||||
|
currentAbstract.value = tableData.value[index].abstract
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
currentChatId.value = tableData.value[index].id
|
||||||
|
currentAbstract.value = tableData.value[index].abstract
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowClickHandle(row: any, column?: any) {
|
||||||
|
if (column && column.type === 'selection') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentChatId.value = row.id
|
||||||
|
currentAbstract.value = row.abstract
|
||||||
|
ChatRecordRef.value.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
const setRowClass = ({ row }: any) => {
|
||||||
|
return currentChatId.value === row?.id ? 'highlight' : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelectionChange = (val: any[]) => {
|
||||||
|
multipleSelection.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// function deleteLog(row: any) {
|
||||||
|
// MsgConfirm(`是否删除对话:${row.abstract} ?`, `删除后无法恢复,请谨慎操作。`, {
|
||||||
|
// confirmButtonText: t('common.delete'),
|
||||||
|
// confirmButtonClass: 'danger'
|
||||||
|
// })
|
||||||
|
// .then(() => {
|
||||||
|
// loading.value = true
|
||||||
|
// logApi.delChatLog(id as string, row.id, loading).then(() => {
|
||||||
|
// MsgSuccess(t('common.deleteSuccess'))
|
||||||
|
// getList()
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// .catch(() => {})
|
||||||
|
// }
|
||||||
|
|
||||||
|
function getList() {
|
||||||
|
let obj: any = {
|
||||||
|
start_time: daterange.value.start_time,
|
||||||
|
end_time: daterange.value.end_time,
|
||||||
|
...filter.value,
|
||||||
|
}
|
||||||
|
if (search.value) {
|
||||||
|
obj = { ...obj, abstract: search.value }
|
||||||
|
}
|
||||||
|
return chatLog.asyncGetChatLog(id as string, paginationConfig, obj, loading).then((res: any) => {
|
||||||
|
tableData.value = res.data.records
|
||||||
|
if (currentChatId.value) {
|
||||||
|
currentChatId.value = tableData.value[0]?.id
|
||||||
|
}
|
||||||
|
paginationConfig.total = res.data.total
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDetail(isLoading = false) {
|
||||||
|
application
|
||||||
|
.asyncGetApplicationDetail(id as string, isLoading ? loading : undefined)
|
||||||
|
.then((res: any) => {
|
||||||
|
detail.value = res.data
|
||||||
|
days.value = res.data.clean_time
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const exportLog = () => {
|
||||||
|
const arr: string[] = []
|
||||||
|
multipleSelection.value.map((v) => {
|
||||||
|
if (v) {
|
||||||
|
arr.push(v.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (detail.value) {
|
||||||
|
let obj: any = {
|
||||||
|
start_time: daterange.value.start_time,
|
||||||
|
end_time: daterange.value.end_time,
|
||||||
|
...filter.value,
|
||||||
|
}
|
||||||
|
if (search.value) {
|
||||||
|
obj = { ...obj, abstract: search.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
chatLogApi.postExportChatLog(detail.value.id, detail.value.name, obj, { select_ids: arr }, loading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDayRangeHandle(val: string) {
|
||||||
|
daterange.value.start_time = val[0]
|
||||||
|
daterange.value.end_time = val[1]
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDayHandle(val: number | string) {
|
||||||
|
if (val !== 'other') {
|
||||||
|
daterange.value.start_time = beforeDay(val)
|
||||||
|
daterange.value.end_time = nowDate
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCleanTime() {
|
||||||
|
const obj = {
|
||||||
|
clean_time: days.value,
|
||||||
|
}
|
||||||
|
application
|
||||||
|
.asyncPutApplication(id as string, obj, loading)
|
||||||
|
.then(() => {
|
||||||
|
MsgSuccess(t('common.saveSuccess'))
|
||||||
|
dialogVisible.value = false
|
||||||
|
getDetail(true)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeKnowledge(knowledge_id: string) {
|
||||||
|
localStorage.setItem(id + 'chat_knowledge_id', knowledge_id)
|
||||||
|
form.value.document_id = ''
|
||||||
|
getDocument(knowledge_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDocument(document_id: string) {
|
||||||
|
localStorage.setItem(id + 'chat_document_id', document_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const knowledgeList = ref<any[]>([])
|
||||||
|
|
||||||
|
function getKnowledge() {
|
||||||
|
application.asyncGetApplicationKnowledge(id, documentLoading).then((res: any) => {
|
||||||
|
knowledgeList.value = res.data
|
||||||
|
if (localStorage.getItem(id + 'chat_knowledge_id')) {
|
||||||
|
form.value.knowledge_id = localStorage.getItem(id + 'chat_knowledge_id') as string
|
||||||
|
if (!knowledgeList.value.find((v) => v.id === form.value.knowledge_id)) {
|
||||||
|
form.value.knowledge_id = ''
|
||||||
|
form.value.document_id = ''
|
||||||
|
} else {
|
||||||
|
getDocument(form.value.knowledge_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
const arr: string[] = []
|
||||||
|
multipleSelection.value.map((v) => {
|
||||||
|
if (v) {
|
||||||
|
arr.push(v.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const obj = {
|
||||||
|
document_id: form.value.document_id,
|
||||||
|
knowledge_id: form.value.knowledge_id,
|
||||||
|
chat_ids: arr,
|
||||||
|
}
|
||||||
|
chatLogApi.postChatLogAddKnowledge(id, obj, documentLoading).then((res: any) => {
|
||||||
|
multipleTableRef.value?.clearSelection()
|
||||||
|
documentDialogVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDocument(knowledge_id: string) {
|
||||||
|
document.asyncGetAllDocument(knowledge_id, documentLoading).then((res: any) => {
|
||||||
|
documentList.value = res.data
|
||||||
|
if (localStorage.getItem(id + 'chat_document_id')) {
|
||||||
|
form.value.document_id = localStorage.getItem(id + 'chat_document_id') as string
|
||||||
|
}
|
||||||
|
if (!documentList.value.find((v) => v.id === form.value.document_id)) {
|
||||||
|
form.value.document_id = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDocumentDialog() {
|
||||||
|
getKnowledge()
|
||||||
|
formRef.value?.clearValidate()
|
||||||
|
documentDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
changeDayHandle(history_day.value)
|
||||||
|
getDetail()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.log-table {
|
||||||
|
:deep(tr) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -10,10 +10,10 @@
|
|||||||
label-width="auto"
|
label-width="auto"
|
||||||
ref="DatasetNodeFormRef"
|
ref="DatasetNodeFormRef"
|
||||||
>
|
>
|
||||||
<el-form-item :label="$t('views.log.selectDataset')">
|
<el-form-item :label="$t('views.chatLog.selectDataset')">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex-between">
|
<div class="flex-between">
|
||||||
<span>{{ $t('views.log.selectDataset') }}</span>
|
<span>{{ $t('views.chatLog.selectDataset') }}</span>
|
||||||
<el-button type="primary" link @click="openDatasetDialog">
|
<el-button type="primary" link @click="openDatasetDialog">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user