feat: 对话日志支持自定义时间
This commit is contained in:
parent
451be0c81c
commit
3b995d34eb
@ -97,7 +97,8 @@ class ChatSerializers(serializers.Serializer):
|
|||||||
|
|
||||||
class Query(serializers.Serializer):
|
class Query(serializers.Serializer):
|
||||||
abstract = serializers.CharField(required=False, error_messages=ErrMessage.char("摘要"))
|
abstract = serializers.CharField(required=False, error_messages=ErrMessage.char("摘要"))
|
||||||
history_day = serializers.IntegerField(required=True, error_messages=ErrMessage.integer("历史天数"))
|
start_time = serializers.DateField(format='%Y-%m-%d', error_messages=ErrMessage.date("开始时间"))
|
||||||
|
end_time = serializers.DateField(format='%Y-%m-%d', error_messages=ErrMessage.date("结束时间"))
|
||||||
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
|
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
|
||||||
application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("应用id"))
|
application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("应用id"))
|
||||||
min_star = serializers.IntegerField(required=False, min_value=0,
|
min_star = serializers.IntegerField(required=False, min_value=0,
|
||||||
@ -110,23 +111,34 @@ class ChatSerializers(serializers.Serializer):
|
|||||||
])
|
])
|
||||||
|
|
||||||
def get_end_time(self):
|
def get_end_time(self):
|
||||||
history_day = self.data.get('history_day')
|
return datetime.datetime.combine(
|
||||||
return datetime.datetime.now() - datetime.timedelta(days=history_day)
|
datetime.datetime.strptime(self.data.get('end_time'), '%Y-%m-%d'),
|
||||||
|
datetime.datetime.max.time())
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_start_time(self):
|
||||||
|
return self.data.get('start_time')
|
||||||
|
|
||||||
|
def get_query_set(self, select_ids=None):
|
||||||
end_time = self.get_end_time()
|
end_time = self.get_end_time()
|
||||||
|
start_time = self.get_start_time()
|
||||||
query_set = QuerySet(model=get_dynamics_model(
|
query_set = QuerySet(model=get_dynamics_model(
|
||||||
{'application_chat.application_id': models.CharField(),
|
{'application_chat.application_id': models.CharField(),
|
||||||
'application_chat.abstract': models.CharField(),
|
'application_chat.abstract': models.CharField(),
|
||||||
"star_num": models.IntegerField(),
|
"star_num": models.IntegerField(),
|
||||||
'trample_num': models.IntegerField(),
|
'trample_num': models.IntegerField(),
|
||||||
'comparer': models.CharField(),
|
'comparer': models.CharField(),
|
||||||
'application_chat.create_time': models.DateTimeField()}))
|
'application_chat.create_time': models.DateTimeField(),
|
||||||
|
'application_chat.id': models.UUIDField(), }))
|
||||||
|
|
||||||
base_query_dict = {'application_chat.application_id': self.data.get("application_id"),
|
base_query_dict = {'application_chat.application_id': self.data.get("application_id"),
|
||||||
'application_chat.create_time__gte': end_time}
|
'application_chat.create_time__gte': start_time,
|
||||||
|
'application_chat.create_time__lte': end_time,
|
||||||
|
}
|
||||||
if 'abstract' in self.data and self.data.get('abstract') is not None:
|
if 'abstract' in self.data and self.data.get('abstract') is not None:
|
||||||
base_query_dict['application_chat.abstract__icontains'] = self.data.get('abstract')
|
base_query_dict['application_chat.abstract__icontains'] = self.data.get('abstract')
|
||||||
|
|
||||||
|
if select_ids is not None and len(select_ids) > 0:
|
||||||
|
base_query_dict['application_chat.id__in'] = select_ids
|
||||||
base_condition = Q(**base_query_dict)
|
base_condition = Q(**base_query_dict)
|
||||||
min_star_query = None
|
min_star_query = None
|
||||||
min_trample_query = None
|
min_trample_query = None
|
||||||
@ -176,11 +188,11 @@ class ChatSerializers(serializers.Serializer):
|
|||||||
row.get('message_tokens') + row.get('answer_tokens'), row.get('run_time'),
|
row.get('message_tokens') + row.get('answer_tokens'), row.get('run_time'),
|
||||||
str(row.get('create_time'))]
|
str(row.get('create_time'))]
|
||||||
|
|
||||||
def export(self, with_valid=True):
|
def export(self, data, with_valid=True):
|
||||||
if with_valid:
|
if with_valid:
|
||||||
self.is_valid(raise_exception=True)
|
self.is_valid(raise_exception=True)
|
||||||
|
|
||||||
data_list = native_search(self.get_query_set(),
|
data_list = native_search(self.get_query_set(data.get('select_ids')),
|
||||||
select_string=get_file_content(
|
select_string=get_file_content(
|
||||||
os.path.join(PROJECT_DIR, "apps", "application", 'sql',
|
os.path.join(PROJECT_DIR, "apps", "application", 'sql',
|
||||||
'export_application_chat.sql')),
|
'export_application_chat.sql')),
|
||||||
|
|||||||
@ -54,10 +54,10 @@ class ChatView(APIView):
|
|||||||
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE,
|
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE,
|
||||||
dynamic_tag=keywords.get('application_id'))])
|
dynamic_tag=keywords.get('application_id'))])
|
||||||
)
|
)
|
||||||
def get(self, request: Request, application_id: str):
|
def post(self, request: Request, application_id: str):
|
||||||
return ChatSerializers.Query(
|
return ChatSerializers.Query(
|
||||||
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
|
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
|
||||||
'user_id': request.user.id}).export()
|
'user_id': request.user.id}).export(request.data)
|
||||||
|
|
||||||
class Open(APIView):
|
class Open(APIView):
|
||||||
authentication_classes = [TokenAuth]
|
authentication_classes = [TokenAuth]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from '@/request/Result'
|
import { Result } from '@/request/Result'
|
||||||
import { get, del, put, exportExcel } from '@/request/index'
|
import { get, del, put, exportExcel, exportExcelPost } from '@/request/index'
|
||||||
import type { pageRequest } from '@/api/type/common'
|
import type { pageRequest } from '@/api/type/common'
|
||||||
import { type Ref } from 'vue'
|
import { type Ref } from 'vue'
|
||||||
|
|
||||||
@ -34,9 +34,10 @@ const exportChatLog: (
|
|||||||
application_id: string,
|
application_id: string,
|
||||||
application_name: string,
|
application_name: string,
|
||||||
param: any,
|
param: any,
|
||||||
|
data: any,
|
||||||
loading?: Ref<boolean>
|
loading?: Ref<boolean>
|
||||||
) => void = (application_id, application_name, param, loading) => {
|
) => void = (application_id, application_name, param, data, loading) => {
|
||||||
exportExcel(application_name, `${prefix}/${application_id}/chat/export`, param, loading)
|
exportExcelPost(application_name, `${prefix}/${application_id}/chat/export`, param, data, loading)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -240,6 +240,45 @@ export const exportExcel: (
|
|||||||
.catch((e) => {})
|
.catch((e) => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportExcelPost: (
|
||||||
|
fileName: string,
|
||||||
|
url: string,
|
||||||
|
params: any,
|
||||||
|
data: any,
|
||||||
|
loading?: NProgress | Ref<boolean>
|
||||||
|
) => Promise<any> = (
|
||||||
|
fileName: string,
|
||||||
|
url: string,
|
||||||
|
params: any,
|
||||||
|
data: any,
|
||||||
|
loading?: NProgress | Ref<boolean>
|
||||||
|
) => {
|
||||||
|
return promise(
|
||||||
|
request({
|
||||||
|
url: url,
|
||||||
|
method: 'post',
|
||||||
|
params, // 查询字符串参数
|
||||||
|
data, // 请求体数据
|
||||||
|
responseType: 'blob'
|
||||||
|
}),
|
||||||
|
loading
|
||||||
|
)
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res) {
|
||||||
|
const blob = new Blob([res], {
|
||||||
|
type: 'application/vnd.ms-excel'
|
||||||
|
})
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = window.URL.createObjectURL(blob)
|
||||||
|
link.download = fileName
|
||||||
|
link.click()
|
||||||
|
// 释放内存
|
||||||
|
window.URL.revokeObjectURL(link.href)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
.catch((e) => {})
|
||||||
|
}
|
||||||
|
|
||||||
export const download: (
|
export const download: (
|
||||||
url: string,
|
url: string,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<LayoutContainer header="对话日志">
|
<LayoutContainer header="对话日志">
|
||||||
<div class="p-24">
|
<div class="p-24">
|
||||||
<div class="mb-16">
|
<div class="mb-16">
|
||||||
<el-select v-model="history_day" class="mr-12 w-240" @change="changeHandle">
|
<el-select v-model="history_day" class="mr-12 w-120" @change="changeDayHandle">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in dayOptions"
|
v-for="item in dayOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@ -10,12 +10,23 @@
|
|||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</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
|
<el-input
|
||||||
v-model="search"
|
v-model="search"
|
||||||
@change="getList"
|
@change="getList"
|
||||||
placeholder="搜索"
|
placeholder="搜索"
|
||||||
prefix-icon="Search"
|
prefix-icon="Search"
|
||||||
class="w-240"
|
class="w-240"
|
||||||
|
style="margin-left: 10px"
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
<el-button class="float-right" @click="exportLog">导出</el-button>
|
<el-button class="float-right" @click="exportLog">导出</el-button>
|
||||||
@ -29,8 +40,10 @@
|
|||||||
@row-click="rowClickHandle"
|
@row-click="rowClickHandle"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:row-class-name="setRowClass"
|
:row-class-name="setRowClass"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
class="log-table"
|
class="log-table"
|
||||||
>
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column prop="abstract" label="摘要" show-overflow-tooltip />
|
<el-table-column prop="abstract" label="摘要" show-overflow-tooltip />
|
||||||
<el-table-column prop="chat_record_count" label="对话提问数" align="right" />
|
<el-table-column prop="chat_record_count" label="对话提问数" align="right" />
|
||||||
<el-table-column prop="star_num" align="right">
|
<el-table-column prop="star_num" align="right">
|
||||||
@ -45,7 +58,9 @@
|
|||||||
link
|
link
|
||||||
@click="popoverVisible = !popoverVisible"
|
@click="popoverVisible = !popoverVisible"
|
||||||
>
|
>
|
||||||
<el-icon><Filter /></el-icon>
|
<el-icon>
|
||||||
|
<Filter />
|
||||||
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
@ -139,9 +154,11 @@ import { cloneDeep } from 'lodash'
|
|||||||
import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
|
import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
|
||||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||||
import logApi from '@/api/log'
|
import logApi from '@/api/log'
|
||||||
import { datetimeFormat } from '@/utils/time'
|
import { beforeDay, datetimeFormat, nowDate } from '@/utils/time'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import type { Dict } from '@/api/type/common'
|
import type { Dict } from '@/api/type/common'
|
||||||
|
import { t } from '@/locales'
|
||||||
|
|
||||||
const { application, log } = useStore()
|
const { application, log } = useStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const {
|
const {
|
||||||
@ -151,21 +168,33 @@ const {
|
|||||||
const dayOptions = [
|
const dayOptions = [
|
||||||
{
|
{
|
||||||
value: 7,
|
value: 7,
|
||||||
label: '过去7天'
|
// @ts-ignore
|
||||||
|
label: t('views.applicationOverview.monitor.pastDayOptions.past7Days') // 使用 t 方法来国际化显示文本
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 30,
|
value: 30,
|
||||||
label: '过去30天'
|
label: t('views.applicationOverview.monitor.pastDayOptions.past30Days')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 90,
|
value: 90,
|
||||||
label: '过去90天'
|
label: t('views.applicationOverview.monitor.pastDayOptions.past90Days')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 183,
|
value: 183,
|
||||||
label: '过去半年'
|
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 multipleSelection = ref<any[]>([])
|
||||||
|
|
||||||
const ChatRecordRef = ref()
|
const ChatRecordRef = ref()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@ -182,7 +211,8 @@ const tableIndexMap = computed<Dict<number>>(() => {
|
|||||||
}))
|
}))
|
||||||
.reduce((pre, next) => ({ ...pre, ...next }), {})
|
.reduce((pre, next) => ({ ...pre, ...next }), {})
|
||||||
})
|
})
|
||||||
const history_day = ref(7)
|
const history_day = ref<number | string>(7)
|
||||||
|
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const detail = ref<any>(null)
|
const detail = ref<any>(null)
|
||||||
|
|
||||||
@ -279,6 +309,10 @@ const setRowClass = ({ row }: any) => {
|
|||||||
return currentChatId.value === row?.id ? 'highlight' : ''
|
return currentChatId.value === row?.id ? 'highlight' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSelectionChange = (val: any[]) => {
|
||||||
|
multipleSelection.value = val
|
||||||
|
}
|
||||||
|
|
||||||
function deleteLog(row: any) {
|
function deleteLog(row: any) {
|
||||||
MsgConfirm(`是否删除对话:${row.abstract} ?`, `删除后无法恢复,请谨慎操作。`, {
|
MsgConfirm(`是否删除对话:${row.abstract} ?`, `删除后无法恢复,请谨慎操作。`, {
|
||||||
confirmButtonText: '删除',
|
confirmButtonText: '删除',
|
||||||
@ -299,15 +333,11 @@ function handleSizeChange() {
|
|||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeHandle(val: number) {
|
|
||||||
history_day.value = val
|
|
||||||
paginationConfig.current_page = 1
|
|
||||||
getList()
|
|
||||||
}
|
|
||||||
|
|
||||||
function getList() {
|
function getList() {
|
||||||
|
paginationConfig.current_page = 1
|
||||||
let obj: any = {
|
let obj: any = {
|
||||||
history_day: history_day.value,
|
start_time: daterange.value.start_time,
|
||||||
|
end_time: daterange.value.end_time,
|
||||||
...filter.value
|
...filter.value
|
||||||
}
|
}
|
||||||
if (search.value) {
|
if (search.value) {
|
||||||
@ -329,23 +359,46 @@ function getDetail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const exportLog = () => {
|
const exportLog = () => {
|
||||||
|
const arr: string[] = []
|
||||||
|
multipleSelection.value.map((v) => {
|
||||||
|
if (v) {
|
||||||
|
arr.push(v.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
if (detail.value) {
|
if (detail.value) {
|
||||||
let obj: any = {
|
let obj: any = {
|
||||||
history_day: history_day.value,
|
start_time: daterange.value.start_time,
|
||||||
|
end_time: daterange.value.end_time,
|
||||||
...filter.value
|
...filter.value
|
||||||
}
|
}
|
||||||
if (search.value) {
|
if (search.value) {
|
||||||
obj = { ...obj, abstract: search.value }
|
obj = { ...obj, abstract: search.value }
|
||||||
}
|
}
|
||||||
logApi.exportChatLog(detail.value.id, detail.value.name, obj, loading)
|
|
||||||
|
logApi.exportChatLog(detail.value.id, detail.value.name, obj, { select_ids: arr }, loading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
function changeDayRangeHandle(val: string) {
|
||||||
|
daterange.value.start_time = val[0]
|
||||||
|
daterange.value.end_time = val[1]
|
||||||
getList()
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDayHandle(val: number | string) {
|
||||||
|
if (val !== 'other') {
|
||||||
|
daterange.value.start_time = beforeDay(val)
|
||||||
|
daterange.value.end_time = nowDate
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
changeDayHandle(history_day.value)
|
||||||
getDetail()
|
getDetail()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user