diff --git a/web/app/components/base/features/feature-panel/index.tsx b/web/app/components/base/features/feature-panel/index.tsx
deleted file mode 100644
index 72799ef2fc..0000000000
--- a/web/app/components/base/features/feature-panel/index.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import {
- memo,
- useMemo,
-} from 'react'
-import { useTranslation } from 'react-i18next'
-import type { OnFeaturesChange } from '../types'
-import { useFeatures } from '../hooks'
-import FileUpload from './file-upload'
-import OpeningStatement from './opening-statement'
-import type { OpeningStatementProps } from './opening-statement'
-import SuggestedQuestionsAfterAnswer from './suggested-questions-after-answer'
-import TextToSpeech from './text-to-speech'
-import SpeechToText from './speech-to-text'
-import Citation from './citation'
-import Moderation from './moderation'
-import type { InputVar } from '@/app/components/workflow/types'
-
-export type FeaturePanelProps = {
- onChange?: OnFeaturesChange
- openingStatementProps: OpeningStatementProps
- disabled?: boolean
- workflowVariables: InputVar[]
-}
-const FeaturePanel = ({
- onChange,
- openingStatementProps,
- disabled,
- workflowVariables,
-}: FeaturePanelProps) => {
- const { t } = useTranslation()
- const features = useFeatures(s => s.features)
-
- const showAdvanceFeature = useMemo(() => {
- return features.opening?.enabled || features.suggested?.enabled || features.speech2text?.enabled || features.text2speech?.enabled || features.citation?.enabled
- }, [features])
-
- const showToolFeature = useMemo(() => {
- return features.moderation?.enabled
- }, [features])
-
- return (
-
-
- {
- showAdvanceFeature && (
-
-
-
- {t('appDebug.feature.groupChat.title')}
-
-
-
-
- {
- features.opening?.enabled && (
-
- )
- }
- {
- features.suggested?.enabled && (
-
- )
- }
- {
- features.text2speech?.enabled && (
-
- )
- }
- {
- features.speech2text?.enabled && (
-
- )
- }
- {
- features.citation?.enabled && (
-
- )
- }
-
-
- )
- }
- {
- showToolFeature && (
-
-
-
- {t('appDebug.feature.groupChat.title')}
-
-
-
-
- {
- features.moderation?.enabled && (
-
- )
- }
-
-
- )
- }
-
- )
-}
-export default memo(FeaturePanel)
diff --git a/web/app/components/base/features/feature-panel/opening-statement/index.tsx b/web/app/components/base/features/feature-panel/opening-statement/index.tsx
deleted file mode 100644
index 1f102700ad..0000000000
--- a/web/app/components/base/features/feature-panel/opening-statement/index.tsx
+++ /dev/null
@@ -1,328 +0,0 @@
-/* eslint-disable multiline-ternary */
-'use client'
-import type { FC } from 'react'
-import React, { useEffect, useRef, useState } from 'react'
-import produce from 'immer'
-import {
- RiAddLine,
- RiDeleteBinLine,
-} from '@remixicon/react'
-import { useTranslation } from 'react-i18next'
-import { useBoolean } from 'ahooks'
-import { ReactSortable } from 'react-sortablejs'
-import {
- useFeatures,
- useFeaturesStore,
-} from '../../hooks'
-import type { OnFeaturesChange } from '../../types'
-import cn from '@/utils/classnames'
-import Panel from '@/app/components/app/configuration/base/feature-panel'
-import Button from '@/app/components/base/button'
-import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
-import { getInputKeys } from '@/app/components/base/block-input'
-import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
-import { getNewVar } from '@/utils/var'
-import { varHighlightHTML } from '@/app/components/app/configuration/base/var-highlight'
-import type { PromptVariable } from '@/models/debug'
-import type { InputVar } from '@/app/components/workflow/types'
-
-const MAX_QUESTION_NUM = 5
-
-export type OpeningStatementProps = {
- onChange?: OnFeaturesChange
- readonly?: boolean
- promptVariables?: PromptVariable[]
- onAutoAddPromptVariable: (variable: PromptVariable[]) => void
- workflowVariables?: InputVar[]
-}
-
-// regex to match the {{}} and replace it with a span
-const regex = /\{\{([^}]+)\}\}/g
-
-const OpeningStatement: FC = ({
- onChange,
- readonly,
- promptVariables = [],
- onAutoAddPromptVariable,
- workflowVariables = [],
-}) => {
- const { t } = useTranslation()
- const featureStore = useFeaturesStore()
- const openingStatement = useFeatures(s => s.features.opening)
- const value = openingStatement?.opening_statement || ''
- const suggestedQuestions = openingStatement?.suggested_questions || []
- const [notIncludeKeys, setNotIncludeKeys] = useState([])
-
- const hasValue = !!(value || '').trim()
- const inputRef = useRef(null)
-
- const [isFocus, { setTrue: didSetFocus, setFalse: setBlur }] = useBoolean(false)
-
- const setFocus = () => {
- didSetFocus()
- setTimeout(() => {
- const input = inputRef.current
- if (input) {
- input.focus()
- input.setSelectionRange(input.value.length, input.value.length)
- }
- }, 0)
- }
-
- const [tempValue, setTempValue] = useState(value)
- useEffect(() => {
- setTempValue(value || '')
- }, [value])
-
- const [tempSuggestedQuestions, setTempSuggestedQuestions] = useState(suggestedQuestions || [])
- const notEmptyQuestions = tempSuggestedQuestions.filter(question => !!question && question.trim())
- const coloredContent = (tempValue || '')
- .replace(//g, '>')
- .replace(regex, varHighlightHTML({ name: '$1' })) // `{{$1}}`
- .replace(/\n/g, '
')
-
- const handleEdit = () => {
- if (readonly)
- return
- setFocus()
- }
-
- const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
-
- const handleCancel = () => {
- setBlur()
- setTempValue(value)
- setTempSuggestedQuestions(suggestedQuestions)
- }
-
- const handleConfirm = () => {
- const keys = getInputKeys(tempValue)
- const promptKeys = promptVariables.map(item => item.key)
- const workflowVariableKeys = workflowVariables.map(item => item.variable)
- let notIncludeKeys: string[] = []
-
- if (promptKeys.length === 0 && workflowVariables.length === 0) {
- if (keys.length > 0)
- notIncludeKeys = keys
- }
- else {
- if (workflowVariables.length > 0)
- notIncludeKeys = keys.filter(key => !workflowVariableKeys.includes(key))
-
- else notIncludeKeys = keys.filter(key => !promptKeys.includes(key))
- }
-
- if (notIncludeKeys.length > 0) {
- setNotIncludeKeys(notIncludeKeys)
- showConfirmAddVar()
- return
- }
- setBlur()
- const { getState } = featureStore!
- const {
- features,
- setFeatures,
- } = getState()
-
- const newFeatures = produce(features, (draft) => {
- if (draft.opening) {
- draft.opening.opening_statement = tempValue
- draft.opening.suggested_questions = tempSuggestedQuestions
- }
- })
- setFeatures(newFeatures)
-
- if (onChange)
- onChange(newFeatures)
- }
-
- const cancelAutoAddVar = () => {
- const { getState } = featureStore!
- const {
- features,
- setFeatures,
- } = getState()
-
- const newFeatures = produce(features, (draft) => {
- if (draft.opening)
- draft.opening.opening_statement = tempValue
- })
- setFeatures(newFeatures)
-
- if (onChange)
- onChange(newFeatures)
- hideConfirmAddVar()
- setBlur()
- }
-
- const autoAddVar = () => {
- const { getState } = featureStore!
- const {
- features,
- setFeatures,
- } = getState()
-
- const newFeatures = produce(features, (draft) => {
- if (draft.opening)
- draft.opening.opening_statement = tempValue
- })
- setFeatures(newFeatures)
- if (onChange)
- onChange(newFeatures)
- onAutoAddPromptVariable([...notIncludeKeys.map(key => getNewVar(key, 'string'))])
- hideConfirmAddVar()
- setBlur()
- }
-
- const headerRight = !readonly ? (
- isFocus ? (
-
-
-
-
- ) : (
-
- )
- ) : null
-
- const renderQuestions = () => {
- return isFocus ? (
-
-
-
-
{t('appDebug.openingStatement.openingQuestion')}
-
ยท
-
{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}
-
-
-
-
{
- return {
- id: index,
- name,
- }
- })}
- setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
- handle='.handle'
- ghostClass="opacity-50"
- animation={150}
- >
- {tempSuggestedQuestions.map((question, index) => {
- return (
-
-
-
{
- const value = e.target.value
- setTempSuggestedQuestions(tempSuggestedQuestions.map((item, i) => {
- if (index === i)
- return value
-
- return item
- }))
- }}
- className={'w-full overflow-x-auto pl-1.5 pr-8 text-sm leading-9 text-gray-900 border-0 grow h-9 bg-transparent focus:outline-none cursor-pointer rounded-lg'}
- />
-
-
{
- setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
- }}
- >
-
-
-
- )
- })}
- {tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
-
{ setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
- className='mt-1 flex items-center h-9 px-3 gap-2 rounded-lg cursor-pointer text-gray-400 bg-gray-100 hover:bg-gray-200'>
-
-
{t('appDebug.variableConfig.addOption')}
-
- )}
-
- ) : (
-
- {notEmptyQuestions.map((question, index) => {
- return (
-
- {question}
-
- )
- })}
-
- )
- }
-
- return (
-
-
-
- }
- headerRight={headerRight}
- hasHeaderBottomBorder={!hasValue}
- isFocus={isFocus}
- >
-
- {(hasValue || (!hasValue && isFocus)) ? (
- <>
- {isFocus
- ? (
-
-
-
- )
- : (
-
- )}
- {renderQuestions()}
- >) : (
-
{t('appDebug.openingStatement.noDataPlaceHolder')}
- )}
-
- {isShowConfirmAddVar && (
-
- )}
-
-
-
- )
-}
-export default React.memo(OpeningStatement)
diff --git a/web/app/components/base/features/new-feature-panel/dialog-wrapper.tsx b/web/app/components/base/features/new-feature-panel/dialog-wrapper.tsx
index 4975a06d15..e2b03faad2 100644
--- a/web/app/components/base/features/new-feature-panel/dialog-wrapper.tsx
+++ b/web/app/components/base/features/new-feature-panel/dialog-wrapper.tsx
@@ -45,7 +45,7 @@ const DialogWrapper = ({
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
-
+
{children}