瀏覽代碼

feat: stop response call api (#340)

Joel 1 年之前
父節點
當前提交
b16a7b0b3b

+ 3 - 1
web/app/components/app/chat/index.tsx

@@ -53,6 +53,7 @@ export type IChatProps = {
   displayScene?: DisplayScene
   useCurrentUserAvatar?: boolean
   isResponsing?: boolean
+  canStopResponsing?: boolean
   abortResponsing?: () => void
   controlClearQuery?: number
   controlFocus?: number
@@ -412,6 +413,7 @@ const Chat: FC<IChatProps> = ({
   displayScene,
   useCurrentUserAvatar,
   isResponsing,
+  canStopResponsing,
   abortResponsing,
   controlClearQuery,
   controlFocus,
@@ -508,7 +510,7 @@ const Chat: FC<IChatProps> = ({
       {
         !isHideSendInput && (
           <div className={cn(!feedbackDisabled && '!left-3.5 !right-3.5', 'absolute z-10 bottom-0 left-0 right-0')}>
-            {isResponsing && (
+            {(isResponsing && canStopResponsing) && (
               <div className='flex justify-center mb-4'>
                 <Button className='flex items-center space-x-1 bg-white' onClick={() => abortResponsing?.()}>
                   {stopIcon}

+ 7 - 3
web/app/components/app/configuration/debug/index.tsx

@@ -16,7 +16,7 @@ import type { IChatItem } from '@/app/components/app/chat'
 import Chat from '@/app/components/app/chat'
 import ConfigContext from '@/context/debug-configuration'
 import { ToastContext } from '@/app/components/base/toast'
-import { fetchConvesationMessages, fetchSuggestedQuestions, sendChatMessage, sendCompletionMessage } from '@/service/debug'
+import { fetchConvesationMessages, fetchSuggestedQuestions, sendChatMessage, sendCompletionMessage, stopChatMessageResponding } from '@/service/debug'
 import Button from '@/app/components/base/button'
 import type { ModelConfig as BackendModelConfig } from '@/types/app'
 import { promptVariablesToUserInputsForm } from '@/utils/model-config'
@@ -136,6 +136,7 @@ const Debug: FC<IDebug> = ({
 
   const doShowSuggestion = isShowSuggestion && !isResponsing
   const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
+  const [messageTaskId, setMessageTaskId] = useState('')
   const onSend = async (message: string) => {
     if (isResponsing) {
       notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
@@ -208,12 +209,13 @@ const Debug: FC<IDebug> = ({
       getAbortController: (abortController) => {
         setAbortController(abortController)
       },
-      onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId }: any) => {
+      onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
         responseItem.content = responseItem.content + message
         if (isFirstMessage && newConversationId) {
           setConversationId(newConversationId)
           _newConversationId = newConversationId
         }
+        setMessageTaskId(taskId)
         if (messageId)
           responseItem.id = messageId
 
@@ -375,8 +377,10 @@ const Debug: FC<IDebug> = ({
                   feedbackDisabled
                   useCurrentUserAvatar
                   isResponsing={isResponsing}
-                  abortResponsing={() => {
+                  canStopResponsing={!!messageTaskId}
+                  abortResponsing={async () => {
                     abortController?.abort()
+                    await stopChatMessageResponding(appId, messageTaskId)
                     setResponsingFalse()
                   }}
                   isShowSuggestion={doShowSuggestion}

+ 7 - 3
web/app/components/share/chat/index.tsx

@@ -14,7 +14,7 @@ import { ToastContext } from '@/app/components/base/toast'
 import Sidebar from '@/app/components/share/chat/sidebar'
 import ConfigSence from '@/app/components/share/chat/config-scence'
 import Header from '@/app/components/share/header'
-import { fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, sendChatMessage, updateFeedback } from '@/service/share'
+import { fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, sendChatMessage, stopChatMessageResponding, updateFeedback } from '@/service/share'
 import type { ConversationItem, SiteInfo } from '@/models/share'
 import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
 import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
@@ -332,6 +332,7 @@ const Main: FC<IMainProps> = ({
   const [isShowSuggestion, setIsShowSuggestion] = useState(false)
   const doShowSuggestion = isShowSuggestion && !isResponsing
   const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
+  const [messageTaskId, setMessageTaskId] = useState('')
   const handleSend = async (message: string) => {
     if (isResponsing) {
       notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
@@ -376,12 +377,13 @@ const Main: FC<IMainProps> = ({
       getAbortController: (abortController) => {
         setAbortController(abortController)
       },
-      onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId }: any) => {
+      onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
         responseItem.content = responseItem.content + message
         responseItem.id = messageId
         if (isFirstMessage && newConversationId)
           tempNewConversationId = newConversationId
 
+        setMessageTaskId(taskId)
         // closesure new list is outdated.
         const newListWithAnswer = produce(
           getChatList().filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
@@ -532,8 +534,10 @@ const Main: FC<IMainProps> = ({
                     isHideFeedbackEdit
                     onFeedback={handleFeedback}
                     isResponsing={isResponsing}
-                    abortResponsing={() => {
+                    canStopResponsing={!!messageTaskId}
+                    abortResponsing={async () => {
                       abortController?.abort()
+                      await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
                       setResponsingFalse()
                     }}
                     checkCanSend={checkCanSend}

+ 3 - 1
web/service/base.ts

@@ -23,7 +23,8 @@ const baseOptions = {
 }
 
 export type IOnDataMoreInfo = {
-  conversationId: string | undefined
+  conversationId?: string
+  taskId?: string
   messageId: string
   errorMessage?: string
 }
@@ -101,6 +102,7 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted
             // can not use format here. Because message is splited.
             onData(unicodeToChar(bufferObj.answer), isFirstMessage, {
               conversationId: bufferObj.conversation_id,
+              taskId: bufferObj.task_id,
               messageId: bufferObj.id,
             })
             isFirstMessage = false

+ 4 - 0
web/service/debug.ts

@@ -15,6 +15,10 @@ export const sendChatMessage = async (appId: string, body: Record<string, any>,
   }, { onData, onCompleted, onError, getAbortController })
 }
 
+export const stopChatMessageResponding = async (appId: string, taskId: string) => {
+  return post(`apps/${appId}/chat-messages/${taskId}/stop`)
+}
+
 export const sendCompletionMessage = async (appId: string, body: Record<string, any>, { onData, onCompleted, onError }: {
   onData: IOnData
   onCompleted: IOnCompleted

+ 4 - 0
web/service/share.ts

@@ -34,6 +34,10 @@ export const sendChatMessage = async (body: Record<string, any>, { onData, onCom
   }, { onData, onCompleted, isPublicAPI: !isInstalledApp, onError, getAbortController })
 }
 
+export const stopChatMessageResponding = async (appId: string, taskId: string, isInstalledApp: boolean, installedAppId = '') => {
+  return getAction('post', isInstalledApp)(getUrl(`chat-messages/${taskId}/stop`, isInstalledApp, installedAppId))
+}
+
 export const sendCompletionMessage = async (body: Record<string, any>, { onData, onCompleted, onError }: {
   onData: IOnData
   onCompleted: IOnCompleted