From e18b57e16d914e710021dca8a6ec38b8dcd02da9 Mon Sep 17 00:00:00 2001 From: Novice Lee Date: Thu, 19 Dec 2024 12:44:30 +0800 Subject: [PATCH 1/3] feat: add partial-success to app logs --- api/fields/conversation_fields.py | 3 ++- api/models/model.py | 24 ++++++++++++++++++++ web/app/components/app/log/list.tsx | 5 ++++ web/app/components/app/workflow-log/list.tsx | 8 +++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/api/fields/conversation_fields.py b/api/fields/conversation_fields.py index 5bd21be80779a4..6a9e347b1e04b4 100644 --- a/api/fields/conversation_fields.py +++ b/api/fields/conversation_fields.py @@ -85,7 +85,7 @@ def format(self, value): } feedback_stat_fields = {"like": fields.Integer, "dislike": fields.Integer} - +status_count_fields = {"success": fields.Integer, "failed": fields.Integer, "partial_success": fields.Integer} model_config_fields = { "opening_statement": fields.String, "suggested_questions": fields.Raw, @@ -166,6 +166,7 @@ def format(self, value): "message_count": fields.Integer, "user_feedback_stats": fields.Nested(feedback_stat_fields), "admin_feedback_stats": fields.Nested(feedback_stat_fields), + "status_count": fields.Nested(status_count_fields), } conversation_with_summary_pagination_fields = { diff --git a/api/models/model.py b/api/models/model.py index 03b8e0bea553aa..8b231e9c72faf0 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -19,6 +19,7 @@ from extensions.ext_database import db from libs.helper import generate_string from models.enums import CreatedByRole +from models.workflow import WorkflowRunStatus from .account import Account, Tenant from .types import StringUUID @@ -679,6 +680,29 @@ def admin_feedback_stats(self): return {"like": like, "dislike": dislike} + @property + def status_count(self): + messages = db.session.query(Message).filter(Message.conversation_id == self.id).all() + status_counts = { + WorkflowRunStatus.SUCCEEDED: 0, + WorkflowRunStatus.FAILED: 0, + WorkflowRunStatus.PARTIAL_SUCCESSED: 0, + } + + for message in messages: + if message.workflow_run: + status_counts[message.workflow_run.status] += 1 + + return ( + { + "success": status_counts[WorkflowRunStatus.SUCCEEDED], + "failed": status_counts[WorkflowRunStatus.FAILED], + "partial_success": status_counts[WorkflowRunStatus.PARTIAL_SUCCESSED], + } + if messages + else None + ) + @property def first_message(self): return db.session.query(Message).filter(Message.conversation_id == self.id).first() diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 8f064c209efe10..32479cf0563dd9 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -597,6 +597,7 @@ const ConversationList: FC = ({ logs, appDetail, onRefresh }) const [showDrawer, setShowDrawer] = useState(false) // Whether to display the chat details drawer const [currentConversation, setCurrentConversation] = useState() // 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 +640,7 @@ const ConversationList: FC = ({ logs, appDetail, onRefresh }) {isChatMode ? t('appLog.table.header.summary') : t('appLog.table.header.input')} {t('appLog.table.header.endUser')} + {isChatflow && {t('appLog.table.header.status')}} {isChatMode ? t('appLog.table.header.messageCount') : t('appLog.table.header.output')} {t('appLog.table.header.userRate')} {t('appLog.table.header.adminRate')} @@ -669,6 +671,9 @@ const ConversationList: FC = ({ logs, appDetail, onRefresh }) {renderTdValue(leftValue || t('appLog.table.empty.noChat'), !leftValue, isChatMode && log.annotated)} {renderTdValue(endUser || defaultValue, !endUser)} + {isChatflow && + {renderTdValue(`${log.status_count.success}/${log.status_count.failed}/${log.status_count.partial_success}`, false)} + } {renderTdValue(rightValue === 0 ? 0 : (rightValue || t('appLog.table.empty.noOutput')), !rightValue, !isChatMode && !!log.annotation?.content, log.annotation)} diff --git a/web/app/components/app/workflow-log/list.tsx b/web/app/components/app/workflow-log/list.tsx index e3de4a957f22e4..0f715f5cc396a1 100644 --- a/web/app/components/app/workflow-log/list.tsx +++ b/web/app/components/app/workflow-log/list.tsx @@ -63,6 +63,14 @@ const WorkflowAppLogList: FC = ({ logs, appDetail, onRefresh }) => { ) } + if (status === 'partial-succeeded') { + return ( +
+ + Partial Success +
+ ) + } } const onCloseDrawer = () => { From 15ee39e7b25cb39ce5164d1bc67d56fc8fb003d4 Mon Sep 17 00:00:00 2001 From: Novice Lee Date: Fri, 20 Dec 2024 09:11:45 +0800 Subject: [PATCH 2/3] feat: add style to chatflow log status --- web/app/components/app/log/list.tsx | 48 +++++++++++++++++--- web/app/components/app/workflow-log/list.tsx | 2 +- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 32479cf0563dd9..8b169b8cc84e8f 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -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 StatusShow = { + success: number + failed: number + partial_success: number +} + const DrawerContext = createContext({} as IDrawerContext) /** @@ -71,6 +78,33 @@ const HandThumbIconWithCount: FC<{ count: number; iconType: 'up' | 'down' }> = ( } +const statusTdRender = (status: StatusShow) => { + if (status.partial_success + status.failed === 0) { + return ( +
+ + Success +
+ ) + } + else if (status.failed === 0) { + return ( +
+ + Partial Success +
+ ) + } + else { + return ( +
+ + {status.failed} {`${status.failed > 1 ? 'Failures' : 'Failure'}`} +
+ ) + } +} + 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 = ({ logs, appDetail, onRefresh }) => { const { t } = useTranslation() const { formatTime } = useTimestamp() @@ -672,7 +706,7 @@ const ConversationList: FC = ({ logs, appDetail, onRefresh }) {renderTdValue(endUser || defaultValue, !endUser)} {isChatflow && - {renderTdValue(`${log.status_count.success}/${log.status_count.failed}/${log.status_count.partial_success}`, false)} + {statusTdRender(log.status_count)} } {renderTdValue(rightValue === 0 ? 0 : (rightValue || t('appLog.table.empty.noOutput')), !rightValue, !isChatMode && !!log.annotation?.content, log.annotation)} diff --git a/web/app/components/app/workflow-log/list.tsx b/web/app/components/app/workflow-log/list.tsx index 0f715f5cc396a1..41db9b5d466822 100644 --- a/web/app/components/app/workflow-log/list.tsx +++ b/web/app/components/app/workflow-log/list.tsx @@ -66,7 +66,7 @@ const WorkflowAppLogList: FC = ({ logs, appDetail, onRefresh }) => { if (status === 'partial-succeeded') { return (
- + Partial Success
) From 153d666f4cbfe2a6efea089a52fce28eafa67653 Mon Sep 17 00:00:00 2001 From: Novice Lee Date: Fri, 20 Dec 2024 11:05:31 +0800 Subject: [PATCH 3/3] fix: rename the status field --- web/app/components/app/log/list.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 8b169b8cc84e8f..383aeb1492c769 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -58,7 +58,7 @@ type IDrawerContext = { appDetail?: App } -type StatusShow = { +type StatusCount = { success: number failed: number partial_success: number @@ -78,8 +78,8 @@ const HandThumbIconWithCount: FC<{ count: number; iconType: 'up' | 'down' }> = ( } -const statusTdRender = (status: StatusShow) => { - if (status.partial_success + status.failed === 0) { +const statusTdRender = (statusCount: StatusCount) => { + if (statusCount.partial_success + statusCount.failed === 0) { return (
@@ -87,7 +87,7 @@ const statusTdRender = (status: StatusShow) => {
) } - else if (status.failed === 0) { + else if (statusCount.failed === 0) { return (
@@ -99,7 +99,7 @@ const statusTdRender = (status: StatusShow) => { return (
- {status.failed} {`${status.failed > 1 ? 'Failures' : 'Failure'}`} + {statusCount.failed} {`${statusCount.failed > 1 ? 'Failures' : 'Failure'}`}
) }