mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-10 03:16:51 +08:00
feat: llm text stream support for workflow app (#3798)
Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
@@ -8,9 +8,8 @@ import { useParams } from 'next/navigation'
|
||||
import { HandThumbDownIcon, HandThumbUpIcon } from '@heroicons/react/24/outline'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { HashtagIcon } from '@heroicons/react/24/solid'
|
||||
// import PromptLog from '@/app/components/app/chat/log'
|
||||
import ResultTab from './result-tab'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import AudioBtn from '@/app/components/base/audio-btn'
|
||||
@@ -26,7 +25,6 @@ import EditReplyModal from '@/app/components/app/annotation/edit-annotation-moda
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process'
|
||||
import type { WorkflowProcess } from '@/app/components/base/chat/types'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
|
||||
const MAX_DEPTH = 3
|
||||
|
||||
@@ -293,23 +291,17 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
||||
<div className={`flex ${contentClassName}`}>
|
||||
<div className='grow w-0'>
|
||||
{workflowProcessData && (
|
||||
<WorkflowProcessItem grayBg data={workflowProcessData} expand={workflowProcessData.expand} />
|
||||
<WorkflowProcessItem grayBg hideInfo data={workflowProcessData} expand={workflowProcessData.expand} />
|
||||
)}
|
||||
{workflowProcessData && !isError && (
|
||||
<ResultTab data={workflowProcessData} content={content} />
|
||||
)}
|
||||
{isError && (
|
||||
<div className='text-gray-400 text-sm'>{t('share.generation.batchFailed.outputPlaceholder')}</div>
|
||||
)}
|
||||
{!isError && (typeof content === 'string') && (
|
||||
{!workflowProcessData && !isError && (typeof content === 'string') && (
|
||||
<Markdown content={content} />
|
||||
)}
|
||||
{!isError && (typeof content !== 'string') && (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
title={<div/>}
|
||||
language={CodeLanguage.json}
|
||||
value={content}
|
||||
isJSONStringifyBeauty
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -427,7 +419,11 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className='text-xs text-gray-500'>{content?.length} {t('common.unit.char')}</div>
|
||||
<div>
|
||||
{!workflowProcessData && (
|
||||
<div className='text-xs text-gray-500'>{content?.length} {t('common.unit.char')}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
74
web/app/components/app/text-generate/item/result-tab.tsx
Normal file
74
web/app/components/app/text-generate/item/result-tab.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
// useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import cn from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
// import Loading from '@/app/components/base/loading'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import type { WorkflowProcess } from '@/app/components/base/chat/types'
|
||||
// import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||
|
||||
const ResultTab = ({
|
||||
data,
|
||||
content,
|
||||
}: {
|
||||
data?: WorkflowProcess
|
||||
content: any
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [currentTab, setCurrentTab] = useState<string>('DETAIL')
|
||||
|
||||
const switchTab = async (tab: string) => {
|
||||
setCurrentTab(tab)
|
||||
}
|
||||
useEffect(() => {
|
||||
if (data?.resultText)
|
||||
switchTab('RESULT')
|
||||
else
|
||||
switchTab('DETAIL')
|
||||
}, [data?.resultText])
|
||||
|
||||
return (
|
||||
<div className='grow relative flex flex-col'>
|
||||
{data?.resultText && (
|
||||
<div className='shrink-0 flex items-center mb-2 border-b-[0.5px] border-[rgba(0,0,0,0.05)]'>
|
||||
<div
|
||||
className={cn(
|
||||
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
|
||||
currentTab === 'RESULT' && '!border-[rgb(21,94,239)] text-gray-700',
|
||||
)}
|
||||
onClick={() => switchTab('RESULT')}
|
||||
>{t('runLog.result')}</div>
|
||||
<div
|
||||
className={cn(
|
||||
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
|
||||
currentTab === 'DETAIL' && '!border-[rgb(21,94,239)] text-gray-700',
|
||||
)}
|
||||
onClick={() => switchTab('DETAIL')}
|
||||
>{t('runLog.detail')}</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn('grow bg-white')}>
|
||||
{currentTab === 'RESULT' && (
|
||||
<Markdown content={data?.resultText || ''} />
|
||||
)}
|
||||
{currentTab === 'DETAIL' && content && (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
title={<div>JSON OUTPUT</div>}
|
||||
language={CodeLanguage.json}
|
||||
value={content}
|
||||
isJSONStringifyBeauty
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ResultTab)
|
||||
@@ -54,6 +54,7 @@ export type WorkflowProcess = {
|
||||
status: WorkflowRunningStatus
|
||||
tracing: NodeTracing[]
|
||||
expand?: boolean // for UI
|
||||
resultText?: string
|
||||
}
|
||||
|
||||
export type ChatItem = IChatItem & {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="image-indent-left">
|
||||
<path id="Icon" d="M21 9.25H15M21 4H3M21 14.75H15M21 20H3M4.6 16H9.4C9.96005 16 10.2401 16 10.454 15.891C10.6422 15.7951 10.7951 15.6422 10.891 15.454C11 15.2401 11 14.9601 11 14.4V9.6C11 9.03995 11 8.75992 10.891 8.54601C10.7951 8.35785 10.6422 8.20487 10.454 8.10899C10.2401 8 9.96005 8 9.4 8H4.6C4.03995 8 3.75992 8 3.54601 8.10899C3.35785 8.20487 3.20487 8.35785 3.10899 8.54601C3 8.75992 3 9.03995 3 9.6V14.4C3 14.9601 3 15.2401 3.10899 15.454C3.20487 15.6422 3.35785 15.7951 3.54601 15.891C3.75992 16 4.03995 16 4.6 16Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 743 B |
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "24",
|
||||
"height": "24",
|
||||
"viewBox": "0 0 24 24",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "image-indent-left"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"d": "M21 9.25H15M21 4H3M21 14.75H15M21 20H3M4.6 16H9.4C9.96005 16 10.2401 16 10.454 15.891C10.6422 15.7951 10.7951 15.6422 10.891 15.454C11 15.2401 11 14.9601 11 14.4V9.6C11 9.03995 11 8.75992 10.891 8.54601C10.7951 8.35785 10.6422 8.20487 10.454 8.10899C10.2401 8 9.96005 8 9.4 8H4.6C4.03995 8 3.75992 8 3.54601 8.10899C3.35785 8.20487 3.20487 8.35785 3.10899 8.54601C3 8.75992 3 9.03995 3 9.6V14.4C3 14.9601 3 15.2401 3.10899 15.454C3.20487 15.6422 3.35785 15.7951 3.54601 15.891C3.75992 16 4.03995 16 4.6 16Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "ImageIndentLeft"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './ImageIndentLeft.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'ImageIndentLeft'
|
||||
|
||||
export default Icon
|
||||
@@ -1,6 +1,7 @@
|
||||
export { default as AlignLeft } from './AlignLeft'
|
||||
export { default as BezierCurve03 } from './BezierCurve03'
|
||||
export { default as Colors } from './Colors'
|
||||
export { default as ImageIndentLeft } from './ImageIndentLeft'
|
||||
export { default as LeftIndent02 } from './LeftIndent02'
|
||||
export { default as LetterSpacing01 } from './LetterSpacing01'
|
||||
export { default as TypeSquare } from './TypeSquare'
|
||||
|
||||
@@ -201,6 +201,7 @@ const Result: FC<IResultProps> = ({
|
||||
status: WorkflowRunningStatus.Running,
|
||||
tracing: [],
|
||||
expand: false,
|
||||
resultText: '',
|
||||
})
|
||||
setRespondingFalse()
|
||||
},
|
||||
@@ -243,15 +244,25 @@ const Result: FC<IResultProps> = ({
|
||||
}))
|
||||
if (!data.outputs)
|
||||
setCompletionRes('')
|
||||
else if (Object.keys(data.outputs).length > 1)
|
||||
setCompletionRes(data.outputs)
|
||||
else
|
||||
setCompletionRes(data.outputs[Object.keys(data.outputs)[0]])
|
||||
setCompletionRes(data.outputs)
|
||||
setRespondingFalse()
|
||||
setMessageId(tempMessageId)
|
||||
onCompleted(getCompletionRes(), taskId, true)
|
||||
isEnd = true
|
||||
},
|
||||
onTextChunk: (params) => {
|
||||
const { data: { text } } = params
|
||||
setWorkflowProccessData(produce(getWorkflowProccessData()!, (draft) => {
|
||||
draft.resultText += text
|
||||
}))
|
||||
},
|
||||
onTextReplace: (params) => {
|
||||
const { data: { text } } = params
|
||||
setWorkflowProccessData(produce(getWorkflowProccessData()!, (draft) => {
|
||||
draft.resultText = text
|
||||
}))
|
||||
},
|
||||
},
|
||||
isInstalledApp,
|
||||
installedAppInfo?.id,
|
||||
|
||||
@@ -124,6 +124,7 @@ export const useWorkflowRun = () => {
|
||||
status: WorkflowRunningStatus.Running,
|
||||
},
|
||||
tracing: [],
|
||||
resultText: '',
|
||||
})
|
||||
|
||||
ssePost(
|
||||
@@ -284,6 +285,27 @@ export const useWorkflowRun = () => {
|
||||
if (onNodeFinished)
|
||||
onNodeFinished(params)
|
||||
},
|
||||
onTextChunk: (params) => {
|
||||
const { data: { text } } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
} = workflowStore.getState()
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.resultTabActive = true
|
||||
draft.resultText += text
|
||||
}))
|
||||
},
|
||||
onTextReplace: (params) => {
|
||||
const { data: { text } } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
} = workflowStore.getState()
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.resultText = text
|
||||
}))
|
||||
},
|
||||
...restCallback,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
useRef,
|
||||
// useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import cn from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OutputPanel from '../run/output-panel'
|
||||
import ResultText from '../run/result-text'
|
||||
import ResultPanel from '../run/result-panel'
|
||||
import TracingPanel from '../run/tracing-panel'
|
||||
import {
|
||||
@@ -32,22 +32,15 @@ const WorkflowPreview = () => {
|
||||
setCurrentTab(tab)
|
||||
}
|
||||
|
||||
const [height, setHieght] = useState(0)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (showDebugAndPreviewPanel && showInputsPanel)
|
||||
setCurrentTab('INPUT')
|
||||
}, [showDebugAndPreviewPanel, showInputsPanel])
|
||||
|
||||
const adjustResultHeight = () => {
|
||||
if (ref.current)
|
||||
setHieght(ref.current?.clientHeight - 16 - 16 - 2 - 1)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustResultHeight()
|
||||
}, [])
|
||||
if ((workflowRunningData?.result.status === WorkflowRunningStatus.Succeeded || workflowRunningData?.result.status === WorkflowRunningStatus.Failed) && !workflowRunningData.resultText)
|
||||
switchTab('DETAIL')
|
||||
}, [workflowRunningData])
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
@@ -107,7 +100,7 @@ const WorkflowPreview = () => {
|
||||
}}
|
||||
>{t('runLog.tracing')}</div>
|
||||
</div>
|
||||
<div ref={ref} className={cn(
|
||||
<div className={cn(
|
||||
'grow bg-white h-0 overflow-y-auto rounded-b-2xl',
|
||||
(currentTab === 'RESULT' || currentTab === 'TRACING') && '!bg-gray-50',
|
||||
)}>
|
||||
@@ -115,11 +108,11 @@ const WorkflowPreview = () => {
|
||||
<InputsPanel onRun={() => switchTab('RESULT')} />
|
||||
)}
|
||||
{currentTab === 'RESULT' && (
|
||||
<OutputPanel
|
||||
<ResultText
|
||||
isRunning={workflowRunningData?.result?.status === WorkflowRunningStatus.Running || !workflowRunningData?.result}
|
||||
outputs={workflowRunningData?.result?.outputs}
|
||||
outputs={workflowRunningData?.resultText}
|
||||
error={workflowRunningData?.result?.error}
|
||||
height={height}
|
||||
onClick={() => switchTab('DETAIL')}
|
||||
/>
|
||||
)}
|
||||
{currentTab === 'DETAIL' && (
|
||||
|
||||
56
web/app/components/workflow/run/result-text.tsx
Normal file
56
web/app/components/workflow/run/result-text.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ImageIndentLeft } from '@/app/components/base/icons/src/vender/line/editor'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import LoadingAnim from '@/app/components/app/chat/loading-anim'
|
||||
|
||||
type ResultTextProps = {
|
||||
isRunning?: boolean
|
||||
outputs?: any
|
||||
error?: string
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
const ResultText: FC<ResultTextProps> = ({
|
||||
isRunning,
|
||||
outputs,
|
||||
error,
|
||||
onClick,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='bg-gray-50 py-2'>
|
||||
{isRunning && !outputs && (
|
||||
<div className='pt-4 pl-[26px]'>
|
||||
<LoadingAnim type='text' />
|
||||
</div>
|
||||
)}
|
||||
{!isRunning && error && (
|
||||
<div className='px-4'>
|
||||
<div className='px-3 py-[10px] rounded-lg !bg-[#fef3f2] border-[0.5px] border-[rbga(0,0,0,0.05)] shadow-xs'>
|
||||
<div className='text-xs leading-[18px] text-[#d92d20]'>{error}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!isRunning && !outputs && !error && (
|
||||
<div className='mt-[120px] px-4 py-2 flex flex-col items-center text-[13px] leading-[18px] text-gray-500'>
|
||||
<ImageIndentLeft className='w-6 h-6 text-gray-400' />
|
||||
<div className='mr-2'>{t('runLog.resultEmpty.title')}</div>
|
||||
<div>
|
||||
{t('runLog.resultEmpty.tipLeft')}
|
||||
<span onClick={onClick} className='cursor-pointer text-primary-600'>{t('runLog.resultEmpty.link')}</span>
|
||||
{t('runLog.resultEmpty.tipRight')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{outputs && (
|
||||
<div className='px-4 py-2'>
|
||||
<Markdown content={outputs} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ResultText
|
||||
@@ -19,11 +19,16 @@ import type {
|
||||
} from './types'
|
||||
import { WorkflowContext } from './context'
|
||||
|
||||
type PreviewRunningData = WorkflowRunningData & {
|
||||
resultTabActive?: boolean
|
||||
resultText?: string
|
||||
}
|
||||
|
||||
type Shape = {
|
||||
appId: string
|
||||
panelWidth: number
|
||||
workflowRunningData?: WorkflowRunningData
|
||||
setWorkflowRunningData: (workflowData?: WorkflowRunningData) => void
|
||||
workflowRunningData?: PreviewRunningData
|
||||
setWorkflowRunningData: (workflowData: PreviewRunningData) => void
|
||||
historyWorkflowData?: HistoryWorkflowData
|
||||
setHistoryWorkflowData: (historyWorkflowData?: HistoryWorkflowData) => void
|
||||
showRunHistory: boolean
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Gesamtzeichen',
|
||||
steps: 'Ausführungsschritte',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'Dieser Lauf gibt nur das JSON-Format aus',
|
||||
tipLeft: 'Bitte gehen Sie zum ',
|
||||
Link: 'Detailpanel',
|
||||
tipRight: 'ansehen.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Total Tokens',
|
||||
steps: 'Run Steps',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'This run only output JSON format,',
|
||||
tipLeft: 'please go to the ',
|
||||
link: 'detail panel',
|
||||
tipRight: ' view it.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Total des jetons',
|
||||
steps: 'Étapes d\'exécution',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'Cela exécute uniquement le format de sortie JSON,',
|
||||
tipLeft: 'veuillez aller à ',
|
||||
link: 'panneau de détail',
|
||||
tipRight: ' visualisez-le.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'トークンの合計',
|
||||
steps: '実行ステップ',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'この実行では JSON 形式のみが出力されます',
|
||||
tipLeft: 'にアクセスしてください',
|
||||
link: '詳細パネル',
|
||||
tipRight: '表示します。',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Total de Tokens',
|
||||
steps: 'Passos de Execução',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'Esta execução apenas produz o formato JSON,',
|
||||
tipLeft: 'por favor vá para ',
|
||||
link: 'painel de detalhes',
|
||||
tipRight: ' veja.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Загальна кількість токенів',
|
||||
steps: 'Кроки виконання',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'Цей запуск лише вихідного формату JSON,',
|
||||
tipLeft: 'будь ласка, перейдіть до ',
|
||||
link: 'панель деталей',
|
||||
tipRight: ' переглянути.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: 'Tổng số token',
|
||||
steps: 'Các bước chạy',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: 'Chạy này chỉ xuất ra định dạng JSON,',
|
||||
tipLeft: 'vui lòng truy cập ',
|
||||
link: 'bảng chi tiết',
|
||||
tipRight: ' xem nó.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: '总 token 数',
|
||||
steps: '运行步数',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: '本次运行仅输出JSON格式,',
|
||||
tipLeft: '请转到',
|
||||
link: '详细信息面板',
|
||||
tipRight: '查看它。',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -18,6 +18,12 @@ const translation = {
|
||||
tokens: '總 token 數',
|
||||
steps: '執行步數',
|
||||
},
|
||||
resultEmpty: {
|
||||
title: '本運行僅輸出JSON格式,',
|
||||
tipLeft: '請到',
|
||||
link: '詳細資訊面板',
|
||||
tipRight: '查看它。',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessageReplace, IOnNodeFinished, IOnNodeStarted, IOnThought, IOnWorkflowFinished, IOnWorkflowStarted } from './base'
|
||||
import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessageReplace, IOnNodeFinished, IOnNodeStarted, 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,
|
||||
@@ -72,11 +72,15 @@ export const sendWorkflowMessage = async (
|
||||
onNodeStarted,
|
||||
onNodeFinished,
|
||||
onWorkflowFinished,
|
||||
onTextChunk,
|
||||
onTextReplace,
|
||||
}: {
|
||||
onWorkflowStarted: IOnWorkflowStarted
|
||||
onNodeStarted: IOnNodeStarted
|
||||
onNodeFinished: IOnNodeFinished
|
||||
onWorkflowFinished: IOnWorkflowFinished
|
||||
onTextChunk: IOnTextChunk
|
||||
onTextReplace: IOnTextReplace
|
||||
},
|
||||
isInstalledApp: boolean,
|
||||
installedAppId = '',
|
||||
@@ -86,7 +90,7 @@ export const sendWorkflowMessage = async (
|
||||
...body,
|
||||
response_mode: 'streaming',
|
||||
},
|
||||
}, { onNodeStarted, onWorkflowStarted, onWorkflowFinished, isPublicAPI: !isInstalledApp, onNodeFinished })
|
||||
}, { onNodeStarted, onWorkflowStarted, onWorkflowFinished, isPublicAPI: !isInstalledApp, onNodeFinished, onTextChunk, onTextReplace })
|
||||
}
|
||||
|
||||
export const fetchAppInfo = async () => {
|
||||
|
||||
Reference in New Issue
Block a user