import { getChannelList, getChannelLog, getLogDetail } from '@/web/core/ai/channel'; import { getSystemModelList } from '@/web/core/ai/config'; import { useUserStore } from '@/web/support/user/useUserStore'; import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Box, Flex, Button, HStack, ModalBody, Grid, GridItem, BoxProps } from '@chakra-ui/react'; import { getModelProvider } from '@fastgpt/global/core/ai/provider'; import DateRangePicker, { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker'; import MyBox from '@fastgpt/web/components/common/MyBox'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import MySelect from '@fastgpt/web/components/common/MySelect'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination'; import { addDays } from 'date-fns'; import { useTranslation } from 'next-i18next'; import React, { useCallback, useMemo, useState } from 'react'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time'; import MyModal from '@fastgpt/web/components/common/MyModal'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; type LogDetailType = { id: number; request_id: string; channelName: string | number; model: React.JSX.Element; duration: number; request_at: string; code: number; prompt_tokens: number; completion_tokens: number; endpoint: string; content?: string; request_body?: string; response_body?: string; }; const ChannelLog = ({ Tab }: { Tab: React.ReactNode }) => { const { t } = useTranslation(); const { userInfo } = useUserStore(); const isRoot = userInfo?.username === 'root'; const [filterProps, setFilterProps] = useState<{ channelId?: string; model?: string; code_type: 'all' | 'success' | 'error'; dateRange: DateRangeType; }>({ code_type: 'all', dateRange: { from: (() => { const today = addDays(new Date(), -1); today.setHours(0, 0, 0, 0); return today; })(), to: (() => { const today = new Date(); today.setHours(23, 59, 59, 999); return today; })() } }); const { data: channelList = [] } = useRequest2( async () => { const res = await getChannelList().then((res) => res.map((item) => ({ label: item.name, value: `${item.id}` })) ); return [ { label: t('common:common.All'), value: '' }, ...res ]; }, { manual: false } ); const { data: systemModelList = [] } = useRequest2(getSystemModelList, { manual: false }); const modelList = useMemo(() => { const res = systemModelList .map((item) => { const provider = getModelProvider(item.provider); return { order: provider.order, icon: provider.avatar, label: item.model, value: item.model }; }) .sort((a, b) => a.order - b.order); return [ { label: t('common:common.All'), value: '' }, ...res ]; }, [systemModelList, t]); const { data, isLoading, ScrollData } = useScrollPagination(getChannelLog, { pageSize: 20, refreshDeps: [filterProps], params: { channel: filterProps.channelId, model_name: filterProps.model, code_type: filterProps.code_type, start_timestamp: filterProps.dateRange.from?.getTime() || 0, end_timestamp: filterProps.dateRange.to?.getTime() || 0 } }); const formatData = useMemo(() => { return data.map((item) => { const duration = item.created_at - item.request_at; const durationSecond = duration / 1000; const channelName = channelList.find((channel) => channel.value === `${item.channel}`)?.label; const model = systemModelList.find((model) => model.model === item.model); const provider = getModelProvider(model?.provider); return { id: item.id, channelName: channelName || item.channel, model: ( {model?.model} ), duration: durationSecond, request_at: formatTime2YMDHMS(item.request_at), code: item.code, prompt_tokens: item.prompt_tokens, completion_tokens: item.completion_tokens, request_id: item.request_id, endpoint: item.endpoint, content: item.content }; }); }, [channelList, data, systemModelList]); const [logDetail, setLogDetail] = useState(); return ( <> {isRoot && ( {Tab} )} {t('common:user.Time')} setFilterProps({ ...filterProps, dateRange: e })} /> {t('account_model:channel_name')} bg={'myGray.50'} isSearch list={channelList} placeholder={t('account_model:select_channel')} value={filterProps.channelId} onchange={(val) => setFilterProps({ ...filterProps, channelId: val })} /> {t('account_model:model_name')} bg={'myGray.50'} isSearch list={modelList} placeholder={t('account_model:select_model')} value={filterProps.model} onchange={(val) => setFilterProps({ ...filterProps, model: val })} /> {t('account_model:log_status')} bg={'myGray.50'} list={[ { label: t('common:common.All'), value: 'all' }, { label: t('common:common.Success'), value: 'success' }, { label: t('common:common.failed'), value: 'error' } ]} value={filterProps.code_type} onchange={(val) => setFilterProps({ ...filterProps, code_type: val })} /> {formatData.map((item) => ( ))}
{t('account_model:channel_name')} {t('account_model:model')} {t('account_model:model_tokens')} {t('account_model:duration')} {t('account_model:channel_status')} {t('account_model:request_at')}
{item.channelName} {item.model} {item.prompt_tokens} / {item.completion_tokens} 10 ? 'red.600' : ''}>{item.duration.toFixed(2)}s {item.code} {item.content && } {item.request_at}
{!!logDetail && setLogDetail(undefined)} />} ); }; export default ChannelLog; const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void }) => { const { t } = useTranslation(); const { data: detailData } = useRequest2( async () => { if (data.code === 200) return data; const res = await getLogDetail(data.id); return { ...res, ...data }; }, { manual: false } ); const Title = useCallback(({ children, ...props }: { children: React.ReactNode } & BoxProps) => { return ( {children} ); }, []); const Container = useCallback( ({ children, ...props }: { children: React.ReactNode } & BoxProps) => { return ( {children} ); }, [] ); return ( {detailData && ( {/* 基本信息表格 */} {/* 第一行 */} RequestID {detailData?.request_id} {t('account_model:channel_status')} {detailData?.code} Endpoint {detailData?.endpoint} {t('account_model:channel_name')} {detailData?.channelName} {t('account_model:request_at')} {detailData?.request_at} {t('account_model:duration')} {detailData?.duration.toFixed(2)}s {t('account_model:model')} {detailData?.model} {t('account_model:model_tokens')} {detailData?.prompt_tokens} / {detailData?.completion_tokens} {detailData?.content && ( Content {detailData?.content} )} {detailData?.request_body && ( Request Body {detailData?.request_body} )} {detailData?.response_body && ( Response Body {detailData?.response_body} )} )} ); };