new features in chat app configuration
|
@ -262,6 +262,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
|||
{(mode !== AppType.completion && res?.opening_statement) && (
|
||||
<div className='mt-7'>
|
||||
<GroupName name={t('appDebug.feature.groupChat.title')} />
|
||||
{/* ##TODO## use new style of opening */}
|
||||
<OpeningStatement
|
||||
value={res?.opening_statement || ''}
|
||||
readonly
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { PlusIcon } from '@heroicons/react/24/solid'
|
||||
|
||||
export type IAddFeatureBtnProps = {
|
||||
toBottomHeight: number
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const ITEM_HEIGHT = 48
|
||||
|
||||
const AddFeatureBtn: FC<IAddFeatureBtnProps> = ({
|
||||
toBottomHeight,
|
||||
onClick,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div
|
||||
className='absolute z-[9] left-0 right-0 flex justify-center pb-4'
|
||||
style={{
|
||||
top: toBottomHeight - ITEM_HEIGHT,
|
||||
background: 'linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, #FFF 100%)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className='flex items-center h-8 space-x-2 px-3
|
||||
border border-primary-100 rounded-lg bg-primary-25 hover:bg-primary-50 cursor-pointer
|
||||
text-xs font-semibold text-primary-600 uppercase
|
||||
'
|
||||
onClick={onClick}
|
||||
>
|
||||
<PlusIcon className='w-4 h-4 font-semibold' />
|
||||
<div>{t('appDebug.operation.addFeature')}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(AddFeatureBtn)
|
|
@ -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<IFeatureItemProps> = ({
|
||||
icon,
|
||||
previewImgClassName,
|
||||
title,
|
||||
description,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className={cn(s.wrap, 'relative flex justify-between p-3 rounded-xl border border-transparent bg-gray-50 hover:border-gray-200 cursor-pointer')}>
|
||||
<div className='flex space-x-3 mr-2'>
|
||||
{/* icon */}
|
||||
<div
|
||||
className='shrink-0 flex items-center justify-center w-8 h-8 rounded-lg border border-gray-200 bg-white'
|
||||
style={{
|
||||
boxShadow: '0px 1px 2px rgba(16, 24, 40, 0.05)',
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div>
|
||||
<div className='text-sm font-semibold text-gray-800'>{title}</div>
|
||||
<div className='text-xs font-normal text-gray-500'>{description}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Switch onChange={onChange} defaultValue={value} />
|
||||
{
|
||||
previewImgClassName && (
|
||||
<div className={cn(s.preview, s[previewImgClassName])}>
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(FeatureItem)
|
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 211 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 18 KiB |
|
@ -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);
|
||||
}
|
|
@ -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 = (
|
||||
<svg width="15" height="13" viewBox="0 0 15 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M8.33328 0.333252C4.83548 0.333252 1.99995 3.16878 1.99995 6.66659C1.99995 7.37325 2.11594 8.05419 2.33045 8.6906C2.36818 8.80254 2.39039 8.86877 2.40482 8.91762L2.40955 8.93407L2.40705 8.93928C2.38991 8.97462 2.36444 9.02207 2.31681 9.11025L1.21555 11.1486C1.1473 11.2749 1.07608 11.4066 1.02711 11.5212C0.978424 11.6351 0.899569 11.844 0.938369 12.0916C0.98385 12.3819 1.15471 12.6375 1.40556 12.7905C1.61957 12.9211 1.84276 12.9281 1.96659 12.9267C2.09117 12.9252 2.24012 12.9098 2.3829 12.895L5.81954 12.5397C5.87458 12.534 5.90335 12.5311 5.92443 12.5295L5.92715 12.5293L5.93539 12.5322C5.96129 12.5415 5.99642 12.555 6.05705 12.5784C6.76435 12.8509 7.53219 12.9999 8.33328 12.9999C11.8311 12.9999 14.6666 10.1644 14.6666 6.66659C14.6666 3.16878 11.8311 0.333252 8.33328 0.333252ZM5.97966 4.7214C6.73118 4.08722 7.73139 4.27352 8.3312 4.96609C8.931 4.27352 9.9183 4.09389 10.6827 4.7214C11.4472 5.34892 11.5401 6.41591 10.9499 7.16596C10.5843 7.63065 9.66655 8.47935 9.02117 9.05789C8.78411 9.2704 8.66558 9.37666 8.52332 9.41947C8.40129 9.4562 8.2611 9.4562 8.13907 9.41947C7.99682 9.37666 7.87829 9.2704 7.64122 9.05789C6.99584 8.47935 6.07814 7.63065 5.71251 7.16596C5.12234 6.41591 5.22815 5.35559 5.97966 4.7214Z" fill="#DD2590" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const ChooseFeature: FC<IChooseFeatureProps> = ({
|
||||
isShow,
|
||||
onClose,
|
||||
isChatApp,
|
||||
config,
|
||||
onChange,
|
||||
showTextToSpeechItem,
|
||||
showSpeechToTextItem,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Modal
|
||||
isShow={isShow}
|
||||
onClose={onClose}
|
||||
className='w-[400px]'
|
||||
title={t('appDebug.operation.addFeature')}
|
||||
closable
|
||||
overflowVisible
|
||||
>
|
||||
<div className='pt-5 pb-10'>
|
||||
{/* Chat Feature */}
|
||||
{isChatApp && (
|
||||
<FeatureGroup
|
||||
title={t('appDebug.feature.groupChat.title')}
|
||||
description={t('appDebug.feature.groupChat.description') as string}
|
||||
>
|
||||
<>
|
||||
<FeatureItem
|
||||
icon={OpeningStatementIcon}
|
||||
previewImgClassName='openingStatementPreview'
|
||||
title={t('appDebug.feature.conversationOpener.title')}
|
||||
description={t('appDebug.feature.conversationOpener.description')}
|
||||
value={config.openingStatement}
|
||||
onChange={value => onChange('openingStatement', value)}
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<SuggestedQuestionsAfterAnswerIcon />}
|
||||
previewImgClassName='suggestedQuestionsAfterAnswerPreview'
|
||||
title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
|
||||
description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
|
||||
value={config.suggestedQuestionsAfterAnswer}
|
||||
onChange={value => onChange('suggestedQuestionsAfterAnswer', value)}
|
||||
/>
|
||||
{
|
||||
showTextToSpeechItem && (
|
||||
<FeatureItem
|
||||
icon={<Speaker className='w-4 h-4 text-[#7839EE]' />}
|
||||
previewImgClassName='textToSpeechPreview'
|
||||
title={t('appDebug.feature.textToSpeech.title')}
|
||||
description={t('appDebug.feature.textToSpeech.description')}
|
||||
value={config.textToSpeech}
|
||||
onChange={value => onChange('textToSpeech', value)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
showSpeechToTextItem && (
|
||||
<FeatureItem
|
||||
icon={<Microphone01 className='w-4 h-4 text-[#7839EE]' />}
|
||||
previewImgClassName='speechToTextPreview'
|
||||
title={t('appDebug.feature.speechToText.title')}
|
||||
description={t('appDebug.feature.speechToText.description')}
|
||||
value={config.speechToText}
|
||||
onChange={value => onChange('speechToText', value)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<FeatureItem
|
||||
icon={<Citations className='w-4 h-4 text-[#FD853A]' />}
|
||||
previewImgClassName='citationPreview'
|
||||
title={t('appDebug.feature.citation.title')}
|
||||
description={t('appDebug.feature.citation.description')}
|
||||
value={config.citation}
|
||||
onChange={value => onChange('citation', value)}
|
||||
/>
|
||||
</>
|
||||
</FeatureGroup>
|
||||
)}
|
||||
|
||||
{/* Text Generation Feature */}
|
||||
{!isChatApp && (
|
||||
<FeatureGroup title={t('appDebug.feature.groupExperience.title')}>
|
||||
<>
|
||||
<FeatureItem
|
||||
icon={<MoreLikeThisIcon />}
|
||||
previewImgClassName='moreLikeThisPreview'
|
||||
title={t('appDebug.feature.moreLikeThis.title')}
|
||||
description={t('appDebug.feature.moreLikeThis.description')}
|
||||
value={config.moreLikeThis}
|
||||
onChange={value => onChange('moreLikeThis', value)}
|
||||
/>
|
||||
{
|
||||
showTextToSpeechItem && (
|
||||
<FeatureItem
|
||||
icon={<Speaker className='w-4 h-4 text-[#7839EE]' />}
|
||||
previewImgClassName='textToSpeechPreview'
|
||||
title={t('appDebug.feature.textToSpeech.title')}
|
||||
description={t('appDebug.feature.textToSpeech.description')}
|
||||
value={config.textToSpeech}
|
||||
onChange={value => onChange('textToSpeech', value)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</>
|
||||
</FeatureGroup>
|
||||
)}
|
||||
<FeatureGroup title={t('appDebug.feature.toolbox.title')}>
|
||||
<>
|
||||
<FeatureItem
|
||||
icon={<FileSearch02 className='w-4 h-4 text-[#039855]' />}
|
||||
previewImgClassName=''
|
||||
title={t('appDebug.feature.moderation.title')}
|
||||
description={t('appDebug.feature.moderation.description')}
|
||||
value={config.moderation}
|
||||
onChange={value => onChange('moderation', value)}
|
||||
/>
|
||||
{isChatApp && (
|
||||
<FeatureItem
|
||||
icon={<MessageFast className='w-4 h-4 text-[#444CE7]' />}
|
||||
title={t('appDebug.feature.annotation.title')}
|
||||
description={t('appDebug.feature.annotation.description')}
|
||||
value={config.annotation}
|
||||
onChange={value => onChange('annotation', value)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</FeatureGroup>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default React.memo(ChooseFeature)
|
|
@ -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<IFeatureGroupProps> = ({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div className='mb-6'>
|
||||
<div className='mb-2'>
|
||||
<GroupName name={title} />
|
||||
{description && (
|
||||
<div className='text-xs font-normal text-gray-500'>{description}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(FeatureGroup)
|
|
@ -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<HTMLDivElement>(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 (
|
||||
<>
|
||||
<div
|
||||
ref={wrapRef}
|
||||
className="grow h-0 relative px-6 pb-[50px] overflow-y-auto"
|
||||
>
|
||||
<AddFeatureBtn toBottomHeight={toBottomHeight} onClick={showChooseFeatureTrue} />
|
||||
{showChooseFeature && (
|
||||
<ChooseFeature
|
||||
isShow={showChooseFeature}
|
||||
onClose={showChooseFeatureFalse}
|
||||
isChatApp={isChatApp}
|
||||
config={featureConfig}
|
||||
onChange={handleFeatureChange}
|
||||
showSpeechToTextItem={!!speech2textDefaultModel}
|
||||
showTextToSpeechItem={!!text2speechDefaultModel}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Template */}
|
||||
<ConfigPrompt
|
||||
mode={mode as AppType}
|
||||
|
@ -254,55 +112,13 @@ const Config: FC = () => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{/* ChatConifig */}
|
||||
{
|
||||
hasChatConfig && (
|
||||
<ChatGroup
|
||||
isShowOpeningStatement={featureConfig.openingStatement}
|
||||
openingStatementConfig={
|
||||
{
|
||||
value: introduction,
|
||||
onChange: setIntroduction,
|
||||
suggestedQuestions,
|
||||
onSuggestedQuestionsChange: setSuggestedQuestions,
|
||||
}
|
||||
}
|
||||
isShowSuggestedQuestionsAfterAnswer={featureConfig.suggestedQuestionsAfterAnswer}
|
||||
isShowTextToSpeech={featureConfig.textToSpeech && !!text2speechDefaultModel}
|
||||
isShowSpeechText={featureConfig.speechToText && !!speech2textDefaultModel}
|
||||
isShowCitation={featureConfig.citation}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{/* Text Generation config */}{
|
||||
hasCompletionConfig && (
|
||||
<ExperienceEnchanceGroup
|
||||
isShowMoreLike={moreLikeThisConfig.enabled}
|
||||
isShowTextToSpeech={featureConfig.textToSpeech && !!text2speechDefaultModel}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{/* Toolbox */}
|
||||
{
|
||||
hasToolbox && (
|
||||
<Toolbox
|
||||
showModerationSettings={moderationConfig.enabled}
|
||||
showAnnotation={isChatApp && featureConfig.annotation}
|
||||
onEmbeddingChange={handleEnableAnnotation}
|
||||
onScoreChange={setScore}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
<ConfigParamModal
|
||||
appId={appId}
|
||||
isInit
|
||||
isShow={isShowAnnotationConfigInit}
|
||||
onHide={() => {
|
||||
setIsShowAnnotationConfigInit(false)
|
||||
showChooseFeatureTrue()
|
||||
// showChooseFeatureTrue()
|
||||
}}
|
||||
onSave={async (embeddingModel, score) => {
|
||||
await handleEnableAnnotation(embeddingModel, score)
|
||||
|
|
|
@ -121,6 +121,7 @@ const DebugWithMultipleModel = () => {
|
|||
))
|
||||
}
|
||||
</div>
|
||||
{/* ##TODO## */}
|
||||
{
|
||||
isChatMode && (
|
||||
<div className='shrink-0 pb-4 px-6'>
|
||||
|
|
|
@ -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<DebugWithSingleModelRefType, DebugWithSi
|
|||
completionParams,
|
||||
} = useDebugConfigurationContext()
|
||||
const { textGenerationModelList } = useProviderContext()
|
||||
const config = useConfigFromDebugContext()
|
||||
const features = useFeatures(s => 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<DebugWithSingleModelRefType, DebugWithSi
|
|||
}
|
||||
}, [handleRestart])
|
||||
|
||||
const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal)
|
||||
|
||||
return (
|
||||
<Chat
|
||||
config={config}
|
||||
chatList={chatList}
|
||||
isResponding={isResponding}
|
||||
chatContainerClassName='px-3 pt-6'
|
||||
chatFooterClassName='px-3 pt-10 pb-2'
|
||||
chatFooterClassName='px-3 pt-10 pb-0'
|
||||
showFeatureBar
|
||||
onFeatureBarClick={setShowAppConfigureFeaturesModal}
|
||||
suggestedQuestions={suggestedQuestions}
|
||||
onSend={doSend}
|
||||
onStopResponding={handleStop}
|
||||
|
|
|
@ -449,6 +449,7 @@ const Debug: FC<IDebug> = ({
|
|||
<ChatUserInput inputs={inputs} />
|
||||
</div>
|
||||
)}
|
||||
{/* ##TODO## new style of completion */}
|
||||
{mode === AppType.completion && (
|
||||
<PromptValuePanel
|
||||
appType={mode as AppType}
|
||||
|
|
|
@ -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 { Citations } from '@/app/components/base/icons/src/vender/solid/editor'
|
||||
|
||||
const Citation: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title={
|
||||
<div className='flex items-center gap-2'>
|
||||
<div>{t('appDebug.feature.citation.title')}</div>
|
||||
</div>
|
||||
}
|
||||
headerIcon={<Citations className='w-4 h-4 text-[#FD853A]' />}
|
||||
headerRight={
|
||||
<div className='text-xs text-gray-500'>{t('appDebug.feature.citation.resDes')}</div>
|
||||
}
|
||||
noBodySpacing
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default React.memo(Citation)
|
|
@ -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<ChatGroupProps> = ({
|
||||
isShowOpeningStatement,
|
||||
openingStatementConfig,
|
||||
isShowSuggestedQuestionsAfterAnswer,
|
||||
isShowSpeechText,
|
||||
isShowTextToSpeech,
|
||||
isShowCitation,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='mt-7'>
|
||||
<GroupName name={t('appDebug.feature.groupChat.title')} />
|
||||
<div className='space-y-3'>
|
||||
{isShowOpeningStatement && (
|
||||
<OpeningStatement {...openingStatementConfig} />
|
||||
)}
|
||||
{isShowSuggestedQuestionsAfterAnswer && (
|
||||
<SuggestedQuestionsAfterAnswer />
|
||||
)}
|
||||
{
|
||||
isShowTextToSpeech && (
|
||||
<TextToSpeech />
|
||||
)
|
||||
}
|
||||
{
|
||||
isShowSpeechText && (
|
||||
<SpeechToText />
|
||||
)
|
||||
}
|
||||
{
|
||||
isShowCitation && (
|
||||
<Citation />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(ChatGroup)
|
|
@ -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 (
|
||||
<Panel
|
||||
title={
|
||||
<div className='flex items-center gap-2'>
|
||||
<div>{t('appDebug.feature.speechToText.title')}</div>
|
||||
</div>
|
||||
}
|
||||
headerIcon={<Microphone01 className='w-4 h-4 text-[#7839EE]' />}
|
||||
headerRight={
|
||||
<div className='text-xs text-gray-500'>{t('appDebug.feature.speechToText.resDes')}</div>
|
||||
}
|
||||
noBodySpacing
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default React.memo(SpeechToTextConfig)
|
|
@ -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 (
|
||||
<Panel
|
||||
title={
|
||||
<div className='flex items-center gap-1'>
|
||||
<div>{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}</div>
|
||||
<Tooltip
|
||||
popupContent={
|
||||
<div className='w-[180px]'>
|
||||
{t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
headerIcon={<SuggestedQuestionsAfterAnswerIcon />}
|
||||
headerRight={
|
||||
<div className='text-xs text-gray-500'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.resDes')}</div>
|
||||
}
|
||||
noBodySpacing
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default React.memo(SuggestedQuestionsAfterAnswer)
|
|
@ -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 (
|
||||
<Panel
|
||||
title={
|
||||
<div className='flex items-center'>
|
||||
<div>{t('appDebug.feature.textToSpeech.title')}</div>
|
||||
</div>
|
||||
}
|
||||
headerIcon={<Speaker className='w-4 h-4 text-[#7839EE]' />}
|
||||
headerRight={
|
||||
<div className='text-xs text-gray-500 inline-flex items-center gap-2'>
|
||||
{languageInfo && (`${languageInfo?.name} - `)}{voiceItem?.name ?? t('appDebug.voice.defaultDisplay')}
|
||||
{ languageInfo?.example && (
|
||||
<AudioBtn
|
||||
value={languageInfo?.example}
|
||||
isAudition
|
||||
voice={textToSpeechConfig.voice}
|
||||
noCache
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
noBodySpacing
|
||||
isShowTextToSpeech
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default React.memo(TextToSpeech)
|
|
@ -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<PublishConfig | null>(null)
|
||||
|
||||
const modalConfig = useMemo(() => appDetail?.model_config || {} as BackendModelConfig, [appDetail])
|
||||
const [conversationId, setConversationId] = useState<string | null>('')
|
||||
|
||||
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,
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<div className="flex flex-col h-full">
|
||||
<div className='relative flex grow h-[200px] pt-14'>
|
||||
{/* Header */}
|
||||
<div className='absolute top-0 left-0 w-full bg-white h-14'>
|
||||
<div className='flex items-center justify-between px-6 h-14'>
|
||||
<div className='flex items-center'>
|
||||
<div className='text-base font-semibold leading-6 text-gray-900'>{t('appDebug.orchestrate')}</div>
|
||||
<div className='flex items-center h-[14px] space-x-1 text-xs'>
|
||||
{isAdvancedMode && (
|
||||
<div className='ml-1 flex items-center h-5 px-1.5 border border-gray-100 rounded-md text-[11px] font-medium text-gray-500 uppercase'>{t('appDebug.promptMode.advanced')}</div>
|
||||
<FeaturesProvider features={featuresData}>
|
||||
<>
|
||||
<div className="flex flex-col h-full">
|
||||
<div className='relative flex grow h-[200px] pt-14'>
|
||||
{/* Header */}
|
||||
<div className='absolute top-0 left-0 w-full bg-white h-14'>
|
||||
<div className='flex items-center justify-between px-6 h-14'>
|
||||
<div className='flex items-center'>
|
||||
<div className='text-base font-semibold leading-6 text-gray-900'>{t('appDebug.orchestrate')}</div>
|
||||
<div className='flex items-center h-[14px] space-x-1 text-xs'>
|
||||
{isAdvancedMode && (
|
||||
<div className='ml-1 flex items-center h-5 px-1.5 border border-gray-100 rounded-md text-[11px] font-medium text-gray-500 uppercase'>{t('appDebug.promptMode.advanced')}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
{/* Agent Setting */}
|
||||
{isAgent && (
|
||||
<AgentSettingButton
|
||||
isChatModel={modelConfig.mode === ModelModeType.chat}
|
||||
agentConfig={modelConfig.agentConfig}
|
||||
|
||||
isFunctionCall={isFunctionCall}
|
||||
onAgentSettingChange={(config) => {
|
||||
const nextConfig = produce(modelConfig, (draft: ModelConfig) => {
|
||||
draft.agentConfig = config
|
||||
})
|
||||
setModelConfig(nextConfig)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* Model and Parameters */}
|
||||
{!debugWithMultipleModel && (
|
||||
<>
|
||||
<ModelParameterModal
|
||||
isAdvancedMode={isAdvancedMode}
|
||||
mode={mode}
|
||||
provider={modelConfig.provider}
|
||||
completionParams={completionParams}
|
||||
modelId={modelConfig.model_id}
|
||||
setModel={setModel as any}
|
||||
onCompletionParamsChange={(newParams: FormValue) => {
|
||||
setCompletionParams(newParams)
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange}
|
||||
/>
|
||||
<div className='mx-2 w-[1px] h-[14px] bg-gray-200'></div>
|
||||
</>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Button className='!h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
|
||||
<span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
|
||||
<CodeBracketIcon className="w-4 h-4 text-gray-500" />
|
||||
</Button>
|
||||
)}
|
||||
<AppPublisher {...{
|
||||
publishDisabled: cannotPublish,
|
||||
publishedAt: (latestPublishedAt || 0) * 1000,
|
||||
debugWithMultipleModel,
|
||||
multipleModelConfigs,
|
||||
onPublish,
|
||||
onRestore: () => setRestoreConfirmOpen(true),
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
{/* Agent Setting */}
|
||||
{isAgent && (
|
||||
<AgentSettingButton
|
||||
isChatModel={modelConfig.mode === ModelModeType.chat}
|
||||
agentConfig={modelConfig.agentConfig}
|
||||
|
||||
isFunctionCall={isFunctionCall}
|
||||
onAgentSettingChange={(config) => {
|
||||
const nextConfig = produce(modelConfig, (draft: ModelConfig) => {
|
||||
draft.agentConfig = config
|
||||
})
|
||||
setModelConfig(nextConfig)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* Model and Parameters */}
|
||||
{!debugWithMultipleModel && (
|
||||
<>
|
||||
<ModelParameterModal
|
||||
isAdvancedMode={isAdvancedMode}
|
||||
mode={mode}
|
||||
provider={modelConfig.provider}
|
||||
completionParams={completionParams}
|
||||
modelId={modelConfig.model_id}
|
||||
setModel={setModel as any}
|
||||
onCompletionParamsChange={(newParams: FormValue) => {
|
||||
setCompletionParams(newParams)
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange}
|
||||
/>
|
||||
<div className='mx-2 w-[1px] h-[14px] bg-gray-200'></div>
|
||||
</>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Button className='!h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
|
||||
<span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
|
||||
<CodeBracketIcon className="w-4 h-4 text-gray-500" />
|
||||
</Button>
|
||||
)}
|
||||
<AppPublisher {...{
|
||||
publishDisabled: cannotPublish,
|
||||
publishedAt: (modalConfig.created_at || 0) * 1000,
|
||||
debugWithMultipleModel,
|
||||
multipleModelConfigs,
|
||||
onPublish,
|
||||
onRestore: () => setRestoreConfirmOpen(true),
|
||||
}} />
|
||||
</div>
|
||||
<div className={`w-full sm:w-1/2 shrink-0 flex flex-col h-full ${debugWithMultipleModel && 'max-w-[560px]'}`}>
|
||||
<Config />
|
||||
</div>
|
||||
{!isMobile && <div className="relative flex flex-col w-1/2 h-full overflow-y-auto grow " style={{ borderColor: 'rgba(0, 0, 0, 0.02)' }}>
|
||||
<div className='grow flex flex-col h-0 border-t-[0.5px] border-l-[0.5px] rounded-tl-2xl border-components-panel-border bg-chatbot-bg '>
|
||||
<Debug
|
||||
isAPIKeySet={isAPIKeySet}
|
||||
onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
|
||||
inputs={inputs}
|
||||
modelParameterParams={{
|
||||
setModel: setModel as any,
|
||||
onCompletionParamsChange: setCompletionParams,
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
<div className={`w-full sm:w-1/2 shrink-0 flex flex-col h-full ${debugWithMultipleModel && 'max-w-[560px]'}`}>
|
||||
<Config />
|
||||
</div>
|
||||
{!isMobile && <div className="relative flex flex-col w-1/2 h-full overflow-y-auto grow " style={{ borderColor: 'rgba(0, 0, 0, 0.02)' }}>
|
||||
<div className='grow flex flex-col h-0 border-t-[0.5px] border-l-[0.5px] rounded-tl-2xl border-components-panel-border bg-chatbot-bg '>
|
||||
<Debug
|
||||
isAPIKeySet={isAPIKeySet}
|
||||
onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
|
||||
inputs={inputs}
|
||||
modelParameterParams={{
|
||||
setModel: setModel as any,
|
||||
onCompletionParamsChange: setCompletionParams,
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
|
||||
/>
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
{restoreConfirmOpen && (
|
||||
<Confirm
|
||||
title={t('appDebug.resetConfig.title')}
|
||||
content={t('appDebug.resetConfig.message')}
|
||||
isShow={restoreConfirmOpen}
|
||||
onConfirm={resetAppConfig}
|
||||
onCancel={() => setRestoreConfirmOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{showUseGPT4Confirm && (
|
||||
<Confirm
|
||||
title={t('appDebug.trailUseGPT4Info.title')}
|
||||
content={t('appDebug.trailUseGPT4Info.description')}
|
||||
isShow={showUseGPT4Confirm}
|
||||
onConfirm={() => {
|
||||
setShowAccountSettingModal({ payload: 'provider' })
|
||||
setShowUseGPT4Confirm(false)
|
||||
}}
|
||||
onCancel={() => setShowUseGPT4Confirm(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isShowSelectDataSet && (
|
||||
<SelectDataSet
|
||||
isShow={isShowSelectDataSet}
|
||||
onClose={hideSelectDataSet}
|
||||
selectedIds={selectedIds}
|
||||
onSelect={handleSelect}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isShowHistoryModal && (
|
||||
<EditHistoryModal
|
||||
isShow={isShowHistoryModal}
|
||||
saveLoading={false}
|
||||
onClose={hideHistoryModal}
|
||||
data={completionPromptConfig.conversation_histories_role}
|
||||
onSave={(data) => {
|
||||
setConversationHistoriesRole(data)
|
||||
hideHistoryModal()
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Drawer showClose isOpen={isShowDebugPanel} onClose={hideDebugPanel} mask footer={null} panelClassname='!bg-gray-50'>
|
||||
<Debug
|
||||
isAPIKeySet={isAPIKeySet}
|
||||
onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
|
||||
inputs={inputs}
|
||||
modelParameterParams={{
|
||||
setModel: setModel as any,
|
||||
onCompletionParamsChange: setCompletionParams,
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
|
||||
{restoreConfirmOpen && (
|
||||
<Confirm
|
||||
title={t('appDebug.resetConfig.title')}
|
||||
content={t('appDebug.resetConfig.message')}
|
||||
isShow={restoreConfirmOpen}
|
||||
onConfirm={resetAppConfig}
|
||||
onCancel={() => setRestoreConfirmOpen(false)}
|
||||
/>
|
||||
</Drawer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{showUseGPT4Confirm && (
|
||||
<Confirm
|
||||
title={t('appDebug.trailUseGPT4Info.title')}
|
||||
content={t('appDebug.trailUseGPT4Info.description')}
|
||||
isShow={showUseGPT4Confirm}
|
||||
onConfirm={() => {
|
||||
setShowAccountSettingModal({ payload: 'provider' })
|
||||
setShowUseGPT4Confirm(false)
|
||||
}}
|
||||
onCancel={() => setShowUseGPT4Confirm(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isShowSelectDataSet && (
|
||||
<SelectDataSet
|
||||
isShow={isShowSelectDataSet}
|
||||
onClose={hideSelectDataSet}
|
||||
selectedIds={selectedIds}
|
||||
onSelect={handleSelect}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isShowHistoryModal && (
|
||||
<EditHistoryModal
|
||||
isShow={isShowHistoryModal}
|
||||
saveLoading={false}
|
||||
onClose={hideHistoryModal}
|
||||
data={completionPromptConfig.conversation_histories_role}
|
||||
onSave={(data) => {
|
||||
setConversationHistoriesRole(data)
|
||||
hideHistoryModal()
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Drawer showClose isOpen={isShowDebugPanel} onClose={hideDebugPanel} mask footer={null} panelClassname='!bg-gray-50'>
|
||||
<Debug
|
||||
isAPIKeySet={isAPIKeySet}
|
||||
onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
|
||||
inputs={inputs}
|
||||
modelParameterParams={{
|
||||
setModel: setModel as any,
|
||||
onCompletionParamsChange: setCompletionParams,
|
||||
}}
|
||||
debugWithMultipleModel={debugWithMultipleModel}
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
|
||||
/>
|
||||
</Drawer>
|
||||
)}
|
||||
{showAppConfigureFeaturesModal && (
|
||||
<NewFeaturePanel
|
||||
show
|
||||
inWorkflow={false}
|
||||
isChatMode={mode !== 'completion'}
|
||||
disabled={false}
|
||||
onChange={handleFeaturesChange}
|
||||
onClose={() => setShowAppConfigureFeaturesModal(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</FeaturesProvider>
|
||||
</ConfigContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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<State & Action>(set => ({
|
||||
|
@ -47,4 +49,6 @@ export const useStore = create<State & Action>(set => ({
|
|||
}
|
||||
}
|
||||
}),
|
||||
showAppConfigureFeaturesModal: false,
|
||||
setShowAppConfigureFeaturesModal: showAppConfigureFeaturesModal => set(() => ({ showAppConfigureFeaturesModal })),
|
||||
}))
|
||||
|
|
|
@ -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<IFeatureGroupProps> = ({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div className='mb-6'>
|
||||
<div className='mb-2'>
|
||||
<GroupName name={title} />
|
||||
{description && (
|
||||
<div className='text-xs font-normal text-gray-500'>{description}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(FeatureGroup)
|
|
@ -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<IFeatureItemProps> = ({
|
||||
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 (
|
||||
<div className={cn(s.wrap, 'relative flex justify-between p-3 rounded-xl border border-transparent bg-gray-50 hover:border-gray-200 cursor-pointer')}>
|
||||
<div className='flex space-x-3 mr-2'>
|
||||
{/* icon */}
|
||||
<div
|
||||
className='shrink-0 flex items-center justify-center w-8 h-8 rounded-lg border border-gray-200 bg-white'
|
||||
style={{
|
||||
boxShadow: '0px 1px 2px rgba(16, 24, 40, 0.05)',
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div>
|
||||
<div className='text-sm font-semibold text-gray-800'>{title}</div>
|
||||
<div className='text-xs font-normal text-gray-500'>{description}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Switch onChange={handleChange} defaultValue={value} />
|
||||
{
|
||||
previewImgClassName && (
|
||||
<div className={cn(s.preview, s[previewImgClassName])}>
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(FeatureItem)
|
Before Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 211 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 18 KiB |
|
@ -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);
|
||||
}
|
|
@ -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<FeatureModalProps> = ({
|
||||
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 (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={handleCancelModal}
|
||||
className='w-[400px]'
|
||||
title={t('appDebug.operation.addFeature')}
|
||||
closable
|
||||
overflowVisible
|
||||
>
|
||||
<div className='pt-5 pb-10'>
|
||||
{/* Chat Feature */}
|
||||
<FeatureGroup
|
||||
title={t('appDebug.feature.groupChat.title')}
|
||||
description={t('appDebug.feature.groupChat.description') as string}
|
||||
>
|
||||
<>
|
||||
<FeatureItem
|
||||
icon={<MessageHeartCircle className='w-4 h-4 text-[#DD2590]' />}
|
||||
previewImgClassName='openingStatementPreview'
|
||||
title={t('appDebug.feature.conversationOpener.title')}
|
||||
description={t('appDebug.feature.conversationOpener.description')}
|
||||
value={!!features.opening?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.opening}
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<SuggestedQuestionsAfterAnswerIcon />}
|
||||
previewImgClassName='suggestedQuestionsAfterAnswerPreview'
|
||||
title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
|
||||
description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
|
||||
value={!!features.suggested?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.suggested}
|
||||
/>
|
||||
{
|
||||
!!text2speechDefaultModel && (
|
||||
<FeatureItem
|
||||
icon={<Speaker className='w-4 h-4 text-[#7839EE]' />}
|
||||
previewImgClassName='textToSpeechPreview'
|
||||
title={t('appDebug.feature.textToSpeech.title')}
|
||||
description={t('appDebug.feature.textToSpeech.description')}
|
||||
value={!!features.text2speech?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.text2speech}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!speech2textDefaultModel && (
|
||||
<FeatureItem
|
||||
icon={<Microphone01 className='w-4 h-4 text-[#7839EE]' />}
|
||||
previewImgClassName='speechToTextPreview'
|
||||
title={t('appDebug.feature.speechToText.title')}
|
||||
description={t('appDebug.feature.speechToText.description')}
|
||||
value={!!features.speech2text?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.speech2text}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<FeatureItem
|
||||
icon={<Citations className='w-4 h-4 text-[#FD853A]' />}
|
||||
previewImgClassName='citationPreview'
|
||||
title={t('appDebug.feature.citation.title')}
|
||||
description={t('appDebug.feature.citation.description')}
|
||||
value={!!features.citation?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.citation}
|
||||
/>
|
||||
</>
|
||||
</FeatureGroup>
|
||||
|
||||
<FeatureGroup title={t('appDebug.feature.toolbox.title')}>
|
||||
<>
|
||||
<FeatureItem
|
||||
icon={<FileSearch02 className='w-4 h-4 text-[#039855]' />}
|
||||
previewImgClassName=''
|
||||
title={t('appDebug.feature.moderation.title')}
|
||||
description={t('appDebug.feature.moderation.description')}
|
||||
value={!!features.moderation?.enabled}
|
||||
onChange={handleChange}
|
||||
type={FeatureEnum.moderation}
|
||||
/>
|
||||
</>
|
||||
</FeatureGroup>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default React.memo(FeatureModal)
|
|
@ -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 (
|
||||
<>
|
||||
<Button
|
||||
className={`
|
||||
border-primary-100 bg-primary-25 text-xs font-semibold text-primary-600
|
||||
`}
|
||||
onClick={() => !disabled && setShowFeaturesModal(true)}
|
||||
>
|
||||
<RiAddLine className='mr-1 w-4 h-4' />
|
||||
{t('appDebug.operation.addFeature')}
|
||||
</Button>
|
||||
{
|
||||
showFeaturesModal && (
|
||||
<FeatureModal onChange={onChange} />
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default React.memo(ChooseFeature)
|
|
@ -1,3 +1 @@
|
|||
export { default as FeaturesPanel } from './feature-panel'
|
||||
export { default as FeaturesChoose } from './feature-choose'
|
||||
export { FeaturesProvider } from './context'
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -35,7 +35,7 @@ const DialogWrapper = ({
|
|||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0">
|
||||
<div className={cn('flex flex-col items-end justify-center min-h-full pb-2', inWorkflow ? 'pt-[112px]' : 'pt-[56px] pr-2')}>
|
||||
<div className={cn('flex flex-col items-end justify-center min-h-full pb-2', inWorkflow ? 'pt-[112px]' : 'pt-[64px] pr-2')}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
|
@ -45,7 +45,7 @@ const DialogWrapper = ({
|
|||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className={cn('grow flex relative w-[420px] h-0 p-0 overflow-hidden text-left align-middle transition-all transform bg-components-panel-bg-alt border-components-panel-border shadow-xl', inWorkflow ? 'border-t-[0.5px] border-l-[0.5px] border-b-[0.5px] rounded-l-2xl' : 'border-[0.5px] rounded', className)}>
|
||||
<Dialog.Panel className={cn('grow flex relative w-[420px] h-0 p-0 overflow-hidden text-left align-middle transition-all transform bg-components-panel-bg-alt border-components-panel-border shadow-xl', inWorkflow ? 'border-t-[0.5px] border-l-[0.5px] border-b-[0.5px] rounded-l-2xl' : 'border-[0.5px] rounded-2xl', className)}>
|
||||
{children}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
|
|
|
@ -44,7 +44,7 @@ const FileUpload = ({
|
|||
})
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}, [featuresStore, onChange])
|
||||
|
||||
return (
|
||||
|
|
|
@ -49,7 +49,7 @@ const SettingContent = ({
|
|||
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}, [featuresStore, onChange, tempPayload])
|
||||
|
||||
return (
|
||||
|
|
|
@ -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 = ({
|
|||
<DialogWrapper
|
||||
show={show}
|
||||
onClose={onClose}
|
||||
inWorkflow={inWorkflow}
|
||||
>
|
||||
<div className='grow flex flex-col h-full'>
|
||||
{/* header */}
|
||||
|
|
|
@ -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()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ const MoreLikeThis = ({
|
|||
})
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}, [featuresStore, onChange])
|
||||
|
||||
return (
|
||||
|
|
|
@ -34,7 +34,7 @@ const SpeechToText = ({
|
|||
})
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}, [featuresStore, onChange])
|
||||
|
||||
return (
|
||||
|
|
|
@ -43,7 +43,7 @@ const TextToSpeech = ({
|
|||
})
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}, [featuresStore, onChange])
|
||||
|
||||
return (
|
||||
|
|
|
@ -60,7 +60,7 @@ const VoiceParamConfig = ({
|
|||
|
||||
setFeatures(newFeatures)
|
||||
if (onChange)
|
||||
onChange(newFeatures)
|
||||
onChange()
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -50,6 +50,9 @@ export const createFeaturesStore = (initProps?: Partial<FeaturesState>) => {
|
|||
transfer_methods: [TransferMethod.local_file, TransferMethod.remote_url],
|
||||
},
|
||||
},
|
||||
annotationReply: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
return createStore<FeatureStoreState>()(set => ({
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -204,13 +204,16 @@ const DebugConfigurationContext = createContext<IDebugConfiguration>({
|
|||
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,
|
||||
},
|
||||
|
|
|
@ -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<string, string | number | object>
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -245,6 +245,7 @@ export type ModelConfig = {
|
|||
}
|
||||
files?: VisionFile[]
|
||||
created_at?: number
|
||||
updated_at?: number
|
||||
}
|
||||
|
||||
export type Language = typeof LanguagesSupported[number]
|
||||
|
|