|
|
|
@@ -16,6 +16,7 @@ import { createContext, useContext } from 'use-context-selector' |
|
|
|
import { useShallow } from 'zustand/react/shallow' |
|
|
|
import { useTranslation } from 'react-i18next' |
|
|
|
import type { ChatItemInTree } from '../../base/chat/types' |
|
|
|
import Indicator from '../../header/indicator' |
|
|
|
import VarPanel from './var-panel' |
|
|
|
import type { FeedbackFunc, FeedbackType, IChatItem, SubmitAnnotationFunc } from '@/app/components/base/chat/chat/type' |
|
|
|
import type { Annotation, ChatConversationGeneralDetail, ChatConversationsResponse, ChatMessage, ChatMessagesRequest, CompletionConversationGeneralDetail, CompletionConversationsResponse, LogAnnotation } from '@/models/log' |
|
|
|
@@ -57,6 +58,12 @@ type IDrawerContext = { |
|
|
|
appDetail?: App |
|
|
|
} |
|
|
|
|
|
|
|
type StatusCount = { |
|
|
|
success: number |
|
|
|
failed: number |
|
|
|
partial_success: number |
|
|
|
} |
|
|
|
|
|
|
|
const DrawerContext = createContext<IDrawerContext>({} as IDrawerContext) |
|
|
|
|
|
|
|
/** |
|
|
|
@@ -71,6 +78,33 @@ const HandThumbIconWithCount: FC<{ count: number; iconType: 'up' | 'down' }> = ( |
|
|
|
</div> |
|
|
|
} |
|
|
|
|
|
|
|
const statusTdRender = (statusCount: StatusCount) => { |
|
|
|
if (statusCount.partial_success + statusCount.failed === 0) { |
|
|
|
return ( |
|
|
|
<div className='inline-flex items-center gap-1 system-xs-semibold-uppercase'> |
|
|
|
<Indicator color={'green'} /> |
|
|
|
<span className='text-util-colors-green-green-600'>Success</span> |
|
|
|
</div> |
|
|
|
) |
|
|
|
} |
|
|
|
else if (statusCount.failed === 0) { |
|
|
|
return ( |
|
|
|
<div className='inline-flex items-center gap-1 system-xs-semibold-uppercase'> |
|
|
|
<Indicator color={'green'} /> |
|
|
|
<span className='text-util-colors-green-green-600'>Partial Success</span> |
|
|
|
</div> |
|
|
|
) |
|
|
|
} |
|
|
|
else { |
|
|
|
return ( |
|
|
|
<div className='inline-flex items-center gap-1 system-xs-semibold-uppercase'> |
|
|
|
<Indicator color={'red'} /> |
|
|
|
<span className='text-util-colors-red-red-600'>{statusCount.failed} {`${statusCount.failed > 1 ? 'Failures' : 'Failure'}`}</span> |
|
|
|
</div> |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const getFormattedChatList = (messages: ChatMessage[], conversationId: string, timezone: string, format: string) => { |
|
|
|
const newChatList: IChatItem[] = [] |
|
|
|
messages.forEach((item: ChatMessage) => { |
|
|
|
@@ -496,8 +530,8 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Text App Conversation Detail Component |
|
|
|
*/ |
|
|
|
* Text App Conversation Detail Component |
|
|
|
*/ |
|
|
|
const CompletionConversationDetailComp: FC<{ appId?: string; conversationId?: string }> = ({ appId, conversationId }) => { |
|
|
|
// Text Generator App Session Details Including Message List |
|
|
|
const detailParams = ({ url: `/apps/${appId}/completion-conversations/${conversationId}` }) |
|
|
|
@@ -542,8 +576,8 @@ const CompletionConversationDetailComp: FC<{ appId?: string; conversationId?: st |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Chat App Conversation Detail Component |
|
|
|
*/ |
|
|
|
* Chat App Conversation Detail Component |
|
|
|
*/ |
|
|
|
const ChatConversationDetailComp: FC<{ appId?: string; conversationId?: string }> = ({ appId, conversationId }) => { |
|
|
|
const detailParams = { url: `/apps/${appId}/chat-conversations/${conversationId}` } |
|
|
|
const { data: conversationDetail } = useSWR(() => (appId && conversationId) ? detailParams : null, fetchChatConversationDetail) |
|
|
|
@@ -585,8 +619,8 @@ const ChatConversationDetailComp: FC<{ appId?: string; conversationId?: string } |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Conversation list component including basic information |
|
|
|
*/ |
|
|
|
* Conversation list component including basic information |
|
|
|
*/ |
|
|
|
const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh }) => { |
|
|
|
const { t } = useTranslation() |
|
|
|
const { formatTime } = useTimestamp() |
|
|
|
@@ -597,6 +631,7 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh }) |
|
|
|
const [showDrawer, setShowDrawer] = useState<boolean>(false) // Whether to display the chat details drawer |
|
|
|
const [currentConversation, setCurrentConversation] = useState<ChatConversationGeneralDetail | CompletionConversationGeneralDetail | undefined>() // Currently selected conversation |
|
|
|
const isChatMode = appDetail.mode !== 'completion' // Whether the app is a chat app |
|
|
|
const isChatflow = appDetail.mode === 'advanced-chat' // Whether the app is a chatflow app |
|
|
|
const { setShowPromptLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({ |
|
|
|
setShowPromptLogModal: state.setShowPromptLogModal, |
|
|
|
setShowAgentLogModal: state.setShowAgentLogModal, |
|
|
|
@@ -639,6 +674,7 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh }) |
|
|
|
<td className='pl-2 pr-1 w-5 rounded-l-lg bg-background-section-burn whitespace-nowrap'></td> |
|
|
|
<td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{isChatMode ? t('appLog.table.header.summary') : t('appLog.table.header.input')}</td> |
|
|
|
<td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{t('appLog.table.header.endUser')}</td> |
|
|
|
{isChatflow && <td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{t('appLog.table.header.status')}</td>} |
|
|
|
<td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{isChatMode ? t('appLog.table.header.messageCount') : t('appLog.table.header.output')}</td> |
|
|
|
<td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{t('appLog.table.header.userRate')}</td> |
|
|
|
<td className='pl-3 py-1.5 bg-background-section-burn whitespace-nowrap'>{t('appLog.table.header.adminRate')}</td> |
|
|
|
@@ -669,6 +705,9 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh }) |
|
|
|
{renderTdValue(leftValue || t('appLog.table.empty.noChat'), !leftValue, isChatMode && log.annotated)} |
|
|
|
</td> |
|
|
|
<td className='p-3 pr-2'>{renderTdValue(endUser || defaultValue, !endUser)}</td> |
|
|
|
{isChatflow && <td className='p-3 pr-2 w-[160px]' style={{ maxWidth: isChatMode ? 300 : 200 }}> |
|
|
|
{statusTdRender(log.status_count)} |
|
|
|
</td>} |
|
|
|
<td className='p-3 pr-2' style={{ maxWidth: isChatMode ? 100 : 200 }}> |
|
|
|
{renderTdValue(rightValue === 0 ? 0 : (rightValue || t('appLog.table.empty.noOutput')), !rightValue, !isChatMode && !!log.annotation?.content, log.annotation)} |
|
|
|
</td> |