mirror of https://github.com/langgenius/dify.git
web app support workflow
This commit is contained in:
parent
58922ba40b
commit
bcce53a929
|
|
@ -25,6 +25,7 @@ import EditReplyModal from '@/app/components/app/annotation/edit-annotation-moda
|
|||
|
||||
const MAX_DEPTH = 3
|
||||
export type IGenerationItemProps = {
|
||||
isWorkflow?: boolean
|
||||
className?: string
|
||||
isError: boolean
|
||||
onRetry: () => void
|
||||
|
|
@ -75,6 +76,7 @@ export const copyIcon = (
|
|||
)
|
||||
|
||||
const GenerationItem: FC<IGenerationItemProps> = ({
|
||||
isWorkflow,
|
||||
className,
|
||||
isError,
|
||||
onRetry,
|
||||
|
|
@ -137,6 +139,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
isInstalledApp,
|
||||
installedAppId,
|
||||
controlClearMoreLikeThis,
|
||||
isWorkflow,
|
||||
}
|
||||
|
||||
const handleMoreLikeThis = async () => {
|
||||
|
|
@ -191,7 +194,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
|
||||
const ratingContent = (
|
||||
<>
|
||||
{!isError && messageId && !feedback?.rating && (
|
||||
{!isWorkflow && !isError && messageId && !feedback?.rating && (
|
||||
<SimpleBtn className="!px-0">
|
||||
<>
|
||||
<div
|
||||
|
|
@ -215,7 +218,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
</>
|
||||
</SimpleBtn>
|
||||
)}
|
||||
{!isError && messageId && feedback?.rating === 'like' && (
|
||||
{!isWorkflow && !isError && messageId && feedback?.rating === 'like' && (
|
||||
<div
|
||||
onClick={() => {
|
||||
onFeedback?.({
|
||||
|
|
@ -226,7 +229,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
<HandThumbUpIcon width={16} height={16} />
|
||||
</div>
|
||||
)}
|
||||
{!isError && messageId && feedback?.rating === 'dislike' && (
|
||||
{!isWorkflow && !isError && messageId && feedback?.rating === 'dislike' && (
|
||||
<div
|
||||
onClick={() => {
|
||||
onFeedback?.({
|
||||
|
|
@ -308,14 +311,16 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
</SimpleBtn>
|
||||
{isInWebApp && (
|
||||
<>
|
||||
<SimpleBtn
|
||||
isDisabled={isError || !messageId}
|
||||
className={cn(isMobile && '!px-1.5', 'ml-2 space-x-1')}
|
||||
onClick={() => { onSave?.(messageId as string) }}
|
||||
>
|
||||
<Bookmark className='w-3.5 h-3.5' />
|
||||
{!isMobile && <div>{t('common.operation.save')}</div>}
|
||||
</SimpleBtn>
|
||||
{!isWorkflow && (
|
||||
<SimpleBtn
|
||||
isDisabled={isError || !messageId}
|
||||
className={cn(isMobile && '!px-1.5', 'ml-2 space-x-1')}
|
||||
onClick={() => { onSave?.(messageId as string) }}
|
||||
>
|
||||
<Bookmark className='w-3.5 h-3.5' />
|
||||
{!isMobile && <div>{t('common.operation.save')}</div>}
|
||||
</SimpleBtn>
|
||||
)}
|
||||
{(moreLikeThis && depth < MAX_DEPTH) && (
|
||||
<SimpleBtn
|
||||
isDisabled={isError || !messageId}
|
||||
|
|
@ -324,15 +329,20 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||
>
|
||||
<Stars02 className='w-3.5 h-3.5' />
|
||||
{!isMobile && <div>{t('appDebug.feature.moreLikeThis.title')}</div>}
|
||||
</SimpleBtn>)}
|
||||
{isError && <SimpleBtn
|
||||
onClick={onRetry}
|
||||
className={cn(isMobile && '!px-1.5', 'ml-2 space-x-1')}
|
||||
>
|
||||
<RefreshCcw01 className='w-3.5 h-3.5' />
|
||||
{!isMobile && <div>{t('share.generation.batchFailed.retry')}</div>}
|
||||
</SimpleBtn>}
|
||||
{!isError && messageId && <div className="mx-3 w-[1px] h-[14px] bg-gray-200"></div>}
|
||||
</SimpleBtn>
|
||||
)}
|
||||
{isError && (
|
||||
<SimpleBtn
|
||||
onClick={onRetry}
|
||||
className={cn(isMobile && '!px-1.5', 'ml-2 space-x-1')}
|
||||
>
|
||||
<RefreshCcw01 className='w-3.5 h-3.5' />
|
||||
{!isMobile && <div>{t('share.generation.batchFailed.retry')}</div>}
|
||||
</SimpleBtn>
|
||||
)}
|
||||
{!isError && messageId && !isWorkflow && (
|
||||
<div className="mx-3 w-[1px] h-[14px] bg-gray-200"></div>
|
||||
)}
|
||||
{ratingContent}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,15 @@ const InstalledApp: FC<IInstalledAppProps> = ({
|
|||
|
||||
return (
|
||||
<div className='h-full py-2 pl-0 pr-2 sm:p-2'>
|
||||
{installedApp?.app.mode === 'chat'
|
||||
? (
|
||||
<ChatWithHistory installedAppInfo={installedApp} className='rounded-2xl shadow-md overflow-hidden' />
|
||||
)
|
||||
: (
|
||||
<TextGenerationApp isInstalledApp installedAppInfo={installedApp}/>
|
||||
)}
|
||||
{installedApp.app.mode !== 'completion' && installedApp.app.mode !== 'workflow' && (
|
||||
<ChatWithHistory installedAppInfo={installedApp} className='rounded-2xl shadow-md overflow-hidden' />
|
||||
)}
|
||||
{installedApp.app.mode === 'completion' && (
|
||||
<TextGenerationApp isInstalledApp installedAppInfo={installedApp}/>
|
||||
)}
|
||||
{installedApp.app.mode === 'workflow' && (
|
||||
<TextGenerationApp isWorkflow isInstalledApp installedAppInfo={installedApp}/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,7 +348,6 @@ const TextGeneration: FC<IMainProps> = ({
|
|||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
console.log('isWorkflow', isWorkflow)
|
||||
const [appData, appParams]: any = await fetchInitData()
|
||||
const { app_id: appId, site: siteInfo, can_replace_logo } = appData
|
||||
setAppId(appId)
|
||||
|
|
@ -395,6 +394,7 @@ const TextGeneration: FC<IMainProps> = ({
|
|||
|
||||
const renderRes = (task?: Task) => (<Res
|
||||
key={task?.id}
|
||||
isWorkflow={isWorkflow}
|
||||
isCallBatchAPI={isCallBatchAPI}
|
||||
isPC={isPC}
|
||||
isMobile={isMobile}
|
||||
|
|
@ -534,18 +534,20 @@ const TextGeneration: FC<IMainProps> = ({
|
|||
items={[
|
||||
{ id: 'create', name: t('share.generation.tabs.create') },
|
||||
{ id: 'batch', name: t('share.generation.tabs.batch') },
|
||||
{
|
||||
id: 'saved',
|
||||
name: t('share.generation.tabs.saved'),
|
||||
isRight: true,
|
||||
extra: savedMessages.length > 0
|
||||
? (
|
||||
<div className='ml-1 flext items-center h-5 px-1.5 rounded-md border border-gray-200 text-gray-500 text-xs font-medium'>
|
||||
{savedMessages.length}
|
||||
</div>
|
||||
)
|
||||
: null,
|
||||
},
|
||||
...(!isWorkflow
|
||||
? [{
|
||||
id: 'saved',
|
||||
name: t('share.generation.tabs.saved'),
|
||||
isRight: true,
|
||||
extra: savedMessages.length > 0
|
||||
? (
|
||||
<div className='ml-1 flext items-center h-5 px-1.5 rounded-md border border-gray-200 text-gray-500 text-xs font-medium'>
|
||||
{savedMessages.length}
|
||||
</div>
|
||||
)
|
||||
: null,
|
||||
}]
|
||||
: []),
|
||||
]}
|
||||
value={currTab}
|
||||
onChange={setCurrTab}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import cn from 'classnames'
|
|||
import TextGenerationRes from '@/app/components/app/text-generate/item'
|
||||
import NoData from '@/app/components/share/text-generation/no-data'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { sendCompletionMessage, updateFeedback } from '@/service/share'
|
||||
import { sendCompletionMessage, sendWorkflowMessage, updateFeedback } from '@/service/share'
|
||||
import type { Feedbacktype } from '@/app/components/app/chat/type'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import type { PromptConfig } from '@/models/debug'
|
||||
|
|
@ -16,6 +16,7 @@ import type { ModerationService } from '@/models/common'
|
|||
import { TransferMethod, type VisionFile, type VisionSettings } from '@/types/app'
|
||||
|
||||
export type IResultProps = {
|
||||
isWorkflow: boolean
|
||||
isCallBatchAPI: boolean
|
||||
isPC: boolean
|
||||
isMobile: boolean
|
||||
|
|
@ -40,6 +41,7 @@ export type IResultProps = {
|
|||
}
|
||||
|
||||
const Result: FC<IResultProps> = ({
|
||||
isWorkflow,
|
||||
isCallBatchAPI,
|
||||
isPC,
|
||||
isMobile,
|
||||
|
|
@ -176,34 +178,71 @@ const Result: FC<IResultProps> = ({
|
|||
isTimeout = true
|
||||
}
|
||||
}, 1000)
|
||||
sendCompletionMessage(data, {
|
||||
onData: (data: string, _isFirstMessage: boolean, { messageId }) => {
|
||||
tempMessageId = messageId
|
||||
res.push(data)
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onCompleted: () => {
|
||||
if (isTimeout)
|
||||
return
|
||||
|
||||
setRespondingFalse()
|
||||
setMessageId(tempMessageId)
|
||||
onCompleted(getCompletionRes(), taskId, true)
|
||||
clearInterval(runId)
|
||||
},
|
||||
onMessageReplace: (messageReplace) => {
|
||||
res = [messageReplace.answer]
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onError() {
|
||||
if (isTimeout)
|
||||
return
|
||||
|
||||
setRespondingFalse()
|
||||
onCompleted(getCompletionRes(), taskId, false)
|
||||
clearInterval(runId)
|
||||
},
|
||||
}, isInstalledApp, installedAppInfo?.id)
|
||||
if (isWorkflow) {
|
||||
// ###TODO###
|
||||
sendWorkflowMessage(
|
||||
data,
|
||||
{
|
||||
onWorkflowStarted: ({ workflow_run_id }) => {
|
||||
tempMessageId = workflow_run_id
|
||||
},
|
||||
onTextChunk: ({ data }) => {
|
||||
res.push(data.text)
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onWorkflowFinished: () => {
|
||||
if (isTimeout)
|
||||
return
|
||||
setRespondingFalse()
|
||||
setMessageId(tempMessageId)
|
||||
onCompleted(getCompletionRes(), taskId, true)
|
||||
clearInterval(runId)
|
||||
},
|
||||
onTextReplace: ({ data }) => {
|
||||
res = [data.text]
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onError() {
|
||||
if (isTimeout)
|
||||
return
|
||||
setRespondingFalse()
|
||||
onCompleted(getCompletionRes(), taskId, false)
|
||||
clearInterval(runId)
|
||||
},
|
||||
},
|
||||
isInstalledApp,
|
||||
installedAppInfo?.id,
|
||||
)
|
||||
}
|
||||
else {
|
||||
sendCompletionMessage(data, {
|
||||
onData: (data: string, _isFirstMessage: boolean, { messageId }) => {
|
||||
tempMessageId = messageId
|
||||
res.push(data)
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onCompleted: () => {
|
||||
if (isTimeout)
|
||||
return
|
||||
setRespondingFalse()
|
||||
setMessageId(tempMessageId)
|
||||
onCompleted(getCompletionRes(), taskId, true)
|
||||
clearInterval(runId)
|
||||
},
|
||||
onMessageReplace: (messageReplace) => {
|
||||
res = [messageReplace.answer]
|
||||
setCompletionRes(res.join(''))
|
||||
},
|
||||
onError() {
|
||||
if (isTimeout)
|
||||
return
|
||||
setRespondingFalse()
|
||||
onCompleted(getCompletionRes(), taskId, false)
|
||||
clearInterval(runId)
|
||||
},
|
||||
}, isInstalledApp, installedAppInfo?.id)
|
||||
}
|
||||
}
|
||||
|
||||
const [controlClearMoreLikeThis, setControlClearMoreLikeThis] = useState(0)
|
||||
|
|
@ -221,6 +260,7 @@ const Result: FC<IResultProps> = ({
|
|||
|
||||
const renderTextGenerationRes = () => (
|
||||
<TextGenerationRes
|
||||
isWorkflow={isWorkflow}
|
||||
className='mt-3'
|
||||
isError={isError}
|
||||
onRetry={handleSend}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessageReplace, IOnThought } from './base'
|
||||
import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessageReplace, IOnTextChunk, IOnTextReplace, IOnThought, IOnWorkflowFinished, IOnWorkflowStarted } from './base'
|
||||
import {
|
||||
del as consoleDel, get as consoleGet, patch as consolePatch, post as consolePost,
|
||||
delPublic as del, getPublic as get, patchPublic as patch, postPublic as post, ssePost,
|
||||
|
|
@ -65,6 +65,32 @@ export const sendCompletionMessage = async (body: Record<string, any>, { onData,
|
|||
}, { onData, onCompleted, isPublicAPI: !isInstalledApp, onError, onMessageReplace })
|
||||
}
|
||||
|
||||
export const sendWorkflowMessage = async (
|
||||
body: Record<string, any>,
|
||||
{
|
||||
onTextChunk,
|
||||
onWorkflowStarted,
|
||||
onTextReplace,
|
||||
onWorkflowFinished,
|
||||
onError,
|
||||
}: {
|
||||
onTextChunk: IOnTextChunk
|
||||
onWorkflowStarted: IOnWorkflowStarted
|
||||
onWorkflowFinished: IOnWorkflowFinished
|
||||
onTextReplace: IOnTextReplace
|
||||
onError: IOnError
|
||||
},
|
||||
isInstalledApp: boolean,
|
||||
installedAppId = '',
|
||||
) => {
|
||||
return ssePost(getUrl('workflows/run', isInstalledApp, installedAppId), {
|
||||
body: {
|
||||
...body,
|
||||
response_mode: 'streaming',
|
||||
},
|
||||
}, { onTextChunk, onWorkflowStarted, onWorkflowFinished, isPublicAPI: !isInstalledApp, onError, onTextReplace })
|
||||
}
|
||||
|
||||
export const fetchAppInfo = async () => {
|
||||
return get('/site') as Promise<AppData>
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue