feat: 对话日志支持自定义时间

This commit is contained in:
wxg0103 2024-10-15 18:47:07 +08:00 committed by wxg0103
parent 451be0c81c
commit 3b995d34eb
5 changed files with 136 additions and 31 deletions

View File

@ -97,7 +97,8 @@ class ChatSerializers(serializers.Serializer):
class Query(serializers.Serializer):
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"))
application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("应用id"))
min_star = serializers.IntegerField(required=False, min_value=0,
@ -110,23 +111,34 @@ class ChatSerializers(serializers.Serializer):
])
def get_end_time(self):
history_day = self.data.get('history_day')
return datetime.datetime.now() - datetime.timedelta(days=history_day)
return datetime.datetime.combine(
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()
start_time = self.get_start_time()
query_set = QuerySet(model=get_dynamics_model(
{'application_chat.application_id': models.CharField(),
'application_chat.abstract': models.CharField(),
"star_num": models.IntegerField(),
'trample_num': models.IntegerField(),
'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"),
'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:
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)
min_star_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'),
str(row.get('create_time'))]
def export(self, with_valid=True):
def export(self, data, with_valid=True):
if with_valid:
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(
os.path.join(PROJECT_DIR, "apps", "application", 'sql',
'export_application_chat.sql')),

View File

@ -54,10 +54,10 @@ class ChatView(APIView):
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE,
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(
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):
authentication_classes = [TokenAuth]

View File

@ -1,5 +1,5 @@
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 Ref } from 'vue'
@ -34,9 +34,10 @@ const exportChatLog: (
application_id: string,
application_name: string,
param: any,
data: any,
loading?: Ref<boolean>
) => void = (application_id, application_name, param, loading) => {
exportExcel(application_name, `${prefix}/${application_id}/chat/export`, param, loading)
) => void = (application_id, application_name, param, data, loading) => {
exportExcelPost(application_name, `${prefix}/${application_id}/chat/export`, param, data, loading)
}
/**

View File

@ -240,6 +240,45 @@ export const exportExcel: (
.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: (
url: string,

View File

@ -2,7 +2,7 @@
<LayoutContainer header="对话日志">
<div class="p-24">
<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
v-for="item in dayOptions"
:key="item.value"
@ -10,12 +10,23 @@
: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="搜索"
prefix-icon="Search"
class="w-240"
style="margin-left: 10px"
clearable
/>
<el-button class="float-right" @click="exportLog">导出</el-button>
@ -29,8 +40,10 @@
@row-click="rowClickHandle"
v-loading="loading"
:row-class-name="setRowClass"
@selection-change="handleSelectionChange"
class="log-table"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="abstract" label="摘要" show-overflow-tooltip />
<el-table-column prop="chat_record_count" label="对话提问数" align="right" />
<el-table-column prop="star_num" align="right">
@ -45,7 +58,9 @@
link
@click="popoverVisible = !popoverVisible"
>
<el-icon><Filter /></el-icon>
<el-icon>
<Filter />
</el-icon>
</el-button>
</template>
<div class="filter">
@ -139,9 +154,11 @@ import { cloneDeep } from 'lodash'
import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import logApi from '@/api/log'
import { datetimeFormat } from '@/utils/time'
import { beforeDay, datetimeFormat, nowDate } from '@/utils/time'
import useStore from '@/stores'
import type { Dict } from '@/api/type/common'
import { t } from '@/locales'
const { application, log } = useStore()
const route = useRoute()
const {
@ -151,21 +168,33 @@ const {
const dayOptions = [
{
value: 7,
label: '过去7天'
// @ts-ignore
label: t('views.applicationOverview.monitor.pastDayOptions.past7Days') // 使 t
},
{
value: 30,
label: '过去30天'
label: t('views.applicationOverview.monitor.pastDayOptions.past30Days')
},
{
value: 90,
label: '过去90天'
label: t('views.applicationOverview.monitor.pastDayOptions.past90Days')
},
{
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 loading = ref(false)
@ -182,7 +211,8 @@ const tableIndexMap = computed<Dict<number>>(() => {
}))
.reduce((pre, next) => ({ ...pre, ...next }), {})
})
const history_day = ref(7)
const history_day = ref<number | string>(7)
const search = ref('')
const detail = ref<any>(null)
@ -279,6 +309,10 @@ 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: '删除',
@ -299,15 +333,11 @@ function handleSizeChange() {
getList()
}
function changeHandle(val: number) {
history_day.value = val
paginationConfig.current_page = 1
getList()
}
function getList() {
paginationConfig.current_page = 1
let obj: any = {
history_day: history_day.value,
start_time: daterange.value.start_time,
end_time: daterange.value.end_time,
...filter.value
}
if (search.value) {
@ -329,23 +359,46 @@ function getDetail() {
}
const exportLog = () => {
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
if (detail.value) {
let obj: any = {
history_day: history_day.value,
start_time: daterange.value.start_time,
end_time: daterange.value.end_time,
...filter.value
}
if (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() {
getList()
}
onMounted(() => {
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()
}
}
onMounted(() => {
changeDayHandle(history_day.value)
getDetail()
})
</script>