web app support workflow

This commit is contained in:
JzoNg 2024-03-14 21:01:58 +08:00
parent 58922ba40b
commit bcce53a929
5 changed files with 149 additions and 69 deletions

View File

@ -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}
</>
)}

View File

@ -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>
)
}

View File

@ -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}

View File

@ -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}

View File

@ -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>
}