mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 00:48:04 +08:00
fix: workflow result generation render
This commit is contained in:
@ -1,13 +1,25 @@
|
||||
import type { TextChunkResponse } from '@/types/workflow'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback } from 'react'
|
||||
import { useCallback, useRef } from 'react'
|
||||
import { v4 as uuidV4 } from 'uuid'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
|
||||
export const useWorkflowTextChunk = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const toolCallIdRef = useRef<string | null>(null)
|
||||
|
||||
const handleWorkflowTextChunk = useCallback((params: TextChunkResponse) => {
|
||||
const { data: { text } } = params
|
||||
const { data: {
|
||||
text,
|
||||
chunk_type,
|
||||
tool_name,
|
||||
tool_arguments,
|
||||
tool_icon,
|
||||
tool_icon_dark,
|
||||
tool_error,
|
||||
tool_elapsed_time,
|
||||
tool_files,
|
||||
} } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
@ -15,7 +27,87 @@ export const useWorkflowTextChunk = () => {
|
||||
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.resultTabActive = true
|
||||
draft.resultText += text
|
||||
|
||||
if (chunk_type === 'text') {
|
||||
draft.resultText += text
|
||||
|
||||
if (!draft.resultLLMGenerationItems)
|
||||
draft.resultLLMGenerationItems = []
|
||||
|
||||
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
|
||||
|
||||
if (isNotCompletedTextItemIndex > -1) {
|
||||
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].text += text
|
||||
}
|
||||
else {
|
||||
draft.resultLLMGenerationItems?.push({
|
||||
id: uuidV4(),
|
||||
type: 'text',
|
||||
text,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk_type === 'tool_call') {
|
||||
if (!draft.resultLLMGenerationItems)
|
||||
draft.resultLLMGenerationItems = []
|
||||
|
||||
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
|
||||
if (isNotCompletedTextItemIndex > -1) {
|
||||
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].textCompleted = true
|
||||
}
|
||||
toolCallIdRef.current = uuidV4()
|
||||
draft.resultLLMGenerationItems?.push({
|
||||
id: toolCallIdRef.current,
|
||||
type: 'tool',
|
||||
toolName: tool_name,
|
||||
toolArguments: tool_arguments,
|
||||
toolIcon: tool_icon,
|
||||
toolIconDark: tool_icon_dark,
|
||||
})
|
||||
}
|
||||
|
||||
if (chunk_type === 'tool_result') {
|
||||
const currentToolCallIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
|
||||
|
||||
if (currentToolCallIndex > -1) {
|
||||
draft.resultLLMGenerationItems![currentToolCallIndex].toolError = tool_error
|
||||
draft.resultLLMGenerationItems![currentToolCallIndex].toolDuration = tool_elapsed_time
|
||||
draft.resultLLMGenerationItems![currentToolCallIndex].toolFiles = tool_files
|
||||
draft.resultLLMGenerationItems![currentToolCallIndex].toolOutput = text
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought_start') {
|
||||
if (!draft.resultLLMGenerationItems)
|
||||
draft.resultLLMGenerationItems = []
|
||||
|
||||
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
|
||||
if (isNotCompletedTextItemIndex > -1) {
|
||||
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].textCompleted = true
|
||||
}
|
||||
toolCallIdRef.current = uuidV4()
|
||||
draft.resultLLMGenerationItems?.push({
|
||||
id: toolCallIdRef.current,
|
||||
type: 'thought',
|
||||
thoughtOutput: '',
|
||||
})
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought') {
|
||||
const currentThoughtIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
|
||||
if (currentThoughtIndex > -1) {
|
||||
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtOutput += text
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought_end') {
|
||||
const currentThoughtIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
|
||||
if (currentThoughtIndex > -1) {
|
||||
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtOutput += text
|
||||
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtCompleted = true
|
||||
}
|
||||
}
|
||||
}))
|
||||
}, [workflowStore])
|
||||
|
||||
|
||||
@ -178,6 +178,7 @@ const WorkflowPreview = () => {
|
||||
<ResultText
|
||||
isRunning={workflowRunningData?.result?.status === WorkflowRunningStatus.Running || !workflowRunningData?.result}
|
||||
outputs={workflowRunningData?.resultText}
|
||||
llmGenerationItems={workflowRunningData?.resultLLMGenerationItems}
|
||||
allFiles={workflowRunningData?.result?.files}
|
||||
error={workflowRunningData?.result?.error}
|
||||
onClick={() => switchTab('DETAIL')}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { LLMGenerationItem } from '@/types/workflow'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import GenerationContent from '@/app/components/base/chat/chat/answer/generation-content'
|
||||
import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
|
||||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
import { ImageIndentLeft } from '@/app/components/base/icons/src/vender/line/editor'
|
||||
@ -10,6 +12,7 @@ import StatusContainer from '@/app/components/workflow/run/status-container'
|
||||
type ResultTextProps = {
|
||||
isRunning?: boolean
|
||||
outputs?: any
|
||||
llmGenerationItems?: LLMGenerationItem[]
|
||||
error?: string
|
||||
onClick?: () => void
|
||||
allFiles?: any[]
|
||||
@ -18,11 +21,16 @@ type ResultTextProps = {
|
||||
const ResultText: FC<ResultTextProps> = ({
|
||||
isRunning,
|
||||
outputs,
|
||||
llmGenerationItems,
|
||||
error,
|
||||
onClick,
|
||||
allFiles,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const generationContentRenderIsUsed = llmGenerationItems?.length && llmGenerationItems.some((item) => {
|
||||
return item.type === 'tool' || item.type === 'thought'
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="bg-background-section-burn">
|
||||
{isRunning && !outputs && (
|
||||
@ -50,11 +58,18 @@ const ResultText: FC<ResultTextProps> = ({
|
||||
)}
|
||||
{(outputs || !!allFiles?.length) && (
|
||||
<>
|
||||
{outputs && (
|
||||
{outputs && !generationContentRenderIsUsed && (
|
||||
<div className="px-4 py-2">
|
||||
<Markdown content={outputs} />
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
generationContentRenderIsUsed && (
|
||||
<div className="px-2 py-1">
|
||||
<GenerationContent llmGenerationItems={llmGenerationItems} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{!!allFiles?.length && allFiles.map(item => (
|
||||
<div key={item.varName} className="system-xs-regular flex flex-col gap-1 px-4 py-2">
|
||||
<div className="py-1 text-text-tertiary ">{item.varName}</div>
|
||||
|
||||
@ -5,10 +5,12 @@ import type {
|
||||
WorkflowRunningData,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { FileUploadConfigResponse } from '@/models/common'
|
||||
import type { LLMGenerationItem } from '@/types/workflow'
|
||||
|
||||
type PreviewRunningData = WorkflowRunningData & {
|
||||
resultTabActive?: boolean
|
||||
resultText?: string
|
||||
resultLLMGenerationItems?: LLMGenerationItem[]
|
||||
}
|
||||
|
||||
type MousePosition = {
|
||||
|
||||
@ -369,6 +369,16 @@ export type TextChunkResponse = {
|
||||
event: string
|
||||
data: {
|
||||
text: string
|
||||
chunk_type?: 'text' | 'tool_call' | 'tool_result' | 'thought' | 'thought_start' | 'thought_end'
|
||||
tool_call_id?: string
|
||||
tool_name?: string
|
||||
tool_arguments?: string
|
||||
tool_icon?: string | IconObject
|
||||
tool_icon_dark?: string | IconObject
|
||||
|
||||
tool_files?: string[]
|
||||
tool_error?: string
|
||||
tool_elapsed_time?: number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user