diff --git a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx index 93510cba45..df1b61432a 100644 --- a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx +++ b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx @@ -262,6 +262,7 @@ const GetAutomaticRes: FC = ({ {(mode !== AppType.completion && res?.opening_statement) && (
+ {/* ##TODO## use new style of opening */} void -} - -const ITEM_HEIGHT = 48 - -const AddFeatureBtn: FC = ({ - toBottomHeight, - onClick, -}) => { - const { t } = useTranslation() - return ( -
-
- -
{t('appDebug.operation.addFeature')}
-
-
- ) -} -export default React.memo(AddFeatureBtn) diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/index.tsx b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/index.tsx deleted file mode 100644 index 18623c11c3..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import s from './style.module.css' -import cn from '@/utils/classnames' -import Switch from '@/app/components/base/switch' - -export type IFeatureItemProps = { - icon: React.ReactNode - previewImgClassName?: string - title: string - description: string - value: boolean - onChange: (value: boolean) => void -} - -const FeatureItem: FC = ({ - icon, - previewImgClassName, - title, - description, - value, - onChange, -}) => { - return ( -
-
- {/* icon */} -
- {icon} -
-
-
{title}
-
{description}
-
-
- - - { - previewImgClassName && ( -
-
) - } -
- ) -} -export default React.memo(FeatureItem) diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.png deleted file mode 100644 index cc0847c942..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.svg b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.svg deleted file mode 100644 index 82fb182a7a..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.svg +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citations-and-attributions-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citations-and-attributions-preview@2x.png deleted file mode 100644 index ef066204ca..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citations-and-attributions-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/conversation-opener-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/conversation-opener-preview@2x.png deleted file mode 100644 index 15639d500d..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/conversation-opener-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this-preview@2x.png deleted file mode 100644 index 62671c5889..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.png deleted file mode 100644 index 9eb1c3a1ce..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.svg b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.svg deleted file mode 100644 index 6ccc84e70f..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/next-question-suggestion-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/next-question-suggestion-preview@2x.png deleted file mode 100644 index 758708ff15..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/next-question-suggestion-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.png deleted file mode 100644 index 51e1bf395e..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-suggestion-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-suggestion-preview@2x.png deleted file mode 100644 index 8bb4add322..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-suggestion-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text-preview@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text-preview@2x.png deleted file mode 100644 index 68df3983dc..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text-preview@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.png deleted file mode 100644 index c951d0c418..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.svg b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.svg deleted file mode 100644 index 029b92fee4..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.png deleted file mode 100644 index bee4be0acf..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.svg b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.svg deleted file mode 100644 index c0102b7e08..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.svg +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png deleted file mode 100644 index 91396e72c7..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png deleted file mode 100644 index 7558e78bd9..0000000000 Binary files a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png and /dev/null differ diff --git a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/style.module.css b/web/app/components/app/configuration/config/feature/choose-feature/feature-item/style.module.css deleted file mode 100644 index 32dc6be3ba..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/feature-item/style.module.css +++ /dev/null @@ -1,41 +0,0 @@ -.preview { - display: none; - position: absolute; - top: 0; - left: 100%; - transform: translate(32px, -54px); - width: 280px; - height: 360px; - background: center center no-repeat; - background-size: contain; - border-radius: 8px; -} - -.wrap:hover .preview { - display: block; -} - -.openingStatementPreview { - background-image: url(./preview-imgs/opening-statement.png); -} - -.suggestedQuestionsAfterAnswerPreview { - background-image: url(./preview-imgs/suggested-questions-after-answer.png); -} - -.moreLikeThisPreview { - background-image: url(./preview-imgs/more-like-this.png); -} - -.speechToTextPreview { - background-image: url(./preview-imgs/speech-to-text.png); -} - -.textToSpeechPreview { - @apply shadow-lg rounded-lg; - background-image: url(./preview-imgs/text-to-audio-preview-assistant@2x.png); -} - -.citationPreview { - background-image: url(./preview-imgs/citation.png); -} diff --git a/web/app/components/app/configuration/config/feature/choose-feature/index.tsx b/web/app/components/app/configuration/config/feature/choose-feature/index.tsx deleted file mode 100644 index 8364f9529d..0000000000 --- a/web/app/components/app/configuration/config/feature/choose-feature/index.tsx +++ /dev/null @@ -1,172 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import { useTranslation } from 'react-i18next' -import FeatureGroup from '../feature-group' -import MoreLikeThisIcon from '../../../base/icons/more-like-this-icon' -import FeatureItem from './feature-item' -import Modal from '@/app/components/base/modal' -import SuggestedQuestionsAfterAnswerIcon from '@/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon' -import { Microphone01, Speaker } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' -import { Citations } from '@/app/components/base/icons/src/vender/solid/editor' -import { FileSearch02 } from '@/app/components/base/icons/src/vender/solid/files' -import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication' -type IConfig = { - openingStatement: boolean - moreLikeThis: boolean - suggestedQuestionsAfterAnswer: boolean - speechToText: boolean - textToSpeech: boolean - citation: boolean - moderation: boolean - annotation: boolean -} - -export type IChooseFeatureProps = { - isShow: boolean - onClose: () => void - config: IConfig - isChatApp: boolean - onChange: (key: string, value: boolean) => void - showTextToSpeechItem?: boolean - showSpeechToTextItem?: boolean -} - -const OpeningStatementIcon = ( - - - -) - -const ChooseFeature: FC = ({ - isShow, - onClose, - isChatApp, - config, - onChange, - showTextToSpeechItem, - showSpeechToTextItem, -}) => { - const { t } = useTranslation() - return ( - -
- {/* Chat Feature */} - {isChatApp && ( - - <> - onChange('openingStatement', value)} - /> - } - previewImgClassName='suggestedQuestionsAfterAnswerPreview' - title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')} - description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')} - value={config.suggestedQuestionsAfterAnswer} - onChange={value => onChange('suggestedQuestionsAfterAnswer', value)} - /> - { - showTextToSpeechItem && ( - } - previewImgClassName='textToSpeechPreview' - title={t('appDebug.feature.textToSpeech.title')} - description={t('appDebug.feature.textToSpeech.description')} - value={config.textToSpeech} - onChange={value => onChange('textToSpeech', value)} - /> - ) - } - { - showSpeechToTextItem && ( - } - previewImgClassName='speechToTextPreview' - title={t('appDebug.feature.speechToText.title')} - description={t('appDebug.feature.speechToText.description')} - value={config.speechToText} - onChange={value => onChange('speechToText', value)} - /> - ) - } - } - previewImgClassName='citationPreview' - title={t('appDebug.feature.citation.title')} - description={t('appDebug.feature.citation.description')} - value={config.citation} - onChange={value => onChange('citation', value)} - /> - - - )} - - {/* Text Generation Feature */} - {!isChatApp && ( - - <> - } - previewImgClassName='moreLikeThisPreview' - title={t('appDebug.feature.moreLikeThis.title')} - description={t('appDebug.feature.moreLikeThis.description')} - value={config.moreLikeThis} - onChange={value => onChange('moreLikeThis', value)} - /> - { - showTextToSpeechItem && ( - } - previewImgClassName='textToSpeechPreview' - title={t('appDebug.feature.textToSpeech.title')} - description={t('appDebug.feature.textToSpeech.description')} - value={config.textToSpeech} - onChange={value => onChange('textToSpeech', value)} - /> - ) - } - - - )} - - <> - } - previewImgClassName='' - title={t('appDebug.feature.moderation.title')} - description={t('appDebug.feature.moderation.description')} - value={config.moderation} - onChange={value => onChange('moderation', value)} - /> - {isChatApp && ( - } - title={t('appDebug.feature.annotation.title')} - description={t('appDebug.feature.annotation.description')} - value={config.annotation} - onChange={value => onChange('annotation', value)} - /> - )} - - -
-
- ) -} -export default React.memo(ChooseFeature) diff --git a/web/app/components/app/configuration/config/feature/feature-group/index.tsx b/web/app/components/app/configuration/config/feature/feature-group/index.tsx deleted file mode 100644 index a4b27f18d4..0000000000 --- a/web/app/components/app/configuration/config/feature/feature-group/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import GroupName from '@/app/components/app/configuration/base/group-name' - -export type IFeatureGroupProps = { - title: string - description?: string - children: React.ReactNode -} - -const FeatureGroup: FC = ({ - title, - description, - children, -}) => { - return ( -
-
- - {description && ( -
{description}
- )} -
-
- {children} -
-
- ) -} -export default React.memo(FeatureGroup) diff --git a/web/app/components/app/configuration/config/index.tsx b/web/app/components/app/configuration/config/index.tsx index b8bedba20b..b569a42875 100644 --- a/web/app/components/app/configuration/config/index.tsx +++ b/web/app/components/app/configuration/config/index.tsx @@ -1,32 +1,22 @@ 'use client' import type { FC } from 'react' -import React, { useRef } from 'react' +import React from 'react' import { useContext } from 'use-context-selector' import produce from 'immer' -import { useBoolean, useScroll } from 'ahooks' import { useFormattingChangedDispatcher } from '../debug/hooks' import DatasetConfig from '../dataset-config' -import ChatGroup from '../features/chat-group' -import ExperienceEnchanceGroup from '../features/experience-enchance-group' -import Toolbox from '../toolbox' import HistoryPanel from '../config-prompt/conversation-histroy/history-panel' import ConfigVision from '../config-vision' import useAnnotationConfig from '../toolbox/annotation/use-annotation-config' -import AddFeatureBtn from './feature/add-feature-btn' -import ChooseFeature from './feature/choose-feature' -import useFeature from './feature/use-feature' import AgentTools from './agent/agent-tools' import ConfigContext from '@/context/debug-configuration' import ConfigPrompt from '@/app/components/app/configuration/config-prompt' import ConfigVar from '@/app/components/app/configuration/config-var' -import { type CitationConfig, type ModelConfig, type ModerationConfig, type MoreLikeThisConfig, type PromptVariable, type SpeechToTextConfig, type SuggestedQuestionsAfterAnswerConfig, type TextToSpeechConfig } from '@/models/debug' +import { type ModelConfig, type PromptVariable } from '@/models/debug' import type { AppType } from '@/types/app' import { ModelModeType } from '@/types/app' -import { useModalContext } from '@/context/modal-context' import ConfigParamModal from '@/app/components/app/configuration/toolbox/annotation/config-param-modal' import AnnotationFullModal from '@/app/components/billing/annotation-full/modal' -import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' -import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' const Config: FC = () => { const { @@ -39,32 +29,13 @@ const Config: FC = () => { // setPromptMode, hasSetBlockStatus, showHistoryModal, - introduction, - setIntroduction, - suggestedQuestions, - setSuggestedQuestions, modelConfig, setModelConfig, setPrevPromptConfig, - moreLikeThisConfig, - setMoreLikeThisConfig, - suggestedQuestionsAfterAnswerConfig, - setSuggestedQuestionsAfterAnswerConfig, - speechToTextConfig, - setSpeechToTextConfig, - textToSpeechConfig, - setTextToSpeechConfig, - citationConfig, - setCitationConfig, annotationConfig, setAnnotationConfig, - moderationConfig, - setModerationConfig, } = useContext(ConfigContext) const isChatApp = ['advanced-chat', 'agent-chat', 'chat'].includes(mode) - const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text) - const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.tts) - const { setShowModerationSettingModal } = useModalContext() const formattingChangedDispatcher = useFormattingChangedDispatcher() const promptTemplate = modelConfig.configs.prompt_template @@ -90,93 +61,10 @@ const Config: FC = () => { setModelConfig(newModelConfig) } - const [showChooseFeature, { - setTrue: showChooseFeatureTrue, - setFalse: showChooseFeatureFalse, - }] = useBoolean(false) - const { featureConfig, handleFeatureChange } = useFeature({ - introduction, - setIntroduction, - moreLikeThis: moreLikeThisConfig.enabled, - setMoreLikeThis: (value) => { - setMoreLikeThisConfig(produce(moreLikeThisConfig, (draft: MoreLikeThisConfig) => { - draft.enabled = value - })) - }, - suggestedQuestionsAfterAnswer: suggestedQuestionsAfterAnswerConfig.enabled, - setSuggestedQuestionsAfterAnswer: (value) => { - setSuggestedQuestionsAfterAnswerConfig(produce(suggestedQuestionsAfterAnswerConfig, (draft: SuggestedQuestionsAfterAnswerConfig) => { - draft.enabled = value - })) - formattingChangedDispatcher() - }, - speechToText: speechToTextConfig.enabled, - setSpeechToText: (value) => { - setSpeechToTextConfig(produce(speechToTextConfig, (draft: SpeechToTextConfig) => { - draft.enabled = value - })) - }, - textToSpeech: textToSpeechConfig.enabled, - setTextToSpeech: (value) => { - setTextToSpeechConfig(produce(textToSpeechConfig, (draft: TextToSpeechConfig) => { - draft.enabled = value - draft.voice = textToSpeechConfig?.voice - draft.language = textToSpeechConfig?.language - })) - }, - citation: citationConfig.enabled, - setCitation: (value) => { - setCitationConfig(produce(citationConfig, (draft: CitationConfig) => { - draft.enabled = value - })) - formattingChangedDispatcher() - }, - annotation: annotationConfig.enabled, - setAnnotation: async (value) => { - if (value) { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - setIsShowAnnotationConfigInit(true) - } - else { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - await handleDisableAnnotation(annotationConfig.embedding_model) - } - }, - moderation: moderationConfig.enabled, - setModeration: (value) => { - setModerationConfig(produce(moderationConfig, (draft: ModerationConfig) => { - draft.enabled = value - })) - if (value && !moderationConfig.type) { - setShowModerationSettingModal({ - payload: { - enabled: true, - type: 'keywords', - config: { - keywords: '', - inputs_config: { - enabled: true, - preset_response: '', - }, - }, - }, - onSaveCallback: setModerationConfig, - onCancelCallback: () => { - setModerationConfig(produce(moderationConfig, (draft: ModerationConfig) => { - draft.enabled = false - showChooseFeatureTrue() - })) - }, - }) - showChooseFeatureFalse() - } - }, - }) - const { handleEnableAnnotation, - setScore, - handleDisableAnnotation, + // setScore, + // handleDisableAnnotation, isShowAnnotationConfigInit, setIsShowAnnotationConfigInit, isShowAnnotationFullModal, @@ -187,41 +75,11 @@ const Config: FC = () => { setAnnotationConfig, }) - const hasChatConfig = isChatApp && (featureConfig.openingStatement || featureConfig.suggestedQuestionsAfterAnswer || (featureConfig.speechToText && !!speech2textDefaultModel) || (featureConfig.textToSpeech && !!text2speechDefaultModel) || featureConfig.citation) - const hasCompletionConfig = !isChatApp && (moreLikeThisConfig.enabled || (featureConfig.textToSpeech && !!text2speechDefaultModel)) - - const hasToolbox = moderationConfig.enabled || featureConfig.annotation - - const wrapRef = useRef(null) - const wrapScroll = useScroll(wrapRef) - const toBottomHeight = (() => { - if (!wrapRef.current) - return 999 - const elem = wrapRef.current - const { clientHeight } = elem - const value = (wrapScroll?.top || 0) + clientHeight - return value - })() - return ( <>
- - {showChooseFeature && ( - - )} - {/* Template */} { /> )} - {/* ChatConifig */} - { - hasChatConfig && ( - - ) - } - - {/* Text Generation config */}{ - hasCompletionConfig && ( - - ) - } - - {/* Toolbox */} - { - hasToolbox && ( - - ) - } - { setIsShowAnnotationConfigInit(false) - showChooseFeatureTrue() + // showChooseFeatureTrue() }} onSave={async (embeddingModel, score) => { await handleEnableAnnotation(embeddingModel, score) diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx index 892d0cfe8b..7ad534d77a 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx @@ -121,6 +121,7 @@ const DebugWithMultipleModel = () => { )) }
+ {/* ##TODO## */} { isChatMode && (
diff --git a/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx b/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx index e041692fe5..c9e83da1c3 100644 --- a/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx +++ b/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx @@ -12,7 +12,7 @@ import { import Chat from '@/app/components/base/chat/chat' import { useChat } from '@/app/components/base/chat/chat/hooks' import { useDebugConfigurationContext } from '@/context/debug-configuration' -import type { OnSend } from '@/app/components/base/chat/types' +import type { ChatConfig, OnSend } from '@/app/components/base/chat/types' import { useProviderContext } from '@/context/provider-context' import { fetchConversationMessages, @@ -22,6 +22,8 @@ import { import Avatar from '@/app/components/base/avatar' import { useAppContext } from '@/context/app-context' import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' +import { useStore as useAppStore } from '@/app/components/app/store' +import { useFeatures } from '@/app/components/base/features/hooks' type DebugWithSingleModelProps = { checkCanSend?: () => boolean @@ -42,7 +44,23 @@ const DebugWithSingleModel = forwardRef s.features) + const configTemplate = useConfigFromDebugContext() + const config = useMemo(() => { + return { + ...configTemplate, + more_like_this: features.moreLikeThis, + opening_statement: features.opening?.opening_statement || '', + suggested_questions: features.opening?.suggested_questions || [], + sensitive_word_avoidance: features.moderation, + speech_to_text: features.speech2text, + text_to_speech: features.text2speech, + file_upload: features.file, + suggested_questions_after_answer: features.suggested, + retriever_resource: features.citation, + // ##TODO## annotation_reply + } as ChatConfig + }, [configTemplate, features]) const { chatList, isResponding, @@ -114,13 +132,17 @@ const DebugWithSingleModel = forwardRef s.setShowAppConfigureFeaturesModal) + return ( = ({
)} + {/* ##TODO## new style of completion */} {mode === AppType.completion && ( { - const { t } = useTranslation() - - return ( - -
{t('appDebug.feature.citation.title')}
-
- } - headerIcon={} - headerRight={ -
{t('appDebug.feature.citation.resDes')}
- } - noBodySpacing - /> - ) -} -export default React.memo(Citation) diff --git a/web/app/components/app/configuration/features/chat-group/index.tsx b/web/app/components/app/configuration/features/chat-group/index.tsx deleted file mode 100644 index fd3cfa3a68..0000000000 --- a/web/app/components/app/configuration/features/chat-group/index.tsx +++ /dev/null @@ -1,65 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import { useTranslation } from 'react-i18next' -import GroupName from '../../base/group-name' -import type { IOpeningStatementProps } from './opening-statement' -import OpeningStatement from './opening-statement' -import SuggestedQuestionsAfterAnswer from './suggested-questions-after-answer' -import SpeechToText from './speech-to-text' -import TextToSpeech from './text-to-speech' -import Citation from './citation' -/* -* Include -* 1. Conversation Opener -* 2. Opening Suggestion -* 3. Next question suggestion -*/ -type ChatGroupProps = { - isShowOpeningStatement: boolean - openingStatementConfig: IOpeningStatementProps - isShowSuggestedQuestionsAfterAnswer: boolean - isShowSpeechText: boolean - isShowTextToSpeech: boolean - isShowCitation: boolean -} -const ChatGroup: FC = ({ - isShowOpeningStatement, - openingStatementConfig, - isShowSuggestedQuestionsAfterAnswer, - isShowSpeechText, - isShowTextToSpeech, - isShowCitation, -}) => { - const { t } = useTranslation() - - return ( -
- -
- {isShowOpeningStatement && ( - - )} - {isShowSuggestedQuestionsAfterAnswer && ( - - )} - { - isShowTextToSpeech && ( - - ) - } - { - isShowSpeechText && ( - - ) - } - { - isShowCitation && ( - - ) - } -
-
- ) -} -export default React.memo(ChatGroup) diff --git a/web/app/components/app/configuration/features/chat-group/speech-to-text/index.tsx b/web/app/components/app/configuration/features/chat-group/speech-to-text/index.tsx deleted file mode 100644 index e452b38971..0000000000 --- a/web/app/components/app/configuration/features/chat-group/speech-to-text/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' -import React, { type FC } from 'react' -import { useTranslation } from 'react-i18next' -import Panel from '@/app/components/app/configuration/base/feature-panel' -import { Microphone01 } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' - -const SpeechToTextConfig: FC = () => { - const { t } = useTranslation() - - return ( - -
{t('appDebug.feature.speechToText.title')}
- - } - headerIcon={} - headerRight={ -
{t('appDebug.feature.speechToText.resDes')}
- } - noBodySpacing - /> - ) -} -export default React.memo(SpeechToTextConfig) diff --git a/web/app/components/app/configuration/features/chat-group/suggested-questions-after-answer/index.tsx b/web/app/components/app/configuration/features/chat-group/suggested-questions-after-answer/index.tsx deleted file mode 100644 index 199558f4aa..0000000000 --- a/web/app/components/app/configuration/features/chat-group/suggested-questions-after-answer/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import { useTranslation } from 'react-i18next' -import Panel from '@/app/components/app/configuration/base/feature-panel' -import SuggestedQuestionsAfterAnswerIcon from '@/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon' -import Tooltip from '@/app/components/base/tooltip' - -const SuggestedQuestionsAfterAnswer: FC = () => { - const { t } = useTranslation() - - return ( - -
{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
- - {t('appDebug.feature.suggestedQuestionsAfterAnswer.description')} - - } - /> - - } - headerIcon={} - headerRight={ -
{t('appDebug.feature.suggestedQuestionsAfterAnswer.resDes')}
- } - noBodySpacing - /> - ) -} -export default React.memo(SuggestedQuestionsAfterAnswer) diff --git a/web/app/components/app/configuration/features/chat-group/text-to-speech/index.tsx b/web/app/components/app/configuration/features/chat-group/text-to-speech/index.tsx deleted file mode 100644 index 72d617c3c3..0000000000 --- a/web/app/components/app/configuration/features/chat-group/text-to-speech/index.tsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client' -import useSWR from 'swr' -import React, { type FC } from 'react' -import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' -import { usePathname } from 'next/navigation' -import Panel from '@/app/components/app/configuration/base/feature-panel' -import { Speaker } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' -import ConfigContext from '@/context/debug-configuration' -import { languages } from '@/i18n/language' -import { fetchAppVoices } from '@/service/apps' -import AudioBtn from '@/app/components/base/audio-btn' - -const TextToSpeech: FC = () => { - const { t } = useTranslation() - const { - textToSpeechConfig, - } = useContext(ConfigContext) - - const pathname = usePathname() - const matched = pathname.match(/\/app\/([^/]+)/) - const appId = (matched?.length && matched[1]) ? matched[1] : '' - const language = textToSpeechConfig.language - const languageInfo = languages.find(i => i.value === textToSpeechConfig.language) - - const voiceItems = useSWR({ appId, language }, fetchAppVoices).data - const voiceItem = voiceItems?.find(item => item.value === textToSpeechConfig.voice) - - return ( - -
{t('appDebug.feature.textToSpeech.title')}
- - } - headerIcon={} - headerRight={ -
- {languageInfo && (`${languageInfo?.name} - `)}{voiceItem?.name ?? t('appDebug.voice.defaultDisplay')} - { languageInfo?.example && ( - - )} -
- } - noBodySpacing - isShowTextToSpeech - /> - ) -} -export default React.memo(TextToSpeech) diff --git a/web/app/components/app/configuration/index.tsx b/web/app/components/app/configuration/index.tsx index 5c5ed87ce3..6237362a3c 100644 --- a/web/app/components/app/configuration/index.tsx +++ b/web/app/components/app/configuration/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import React, { useEffect, useMemo, useRef, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import { usePathname } from 'next/navigation' @@ -9,17 +9,17 @@ import { useBoolean, useGetState } from 'ahooks' import { clone, isEqual } from 'lodash-es' import { CodeBracketIcon } from '@heroicons/react/20/solid' import { useShallow } from 'zustand/react/shallow' -import Button from '../../base/button' -import Loading from '../../base/loading' -import AppPublisher from '../app-publisher' -import AgentSettingButton from './config/agent-setting-button' -import useAdvancedPromptConfig from './hooks/use-advanced-prompt-config' -import EditHistoryModal from './config-prompt/conversation-histroy/edit-modal' +import AgentSettingButton from '@/app/components/app/configuration/config/agent-setting-button' +import useAdvancedPromptConfig from '@/app/components/app/configuration/hooks/use-advanced-prompt-config' +import EditHistoryModal from '@/app/components/app/configuration/config-prompt/conversation-histroy/edit-modal' import { useDebugWithSingleOrMultipleModel, useFormattingChangedDispatcher, -} from './debug/hooks' -import type { ModelAndParameter } from './debug/types' +} from '@/app/components/app/configuration/debug/hooks' +import type { ModelAndParameter } from '@/app/components/app/configuration/debug/types' +import Button from '@/app/components/base/button' +import Loading from '@/app/components/base/loading' +import AppPublisher from '@/app/components/app/app-publisher' import type { AnnotationReplyConfig, DatasetConfigs, @@ -61,6 +61,11 @@ import { getMultipleRetrievalConfig, getSelectedDatasetsMode, } from '@/app/components/workflow/nodes/knowledge-retrieval/utils' +import { FeaturesProvider } from '@/app/components/base/features' +import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types' +import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants' +import { SupportUploadFileTypes } from '@/app/components/workflow/types' +import NewFeaturePanel from '@/app/components/base/features/new-feature-panel' type PublishConfig = { modelConfig: ModelConfig @@ -70,10 +75,13 @@ type PublishConfig = { const Configuration: FC = () => { const { t } = useTranslation() const { notify } = useContext(ToastContext) - const { appDetail, setAppSiderbarExpand } = useAppStore(useShallow(state => ({ + const { appDetail, showAppConfigureFeaturesModal, setAppSiderbarExpand, setShowAppConfigureFeaturesModal } = useAppStore(useShallow(state => ({ appDetail: state.appDetail, setAppSiderbarExpand: state.setAppSiderbarExpand, + showAppConfigureFeaturesModal: state.showAppConfigureFeaturesModal, + setShowAppConfigureFeaturesModal: state.setShowAppConfigureFeaturesModal, }))) + const latestPublishedAt = useMemo(() => appDetail?.model_config.updated_at, [appDetail]) const [formattingChanged, setFormattingChanged] = useState(false) const { setShowAccountSettingModal } = useModalContext() const [hasFetchedDetail, setHasFetchedDetail] = useState(false) @@ -84,7 +92,6 @@ const Configuration: FC = () => { const [mode, setMode] = useState('') const [publishedConfig, setPublishedConfig] = useState(null) - const modalConfig = useMemo(() => appDetail?.model_config || {} as BackendModelConfig, [appDetail]) const [conversationId, setConversationId] = useState('') const media = useBreakpoints() @@ -158,13 +165,16 @@ const Configuration: FC = () => { prompt_template: '', prompt_variables: [] as PromptVariable[], }, - opening_statement: '', more_like_this: null, - suggested_questions_after_answer: null, + opening_statement: '', + suggested_questions: [], + sensitive_word_avoidance: null, speech_to_text: null, text_to_speech: null, + file_upload: null, + suggested_questions_after_answer: null, retriever_resource: null, - sensitive_word_avoidance: null, + annotation_reply: null, dataSets: [], agentConfig: DEFAULT_AGENT_SETTING, }) @@ -422,6 +432,41 @@ const Configuration: FC = () => { const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision) + // *** web app features *** + const featuresData: FeaturesData = useMemo(() => { + return { + moreLikeThis: modelConfig.more_like_this || { enabled: false }, + opening: { + enabled: !!modelConfig.opening_statement, + opening_statement: modelConfig.opening_statement || '', + suggested_questions: modelConfig.suggested_questions || [], + }, + moderation: modelConfig.sensitive_word_avoidance || { enabled: false }, + speech2text: modelConfig.speech_to_text || { enabled: false }, + text2speech: modelConfig.text_to_speech || { enabled: false }, + file: { + image: { + enabled: !!modelConfig.file_upload?.image?.enabled, + number_limits: modelConfig.file_upload?.image?.number_limits || 3, + transfer_methods: modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'], + }, + enabled: !!(modelConfig.file_upload?.enabled || modelConfig.file_upload?.image?.enabled), + allowed_file_types: modelConfig.file_upload?.allowed_file_types || [SupportUploadFileTypes.image], + allowed_file_extensions: modelConfig.file_upload?.allowed_file_extensions || FILE_EXTS[SupportUploadFileTypes.image].map(ext => `.${ext}`), + allowed_file_upload_methods: modelConfig.file_upload?.allowed_file_upload_methods || modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'], + number_limits: modelConfig.file_upload?.number_limits || modelConfig.file_upload?.image?.number_limits || 3, + } as FileUpload, + suggested: modelConfig.suggested_questions_after_answer || { enabled: false }, + citation: modelConfig.retriever_resource || { enabled: false }, + annotationReply: modelConfig.annotation_reply || { enabled: false }, + } + }, [modelConfig]) + const handleFeaturesChange = useCallback((flag: any) => { + setShowAppConfigureFeaturesModal(true) + if (flag) + formattingChangedDispatcher() + }, [formattingChangedDispatcher, setShowAppConfigureFeaturesModal]) + useEffect(() => { (async () => { const collectionList = await fetchCollectionList() @@ -514,13 +559,16 @@ const Configuration: FC = () => { modelConfig.dataset_query_variable, ), }, - opening_statement: modelConfig.opening_statement, more_like_this: modelConfig.more_like_this, - suggested_questions_after_answer: modelConfig.suggested_questions_after_answer, + opening_statement: modelConfig.opening_statement, + suggested_questions: modelConfig.suggested_questions, + sensitive_word_avoidance: modelConfig.sensitive_word_avoidance, speech_to_text: modelConfig.speech_to_text, text_to_speech: modelConfig.text_to_speech, + file_upload: modelConfig.file_upload, + suggested_questions_after_answer: modelConfig.suggested_questions_after_answer, retriever_resource: modelConfig.retriever_resource, - sensitive_word_avoidance: modelConfig.sensitive_word_avoidance, + annotation_reply: modelConfig.annotation_reply, external_data_tools: modelConfig.external_data_tools, dataSets: datasets || [], // eslint-disable-next-line multiline-ternary @@ -543,6 +591,7 @@ const Configuration: FC = () => { completionParams: model.completion_params, } + // ##TODO## new vision config if (modelConfig.file_upload) handleSetVisionConfig(modelConfig.file_upload.image, true) @@ -788,153 +837,165 @@ const Configuration: FC = () => { setRerankSettingModalOpen, }} > - <> -
-
- {/* Header */} -
-
-
-
{t('appDebug.orchestrate')}
-
- {isAdvancedMode && ( -
{t('appDebug.promptMode.advanced')}
+ + <> +
+
+ {/* Header */} +
+
+
+
{t('appDebug.orchestrate')}
+
+ {isAdvancedMode && ( +
{t('appDebug.promptMode.advanced')}
+ )} +
+
+
+ {/* Agent Setting */} + {isAgent && ( + { + const nextConfig = produce(modelConfig, (draft: ModelConfig) => { + draft.agentConfig = config + }) + setModelConfig(nextConfig) + }} + /> )} + {/* Model and Parameters */} + {!debugWithMultipleModel && ( + <> + { + setCompletionParams(newParams) + }} + debugWithMultipleModel={debugWithMultipleModel} + onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange} + /> +
+ + )} + {isMobile && ( + + )} + setRestoreConfirmOpen(true), + }} />
-
- {/* Agent Setting */} - {isAgent && ( - { - const nextConfig = produce(modelConfig, (draft: ModelConfig) => { - draft.agentConfig = config - }) - setModelConfig(nextConfig) - }} - /> - )} - {/* Model and Parameters */} - {!debugWithMultipleModel && ( - <> - { - setCompletionParams(newParams) - }} - debugWithMultipleModel={debugWithMultipleModel} - onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange} - /> -
- - )} - {isMobile && ( - - )} - setRestoreConfirmOpen(true), - }} /> +
+
+ +
+ {!isMobile &&
+
+ setShowAccountSettingModal({ payload: 'provider' })} + inputs={inputs} + modelParameterParams={{ + setModel: setModel as any, + onCompletionParamsChange: setCompletionParams, + }} + debugWithMultipleModel={debugWithMultipleModel} + multipleModelConfigs={multipleModelConfigs} + onMultipleModelConfigsChange={handleMultipleModelConfigsChange} + />
-
+
}
-
- -
- {!isMobile &&
-
- setShowAccountSettingModal({ payload: 'provider' })} - inputs={inputs} - modelParameterParams={{ - setModel: setModel as any, - onCompletionParamsChange: setCompletionParams, - }} - debugWithMultipleModel={debugWithMultipleModel} - multipleModelConfigs={multipleModelConfigs} - onMultipleModelConfigsChange={handleMultipleModelConfigsChange} - /> -
-
}
-
- {restoreConfirmOpen && ( - setRestoreConfirmOpen(false)} - /> - )} - {showUseGPT4Confirm && ( - { - setShowAccountSettingModal({ payload: 'provider' }) - setShowUseGPT4Confirm(false) - }} - onCancel={() => setShowUseGPT4Confirm(false)} - /> - )} - - {isShowSelectDataSet && ( - - )} - - {isShowHistoryModal && ( - { - setConversationHistoriesRole(data) - hideHistoryModal() - }} - /> - )} - {isMobile && ( - - setShowAccountSettingModal({ payload: 'provider' })} - inputs={inputs} - modelParameterParams={{ - setModel: setModel as any, - onCompletionParamsChange: setCompletionParams, - }} - debugWithMultipleModel={debugWithMultipleModel} - multipleModelConfigs={multipleModelConfigs} - onMultipleModelConfigsChange={handleMultipleModelConfigsChange} + {restoreConfirmOpen && ( + setRestoreConfirmOpen(false)} /> - - )} - + )} + {showUseGPT4Confirm && ( + { + setShowAccountSettingModal({ payload: 'provider' }) + setShowUseGPT4Confirm(false) + }} + onCancel={() => setShowUseGPT4Confirm(false)} + /> + )} + + {isShowSelectDataSet && ( + + )} + + {isShowHistoryModal && ( + { + setConversationHistoriesRole(data) + hideHistoryModal() + }} + /> + )} + {isMobile && ( + + setShowAccountSettingModal({ payload: 'provider' })} + inputs={inputs} + modelParameterParams={{ + setModel: setModel as any, + onCompletionParamsChange: setCompletionParams, + }} + debugWithMultipleModel={debugWithMultipleModel} + multipleModelConfigs={multipleModelConfigs} + onMultipleModelConfigsChange={handleMultipleModelConfigsChange} + /> + + )} + {showAppConfigureFeaturesModal && ( + setShowAppConfigureFeaturesModal(false)} + /> + )} + + ) } diff --git a/web/app/components/app/store.ts b/web/app/components/app/store.ts index 0209102372..5f02f92f0d 100644 --- a/web/app/components/app/store.ts +++ b/web/app/components/app/store.ts @@ -10,6 +10,7 @@ type State = { showPromptLogModal: boolean showAgentLogModal: boolean showMessageLogModal: boolean + showAppConfigureFeaturesModal: boolean } type Action = { @@ -20,6 +21,7 @@ type Action = { setShowPromptLogModal: (showPromptLogModal: boolean) => void setShowAgentLogModal: (showAgentLogModal: boolean) => void setShowMessageLogModal: (showMessageLogModal: boolean) => void + setShowAppConfigureFeaturesModal: (showAppConfigureFeaturesModal: boolean) => void } export const useStore = create(set => ({ @@ -47,4 +49,6 @@ export const useStore = create(set => ({ } } }), + showAppConfigureFeaturesModal: false, + setShowAppConfigureFeaturesModal: showAppConfigureFeaturesModal => set(() => ({ showAppConfigureFeaturesModal })), })) diff --git a/web/app/components/base/features/feature-choose/feature-group/index.tsx b/web/app/components/base/features/feature-choose/feature-group/index.tsx deleted file mode 100644 index a4b27f18d4..0000000000 --- a/web/app/components/base/features/feature-choose/feature-group/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import GroupName from '@/app/components/app/configuration/base/group-name' - -export type IFeatureGroupProps = { - title: string - description?: string - children: React.ReactNode -} - -const FeatureGroup: FC = ({ - title, - description, - children, -}) => { - return ( -
-
- - {description && ( -
{description}
- )} -
-
- {children} -
-
- ) -} -export default React.memo(FeatureGroup) diff --git a/web/app/components/base/features/feature-choose/feature-item/index.tsx b/web/app/components/base/features/feature-choose/feature-item/index.tsx deleted file mode 100644 index 9a470d633a..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/index.tsx +++ /dev/null @@ -1,96 +0,0 @@ -'use client' -import type { FC } from 'react' -import React, { useCallback } from 'react' -import produce from 'immer' -import s from './style.module.css' -import cn from '@/utils/classnames' -import Switch from '@/app/components/base/switch' -import { FeatureEnum } from '@/app/components/base/features/types' -import { useFeaturesStore } from '@/app/components/base/features/hooks' -import { useModalContext } from '@/context/modal-context' - -export type IFeatureItemProps = { - icon: React.ReactNode - previewImgClassName?: string - title: string - description: string - value: boolean - onChange: (type: FeatureEnum, value: boolean) => void - type: FeatureEnum -} - -const FeatureItem: FC = ({ - icon, - previewImgClassName, - title, - description, - value, - onChange, - type, -}) => { - const featuresStore = useFeaturesStore() - const { setShowModerationSettingModal } = useModalContext() - - const handleChange = useCallback((newValue: boolean) => { - const { - features, - setFeatures, - } = featuresStore!.getState() - - if (newValue && !features.moderation?.type && type === FeatureEnum.moderation) { - setShowModerationSettingModal({ - payload: { - enabled: true, - type: 'keywords', - config: { - keywords: '', - inputs_config: { - enabled: true, - preset_response: '', - }, - }, - }, - onSaveCallback: (newModeration) => { - setFeatures(produce(features, (draft) => { - draft.moderation = newModeration - })) - }, - onCancelCallback: () => { - setFeatures(produce(features, (draft) => { - draft.moderation = { enabled: false } - })) - }, - }) - return - } - onChange(type, newValue) - }, [type, onChange, featuresStore, setShowModerationSettingModal]) - - return ( -
-
- {/* icon */} -
- {icon} -
-
-
{title}
-
{description}
-
-
- - - { - previewImgClassName && ( -
-
) - } -
- ) -} -export default React.memo(FeatureItem) diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citation.svg b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citation.svg deleted file mode 100644 index 82fb182a7a..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citation.svg +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citations-and-attributions-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citations-and-attributions-preview@2x.png deleted file mode 100644 index ef066204ca..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/citations-and-attributions-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/conversation-opener-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/conversation-opener-preview@2x.png deleted file mode 100644 index 15639d500d..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/conversation-opener-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this-preview@2x.png deleted file mode 100644 index 62671c5889..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this.svg b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this.svg deleted file mode 100644 index 6ccc84e70f..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/more-like-this.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/next-question-suggestion-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/next-question-suggestion-preview@2x.png deleted file mode 100644 index 758708ff15..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/next-question-suggestion-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-statement.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-statement.png deleted file mode 100644 index 51e1bf395e..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-statement.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-suggestion-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-suggestion-preview@2x.png deleted file mode 100644 index 8bb4add322..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/opening-suggestion-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text-preview@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text-preview@2x.png deleted file mode 100644 index 68df3983dc..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text-preview@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text.svg b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text.svg deleted file mode 100644 index 029b92fee4..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/speech-to-text.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/suggested-questions-after-answer.svg b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/suggested-questions-after-answer.svg deleted file mode 100644 index c0102b7e08..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/suggested-questions-after-answer.svg +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png deleted file mode 100644 index 91396e72c7..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png b/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png deleted file mode 100644 index 7558e78bd9..0000000000 Binary files a/web/app/components/base/features/feature-choose/feature-item/preview-imgs/text-to-audio-preview-completion@2x.png and /dev/null differ diff --git a/web/app/components/base/features/feature-choose/feature-item/style.module.css b/web/app/components/base/features/feature-choose/feature-item/style.module.css deleted file mode 100644 index 80c9460e48..0000000000 --- a/web/app/components/base/features/feature-choose/feature-item/style.module.css +++ /dev/null @@ -1,41 +0,0 @@ -.preview { - display: none; - position: absolute; - top: 0; - left: 100%; - transform: translate(32px, -54px); - width: 280px; - height: 360px; - background: center center no-repeat; - background-size: contain; - border-radius: 8px; -} - -.wrap:hover .preview { - display: block; -} - -.openingStatementPreview { - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/opening-statement.png); -} - -.suggestedQuestionsAfterAnswerPreview { - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/suggested-questions-after-answer.png); -} - -.moreLikeThisPreview { - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/more-like-this.png); -} - -.speechToTextPreview { - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/speech-to-text.png); -} - -.textToSpeechPreview { - @apply shadow-lg rounded-lg; - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/text-to-audio-preview-assistant@2x.png); -} - -.citationPreview { - background-image: url(~@/app/components/app/configuration/config/feature/choose-feature/feature-item/preview-imgs/citation.png); -} diff --git a/web/app/components/base/features/feature-choose/feature-modal.tsx b/web/app/components/base/features/feature-choose/feature-modal.tsx deleted file mode 100644 index 7f73fe65a1..0000000000 --- a/web/app/components/base/features/feature-choose/feature-modal.tsx +++ /dev/null @@ -1,147 +0,0 @@ -'use client' -import type { FC } from 'react' -import React, { useCallback } from 'react' -import produce from 'immer' -import { useTranslation } from 'react-i18next' -import { - useFeatures, - useFeaturesStore, -} from '../hooks' -import type { OnFeaturesChange } from '../types' -import FeatureGroup from './feature-group' -import FeatureItem from './feature-item' -import Modal from '@/app/components/base/modal' -import SuggestedQuestionsAfterAnswerIcon from '@/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon' -import { Microphone01, Speaker } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' -import { Citations } from '@/app/components/base/icons/src/vender/solid/editor' -import { FileSearch02 } from '@/app/components/base/icons/src/vender/solid/files' -import { MessageHeartCircle } from '@/app/components/base/icons/src/vender/solid/communication' -import { FeatureEnum } from '@/app/components/base/features/types' -import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' -import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' - -export type FeatureModalProps = { - onChange?: OnFeaturesChange -} - -const FeatureModal: FC = ({ - onChange, -}) => { - const { t } = useTranslation() - const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text) - const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.tts) - const featuresStore = useFeaturesStore() - const setShowFeaturesModal = useFeatures(s => s.setShowFeaturesModal) - const features = useFeatures(s => s.features) - - const handleCancelModal = useCallback(() => { - setShowFeaturesModal(false) - }, [setShowFeaturesModal]) - - const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => { - const { - features, - setFeatures, - } = featuresStore!.getState() - - const newFeatures = produce(features, (draft) => { - draft[type] = { - ...draft[type], - enabled, - } - }) - setFeatures(newFeatures) - if (onChange) - onChange(newFeatures) - }, [featuresStore, onChange]) - - return ( - -
- {/* Chat Feature */} - - <> - } - previewImgClassName='openingStatementPreview' - title={t('appDebug.feature.conversationOpener.title')} - description={t('appDebug.feature.conversationOpener.description')} - value={!!features.opening?.enabled} - onChange={handleChange} - type={FeatureEnum.opening} - /> - } - previewImgClassName='suggestedQuestionsAfterAnswerPreview' - title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')} - description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')} - value={!!features.suggested?.enabled} - onChange={handleChange} - type={FeatureEnum.suggested} - /> - { - !!text2speechDefaultModel && ( - } - previewImgClassName='textToSpeechPreview' - title={t('appDebug.feature.textToSpeech.title')} - description={t('appDebug.feature.textToSpeech.description')} - value={!!features.text2speech?.enabled} - onChange={handleChange} - type={FeatureEnum.text2speech} - /> - ) - } - { - !!speech2textDefaultModel && ( - } - previewImgClassName='speechToTextPreview' - title={t('appDebug.feature.speechToText.title')} - description={t('appDebug.feature.speechToText.description')} - value={!!features.speech2text?.enabled} - onChange={handleChange} - type={FeatureEnum.speech2text} - /> - ) - } - } - previewImgClassName='citationPreview' - title={t('appDebug.feature.citation.title')} - description={t('appDebug.feature.citation.description')} - value={!!features.citation?.enabled} - onChange={handleChange} - type={FeatureEnum.citation} - /> - - - - - <> - } - previewImgClassName='' - title={t('appDebug.feature.moderation.title')} - description={t('appDebug.feature.moderation.description')} - value={!!features.moderation?.enabled} - onChange={handleChange} - type={FeatureEnum.moderation} - /> - - -
-
- ) -} -export default React.memo(FeatureModal) diff --git a/web/app/components/base/features/feature-choose/index.tsx b/web/app/components/base/features/feature-choose/index.tsx deleted file mode 100644 index e7b114f783..0000000000 --- a/web/app/components/base/features/feature-choose/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client' -import React from 'react' -import { useTranslation } from 'react-i18next' -import { - RiAddLine, -} from '@remixicon/react' -import { useFeatures } from '../hooks' -import type { OnFeaturesChange } from '../types' -import FeatureModal from './feature-modal' -import Button from '@/app/components/base/button' - -type ChooseFeatureProps = { - onChange?: OnFeaturesChange - disabled?: boolean -} -const ChooseFeature = ({ - onChange, - disabled, -}: ChooseFeatureProps) => { - const { t } = useTranslation() - const showFeaturesModal = useFeatures(s => s.showFeaturesModal) - const setShowFeaturesModal = useFeatures(s => s.setShowFeaturesModal) - return ( - <> - - { - showFeaturesModal && ( - - ) - } - - ) -} -export default React.memo(ChooseFeature) diff --git a/web/app/components/base/features/index.tsx b/web/app/components/base/features/index.tsx index 13bffb3669..daea711c07 100644 --- a/web/app/components/base/features/index.tsx +++ b/web/app/components/base/features/index.tsx @@ -1,3 +1 @@ -export { default as FeaturesPanel } from './feature-panel' -export { default as FeaturesChoose } from './feature-choose' export { FeaturesProvider } from './context' diff --git a/web/app/components/base/features/new-feature-panel/conversation-opener/index.tsx b/web/app/components/base/features/new-feature-panel/conversation-opener/index.tsx index f9e2d5b213..db7bad4d18 100644 --- a/web/app/components/base/features/new-feature-panel/conversation-opener/index.tsx +++ b/web/app/components/base/features/new-feature-panel/conversation-opener/index.tsx @@ -39,11 +39,11 @@ const ConversationOpener = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, onCancelCallback: () => { if (onChange) - onChange(features) + onChange() }, }) }, [disabled, featuresStore, onChange, opening, setShowOpeningModal]) @@ -62,7 +62,7 @@ const ConversationOpener = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange]) return ( 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 d1900c191f..4975a06d15 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 @@ -35,7 +35,7 @@ const DialogWrapper = ({
-
+
- + {children} diff --git a/web/app/components/base/features/new-feature-panel/file-upload/index.tsx b/web/app/components/base/features/new-feature-panel/file-upload/index.tsx index 505e7cc809..7babdd71fd 100644 --- a/web/app/components/base/features/new-feature-panel/file-upload/index.tsx +++ b/web/app/components/base/features/new-feature-panel/file-upload/index.tsx @@ -44,7 +44,7 @@ const FileUpload = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange]) return ( diff --git a/web/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx b/web/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx index 44d1da938f..59d363f880 100644 --- a/web/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx +++ b/web/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx @@ -49,7 +49,7 @@ const SettingContent = ({ setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange, tempPayload]) return ( diff --git a/web/app/components/base/features/new-feature-panel/index.tsx b/web/app/components/base/features/new-feature-panel/index.tsx index 2388668a6c..1d7e174985 100644 --- a/web/app/components/base/features/new-feature-panel/index.tsx +++ b/web/app/components/base/features/new-feature-panel/index.tsx @@ -33,6 +33,7 @@ type Props = { disabled: boolean onChange?: OnFeaturesChange onClose: () => void + inWorkflow?: boolean } const NewFeaturePanel = ({ @@ -42,6 +43,7 @@ const NewFeaturePanel = ({ disabled, onChange, onClose, + inWorkflow = true, }: Props) => { const { t } = useTranslation() const router = useRouter() @@ -74,6 +76,7 @@ const NewFeaturePanel = ({
{/* header */} diff --git a/web/app/components/base/features/new-feature-panel/moderation/index.tsx b/web/app/components/base/features/new-feature-panel/moderation/index.tsx index 476d5a7a96..201efe3f67 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/index.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/index.tsx @@ -54,7 +54,7 @@ const Moderation = ({ }, onCancelCallback: () => { if (onChange) - onChange(features) + onChange() }, }) } @@ -92,7 +92,7 @@ const Moderation = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, }) } diff --git a/web/app/components/base/features/new-feature-panel/more-like-this.tsx b/web/app/components/base/features/new-feature-panel/more-like-this.tsx index 59fd806493..ac9ab07c9d 100644 --- a/web/app/components/base/features/new-feature-panel/more-like-this.tsx +++ b/web/app/components/base/features/new-feature-panel/more-like-this.tsx @@ -34,7 +34,7 @@ const MoreLikeThis = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange]) return ( diff --git a/web/app/components/base/features/new-feature-panel/speech-to-text.tsx b/web/app/components/base/features/new-feature-panel/speech-to-text.tsx index 7a490bcdcc..837b924035 100644 --- a/web/app/components/base/features/new-feature-panel/speech-to-text.tsx +++ b/web/app/components/base/features/new-feature-panel/speech-to-text.tsx @@ -34,7 +34,7 @@ const SpeechToText = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange]) return ( diff --git a/web/app/components/base/features/new-feature-panel/text-to-speech/index.tsx b/web/app/components/base/features/new-feature-panel/text-to-speech/index.tsx index efbd51dd4e..4bde7247a8 100644 --- a/web/app/components/base/features/new-feature-panel/text-to-speech/index.tsx +++ b/web/app/components/base/features/new-feature-panel/text-to-speech/index.tsx @@ -43,7 +43,7 @@ const TextToSpeech = ({ }) setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() }, [featuresStore, onChange]) return ( diff --git a/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx b/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx index 47d47b7514..360ea8a72a 100644 --- a/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx +++ b/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx @@ -60,7 +60,7 @@ const VoiceParamConfig = ({ setFeatures(newFeatures) if (onChange) - onChange(newFeatures) + onChange() } return ( diff --git a/web/app/components/base/features/store.ts b/web/app/components/base/features/store.ts index 306640a08e..7fb3c9848a 100644 --- a/web/app/components/base/features/store.ts +++ b/web/app/components/base/features/store.ts @@ -50,6 +50,9 @@ export const createFeaturesStore = (initProps?: Partial) => { transfer_methods: [TransferMethod.local_file, TransferMethod.remote_url], }, }, + annotationReply: { + enabled: false, + }, }, } return createStore()(set => ({ diff --git a/web/app/components/base/features/types.ts b/web/app/components/base/features/types.ts index 128264a69f..211ba96cd5 100644 --- a/web/app/components/base/features/types.ts +++ b/web/app/components/base/features/types.ts @@ -39,6 +39,16 @@ export type FileUpload = { number_limits?: number } & EnabledOrDisabled +export type AnnotationReplyConfig = { + enabled: boolean + id?: string + score_threshold?: number + embedding_model?: { + embedding_provider_name: string + embedding_model_name: string + } +} + export enum FeatureEnum { moreLikeThis = 'moreLikeThis', opening = 'opening', @@ -48,6 +58,7 @@ export enum FeatureEnum { citation = 'citation', moderation = 'moderation', file = 'file', + annotationReply = 'annotationReply', } export type Features = { @@ -59,6 +70,7 @@ export type Features = { [FeatureEnum.citation]?: RetrieverResource [FeatureEnum.moderation]?: SensitiveWordAvoidance [FeatureEnum.file]?: FileUpload + [FeatureEnum.annotationReply]?: AnnotationReplyConfig } -export type OnFeaturesChange = (features: Features) => void +export type OnFeaturesChange = (features?: Features) => void diff --git a/web/context/debug-configuration.ts b/web/context/debug-configuration.ts index ff65fc29e6..bce93a58b2 100644 --- a/web/context/debug-configuration.ts +++ b/web/context/debug-configuration.ts @@ -204,13 +204,16 @@ const DebugConfigurationContext = createContext({ prompt_template: '', prompt_variables: [], }, - opening_statement: null, more_like_this: null, - suggested_questions_after_answer: null, + opening_statement: '', + suggested_questions: [], + sensitive_word_avoidance: null, speech_to_text: null, text_to_speech: null, + file_upload: null, + suggested_questions_after_answer: null, retriever_resource: null, - sensitive_word_avoidance: null, + annotation_reply: null, dataSets: [], agentConfig: DEFAULT_AGENT_SETTING, }, diff --git a/web/models/debug.ts b/web/models/debug.ts index 2b2af80065..2bfdf681ef 100644 --- a/web/models/debug.ts +++ b/web/models/debug.ts @@ -2,6 +2,7 @@ import type { AgentStrategy, ModelModeType, RETRIEVE_TYPE, ToolItem, TtsAutoPlay import type { RerankingModeEnum, } from '@/models/datasets' +import type { FileUpload } from '@/app/components/base/features/types' export type Inputs = Record export enum PromptMode { @@ -126,11 +127,14 @@ export type ModelConfig = { configs: PromptConfig opening_statement: string | null more_like_this: MoreLikeThisConfig | null + suggested_questions: string[] | null suggested_questions_after_answer: SuggestedQuestionsAfterAnswerConfig | null speech_to_text: SpeechToTextConfig | null text_to_speech: TextToSpeechConfig | null + file_upload: FileUpload | null retriever_resource: RetrieverResourceConfig | null sensitive_word_avoidance: ModerationConfig | null + annotation_reply: AnnotationReplyConfig | null dataSets: any[] agentConfig: AgentConfig } diff --git a/web/types/app.ts b/web/types/app.ts index fb8a407dd2..80eeda15f8 100644 --- a/web/types/app.ts +++ b/web/types/app.ts @@ -245,6 +245,7 @@ export type ModelConfig = { } files?: VisionFile[] created_at?: number + updated_at?: number } export type Language = typeof LanguagesSupported[number]