mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-15 22:06:52 +08:00
feat: stop response call api (#340)
This commit is contained in:
@@ -53,6 +53,7 @@ export type IChatProps = {
|
|||||||
displayScene?: DisplayScene
|
displayScene?: DisplayScene
|
||||||
useCurrentUserAvatar?: boolean
|
useCurrentUserAvatar?: boolean
|
||||||
isResponsing?: boolean
|
isResponsing?: boolean
|
||||||
|
canStopResponsing?: boolean
|
||||||
abortResponsing?: () => void
|
abortResponsing?: () => void
|
||||||
controlClearQuery?: number
|
controlClearQuery?: number
|
||||||
controlFocus?: number
|
controlFocus?: number
|
||||||
@@ -412,6 +413,7 @@ const Chat: FC<IChatProps> = ({
|
|||||||
displayScene,
|
displayScene,
|
||||||
useCurrentUserAvatar,
|
useCurrentUserAvatar,
|
||||||
isResponsing,
|
isResponsing,
|
||||||
|
canStopResponsing,
|
||||||
abortResponsing,
|
abortResponsing,
|
||||||
controlClearQuery,
|
controlClearQuery,
|
||||||
controlFocus,
|
controlFocus,
|
||||||
@@ -508,7 +510,7 @@ const Chat: FC<IChatProps> = ({
|
|||||||
{
|
{
|
||||||
!isHideSendInput && (
|
!isHideSendInput && (
|
||||||
<div className={cn(!feedbackDisabled && '!left-3.5 !right-3.5', 'absolute z-10 bottom-0 left-0 right-0')}>
|
<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'>
|
<div className='flex justify-center mb-4'>
|
||||||
<Button className='flex items-center space-x-1 bg-white' onClick={() => abortResponsing?.()}>
|
<Button className='flex items-center space-x-1 bg-white' onClick={() => abortResponsing?.()}>
|
||||||
{stopIcon}
|
{stopIcon}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import type { IChatItem } from '@/app/components/app/chat'
|
|||||||
import Chat from '@/app/components/app/chat'
|
import Chat from '@/app/components/app/chat'
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
import { ToastContext } from '@/app/components/base/toast'
|
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 Button from '@/app/components/base/button'
|
||||||
import type { ModelConfig as BackendModelConfig } from '@/types/app'
|
import type { ModelConfig as BackendModelConfig } from '@/types/app'
|
||||||
import { promptVariablesToUserInputsForm } from '@/utils/model-config'
|
import { promptVariablesToUserInputsForm } from '@/utils/model-config'
|
||||||
@@ -136,6 +136,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
|
|
||||||
const doShowSuggestion = isShowSuggestion && !isResponsing
|
const doShowSuggestion = isShowSuggestion && !isResponsing
|
||||||
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
||||||
|
const [messageTaskId, setMessageTaskId] = useState('')
|
||||||
const onSend = async (message: string) => {
|
const onSend = async (message: string) => {
|
||||||
if (isResponsing) {
|
if (isResponsing) {
|
||||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
|
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
|
||||||
@@ -208,12 +209,13 @@ const Debug: FC<IDebug> = ({
|
|||||||
getAbortController: (abortController) => {
|
getAbortController: (abortController) => {
|
||||||
setAbortController(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.content = responseItem.content + message
|
||||||
if (isFirstMessage && newConversationId) {
|
if (isFirstMessage && newConversationId) {
|
||||||
setConversationId(newConversationId)
|
setConversationId(newConversationId)
|
||||||
_newConversationId = newConversationId
|
_newConversationId = newConversationId
|
||||||
}
|
}
|
||||||
|
setMessageTaskId(taskId)
|
||||||
if (messageId)
|
if (messageId)
|
||||||
responseItem.id = messageId
|
responseItem.id = messageId
|
||||||
|
|
||||||
@@ -375,8 +377,10 @@ const Debug: FC<IDebug> = ({
|
|||||||
feedbackDisabled
|
feedbackDisabled
|
||||||
useCurrentUserAvatar
|
useCurrentUserAvatar
|
||||||
isResponsing={isResponsing}
|
isResponsing={isResponsing}
|
||||||
abortResponsing={() => {
|
canStopResponsing={!!messageTaskId}
|
||||||
|
abortResponsing={async () => {
|
||||||
abortController?.abort()
|
abortController?.abort()
|
||||||
|
await stopChatMessageResponding(appId, messageTaskId)
|
||||||
setResponsingFalse()
|
setResponsingFalse()
|
||||||
}}
|
}}
|
||||||
isShowSuggestion={doShowSuggestion}
|
isShowSuggestion={doShowSuggestion}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { ToastContext } from '@/app/components/base/toast'
|
|||||||
import Sidebar from '@/app/components/share/chat/sidebar'
|
import Sidebar from '@/app/components/share/chat/sidebar'
|
||||||
import ConfigSence from '@/app/components/share/chat/config-scence'
|
import ConfigSence from '@/app/components/share/chat/config-scence'
|
||||||
import Header from '@/app/components/share/header'
|
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 { ConversationItem, SiteInfo } from '@/models/share'
|
||||||
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
||||||
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
|
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
|
||||||
@@ -332,6 +332,7 @@ const Main: FC<IMainProps> = ({
|
|||||||
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
|
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
|
||||||
const doShowSuggestion = isShowSuggestion && !isResponsing
|
const doShowSuggestion = isShowSuggestion && !isResponsing
|
||||||
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
||||||
|
const [messageTaskId, setMessageTaskId] = useState('')
|
||||||
const handleSend = async (message: string) => {
|
const handleSend = async (message: string) => {
|
||||||
if (isResponsing) {
|
if (isResponsing) {
|
||||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
|
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
|
||||||
@@ -376,12 +377,13 @@ const Main: FC<IMainProps> = ({
|
|||||||
getAbortController: (abortController) => {
|
getAbortController: (abortController) => {
|
||||||
setAbortController(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.content = responseItem.content + message
|
||||||
responseItem.id = messageId
|
responseItem.id = messageId
|
||||||
if (isFirstMessage && newConversationId)
|
if (isFirstMessage && newConversationId)
|
||||||
tempNewConversationId = newConversationId
|
tempNewConversationId = newConversationId
|
||||||
|
|
||||||
|
setMessageTaskId(taskId)
|
||||||
// closesure new list is outdated.
|
// closesure new list is outdated.
|
||||||
const newListWithAnswer = produce(
|
const newListWithAnswer = produce(
|
||||||
getChatList().filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
|
getChatList().filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
|
||||||
@@ -532,8 +534,10 @@ const Main: FC<IMainProps> = ({
|
|||||||
isHideFeedbackEdit
|
isHideFeedbackEdit
|
||||||
onFeedback={handleFeedback}
|
onFeedback={handleFeedback}
|
||||||
isResponsing={isResponsing}
|
isResponsing={isResponsing}
|
||||||
abortResponsing={() => {
|
canStopResponsing={!!messageTaskId}
|
||||||
|
abortResponsing={async () => {
|
||||||
abortController?.abort()
|
abortController?.abort()
|
||||||
|
await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
|
||||||
setResponsingFalse()
|
setResponsingFalse()
|
||||||
}}
|
}}
|
||||||
checkCanSend={checkCanSend}
|
checkCanSend={checkCanSend}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ const baseOptions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type IOnDataMoreInfo = {
|
export type IOnDataMoreInfo = {
|
||||||
conversationId: string | undefined
|
conversationId?: string
|
||||||
|
taskId?: string
|
||||||
messageId: string
|
messageId: string
|
||||||
errorMessage?: string
|
errorMessage?: string
|
||||||
}
|
}
|
||||||
@@ -101,6 +102,7 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted
|
|||||||
// can not use format here. Because message is splited.
|
// can not use format here. Because message is splited.
|
||||||
onData(unicodeToChar(bufferObj.answer), isFirstMessage, {
|
onData(unicodeToChar(bufferObj.answer), isFirstMessage, {
|
||||||
conversationId: bufferObj.conversation_id,
|
conversationId: bufferObj.conversation_id,
|
||||||
|
taskId: bufferObj.task_id,
|
||||||
messageId: bufferObj.id,
|
messageId: bufferObj.id,
|
||||||
})
|
})
|
||||||
isFirstMessage = false
|
isFirstMessage = false
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ export const sendChatMessage = async (appId: string, body: Record<string, any>,
|
|||||||
}, { onData, onCompleted, onError, getAbortController })
|
}, { 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 }: {
|
export const sendCompletionMessage = async (appId: string, body: Record<string, any>, { onData, onCompleted, onError }: {
|
||||||
onData: IOnData
|
onData: IOnData
|
||||||
onCompleted: IOnCompleted
|
onCompleted: IOnCompleted
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ export const sendChatMessage = async (body: Record<string, any>, { onData, onCom
|
|||||||
}, { onData, onCompleted, isPublicAPI: !isInstalledApp, onError, getAbortController })
|
}, { 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 }: {
|
export const sendCompletionMessage = async (body: Record<string, any>, { onData, onCompleted, onError }: {
|
||||||
onData: IOnData
|
onData: IOnData
|
||||||
onCompleted: IOnCompleted
|
onCompleted: IOnCompleted
|
||||||
|
|||||||
Reference in New Issue
Block a user