| @@ -58,6 +58,7 @@ export type IGenerationItemProps = { | |||
| innerClassName?: string | |||
| contentClassName?: string | |||
| footerClassName?: string | |||
| hideProcessDetail?: boolean | |||
| } | |||
| export const SimpleBtn = ({ className, isDisabled, onClick, children }: { | |||
| @@ -108,6 +109,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({ | |||
| varList, | |||
| innerClassName, | |||
| contentClassName, | |||
| hideProcessDetail, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const params = useParams() | |||
| @@ -291,7 +293,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({ | |||
| <div className={`flex ${contentClassName}`}> | |||
| <div className='grow w-0'> | |||
| {workflowProcessData && ( | |||
| <WorkflowProcessItem grayBg hideInfo data={workflowProcessData} expand={workflowProcessData.expand} /> | |||
| <WorkflowProcessItem grayBg hideInfo data={workflowProcessData} expand={workflowProcessData.expand} hideProcessDetail={hideProcessDetail} /> | |||
| )} | |||
| {workflowProcessData && !isError && ( | |||
| <ResultTab data={workflowProcessData} content={content} /> | |||
| @@ -140,6 +140,7 @@ const ChatWrapper = () => { | |||
| allToolIcons={appMeta?.tool_icons || {}} | |||
| onFeedback={handleFeedback} | |||
| suggestedQuestions={suggestedQuestions} | |||
| hideProcessDetail | |||
| /> | |||
| ) | |||
| } | |||
| @@ -31,6 +31,7 @@ type AnswerProps = { | |||
| allToolIcons?: Record<string, string | Emoji> | |||
| showPromptLog?: boolean | |||
| chatAnswerContainerInner?: string | |||
| hideProcessDetail?: boolean | |||
| } | |||
| const Answer: FC<AnswerProps> = ({ | |||
| item, | |||
| @@ -42,6 +43,7 @@ const Answer: FC<AnswerProps> = ({ | |||
| allToolIcons, | |||
| showPromptLog, | |||
| chatAnswerContainerInner, | |||
| hideProcessDetail, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { | |||
| @@ -129,7 +131,7 @@ const Answer: FC<AnswerProps> = ({ | |||
| } | |||
| { | |||
| workflowProcess && ( | |||
| <WorkflowProcess data={workflowProcess} hideInfo /> | |||
| <WorkflowProcess data={workflowProcess} hideInfo hideProcessDetail={hideProcessDetail} /> | |||
| ) | |||
| } | |||
| { | |||
| @@ -18,12 +18,14 @@ type WorkflowProcessProps = { | |||
| grayBg?: boolean | |||
| expand?: boolean | |||
| hideInfo?: boolean | |||
| hideProcessDetail?: boolean | |||
| } | |||
| const WorkflowProcessItem = ({ | |||
| data, | |||
| grayBg, | |||
| expand = false, | |||
| hideInfo = false, | |||
| hideProcessDetail = false, | |||
| }: WorkflowProcessProps) => { | |||
| const { t } = useTranslation() | |||
| const [collapse, setCollapse] = useState(!expand) | |||
| @@ -94,6 +96,7 @@ const WorkflowProcessItem = ({ | |||
| <NodePanel | |||
| nodeInfo={node} | |||
| hideInfo={hideInfo} | |||
| hideProcessDetail={hideProcessDetail} | |||
| /> | |||
| </div> | |||
| )) | |||
| @@ -54,6 +54,7 @@ export type ChatProps = { | |||
| chatNode?: ReactNode | |||
| onFeedback?: (messageId: string, feedback: Feedback) => void | |||
| chatAnswerContainerInner?: string | |||
| hideProcessDetail?: boolean | |||
| } | |||
| const Chat: FC<ChatProps> = ({ | |||
| config, | |||
| @@ -78,6 +79,7 @@ const Chat: FC<ChatProps> = ({ | |||
| chatNode, | |||
| onFeedback, | |||
| chatAnswerContainerInner, | |||
| hideProcessDetail, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({ | |||
| @@ -204,6 +206,7 @@ const Chat: FC<ChatProps> = ({ | |||
| allToolIcons={allToolIcons} | |||
| showPromptLog={showPromptLog} | |||
| chatAnswerContainerInner={chatAnswerContainerInner} | |||
| hideProcessDetail={hideProcessDetail} | |||
| /> | |||
| ) | |||
| } | |||
| @@ -332,6 +332,7 @@ const Result: FC<IResultProps> = ({ | |||
| taskId={isCallBatchAPI ? ((taskId as number) < 10 ? `0${taskId}` : `${taskId}`) : undefined} | |||
| controlClearMoreLikeThis={controlClearMoreLikeThis} | |||
| isShowTextToSpeech={isShowTextToSpeech} | |||
| hideProcessDetail | |||
| /> | |||
| ) | |||
| @@ -146,7 +146,7 @@ const ConfigPrompt: FC<Props> = ({ | |||
| <ReactSortable className="space-y-1" | |||
| list={payloadWithIds} | |||
| setList={(list) => { | |||
| if ((payload as PromptItem[])?.[0].role === PromptRole.system && list[0].p.role !== PromptRole.system) | |||
| if ((payload as PromptItem[])?.[0].role === PromptRole.system && list[0].p?.role !== PromptRole.system) | |||
| return | |||
| onChange(list.map(item => item.p)) | |||
| @@ -44,7 +44,14 @@ const nodeDefault: NodeDefault<LLMNodeType> = { | |||
| if (!errorMessages && !payload.memory) { | |||
| const isChatModel = payload.model.mode === 'chat' | |||
| const isPromptyEmpty = isChatModel ? !(payload.prompt_template as PromptItem[]).some(t => t.text !== '') : (payload.prompt_template as PromptItem).text === '' | |||
| const isPromptyEmpty = isChatModel | |||
| ? !(payload.prompt_template as PromptItem[]).some((t) => { | |||
| if (t.edition_type === EditionType.jinja2) | |||
| return t.jinja2_text !== '' | |||
| return t.text !== '' | |||
| }) | |||
| : ((payload.prompt_template as PromptItem).edition_type === EditionType.jinja2 ? (payload.prompt_template as PromptItem).jinja2_text === '' : (payload.prompt_template as PromptItem).text === '') | |||
| if (isPromptyEmpty) | |||
| errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.llm.prompt') }) | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| 'use client' | |||
| import { useTranslation } from 'react-i18next' | |||
| import type { FC } from 'react' | |||
| import { useEffect, useState } from 'react' | |||
| import { useCallback, useEffect, useState } from 'react' | |||
| import cn from 'classnames' | |||
| import BlockIcon from '../block-icon' | |||
| import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' | |||
| @@ -14,10 +14,20 @@ import type { NodeTracing } from '@/types/workflow' | |||
| type Props = { | |||
| nodeInfo: NodeTracing | |||
| hideInfo?: boolean | |||
| hideProcessDetail?: boolean | |||
| } | |||
| const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => { | |||
| const [collapseState, setCollapseState] = useState<boolean>(true) | |||
| const NodePanel: FC<Props> = ({ | |||
| nodeInfo, | |||
| hideInfo = false, | |||
| hideProcessDetail, | |||
| }) => { | |||
| const [collapseState, doSetCollapseState] = useState<boolean>(true) | |||
| const setCollapseState = useCallback((state: boolean) => { | |||
| if (hideProcessDetail) | |||
| return | |||
| doSetCollapseState(state) | |||
| }, [hideProcessDetail]) | |||
| const { t } = useTranslation() | |||
| const getTime = (time: number) => { | |||
| @@ -39,7 +49,7 @@ const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => { | |||
| useEffect(() => { | |||
| setCollapseState(!nodeInfo.expand) | |||
| }, [nodeInfo.expand]) | |||
| }, [nodeInfo.expand, setCollapseState]) | |||
| return ( | |||
| <div className={cn('px-4 py-1', hideInfo && '!p-0')}> | |||
| @@ -52,12 +62,15 @@ const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => { | |||
| )} | |||
| onClick={() => setCollapseState(!collapseState)} | |||
| > | |||
| <ChevronRight | |||
| className={cn( | |||
| 'shrink-0 w-3 h-3 mr-1 text-gray-400 transition-all group-hover:text-gray-500', | |||
| !collapseState && 'rotate-90', | |||
| )} | |||
| /> | |||
| {!hideProcessDetail && ( | |||
| <ChevronRight | |||
| className={cn( | |||
| 'shrink-0 w-3 h-3 mr-1 text-gray-400 transition-all group-hover:text-gray-500', | |||
| !collapseState && 'rotate-90', | |||
| )} | |||
| /> | |||
| )} | |||
| <BlockIcon size={hideInfo ? 'xs' : 'sm'} className={cn('shrink-0 mr-2', hideInfo && '!mr-1')} type={nodeInfo.node_type} toolIcon={nodeInfo.extras?.icon || nodeInfo.extras} /> | |||
| <div className={cn( | |||
| 'grow text-gray-700 text-[13px] leading-[16px] font-semibold truncate', | |||
| @@ -77,12 +90,12 @@ const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => { | |||
| )} | |||
| {nodeInfo.status === 'running' && ( | |||
| <div className='shrink-0 flex items-center text-primary-600 text-[13px] leading-[16px] font-medium'> | |||
| <Loading02 className='mr-1 w-3.5 h-3.5 animate-spin' /> | |||
| <span>Running</span> | |||
| <span className='mr-2 text-xs font-normal'>Running</span> | |||
| <Loading02 className='w-3.5 h-3.5 animate-spin' /> | |||
| </div> | |||
| )} | |||
| </div> | |||
| {!collapseState && ( | |||
| {!collapseState && !hideProcessDetail && ( | |||
| <div className='pb-2'> | |||
| <div className={cn('px-[10px] py-1', hideInfo && '!px-2 !py-0.5')}> | |||
| {nodeInfo.status === 'stopped' && ( | |||