mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-18 20:55:58 +08:00
vision config
This commit is contained in:
parent
0b94218378
commit
b60c7a5826
@ -9,7 +9,6 @@ export type IFeaturePanelProps = {
|
|||||||
title: ReactNode
|
title: ReactNode
|
||||||
headerRight?: ReactNode
|
headerRight?: ReactNode
|
||||||
hasHeaderBottomBorder?: boolean
|
hasHeaderBottomBorder?: boolean
|
||||||
isFocus?: boolean
|
|
||||||
noBodySpacing?: boolean
|
noBodySpacing?: boolean
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
}
|
}
|
||||||
@ -20,25 +19,17 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
|
|||||||
title,
|
title,
|
||||||
headerRight,
|
headerRight,
|
||||||
hasHeaderBottomBorder,
|
hasHeaderBottomBorder,
|
||||||
isFocus,
|
|
||||||
noBodySpacing,
|
noBodySpacing,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cn('rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn pb-3', noBodySpacing && '!pb-0', className)}>
|
||||||
className={cn(className, isFocus && 'border border-[#2D0DEE]', 'rounded-xl bg-gray-50 pt-2 pb-3', noBodySpacing && '!pb-0')}
|
|
||||||
style={isFocus
|
|
||||||
? {
|
|
||||||
boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
|
|
||||||
}
|
|
||||||
: {}}
|
|
||||||
>
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className={cn('pb-2 px-3', hasHeaderBottomBorder && 'border-b border-gray-100')}>
|
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
|
||||||
<div className='flex justify-between items-center h-8'>
|
<div className='flex justify-between items-center h-8'>
|
||||||
<div className='flex items-center space-x-1 shrink-0'>
|
<div className='flex items-center space-x-1 shrink-0'>
|
||||||
{headerIcon && <div className='flex items-center justify-center w-6 h-6'>{headerIcon}</div>}
|
{headerIcon && <div className='flex items-center justify-center w-6 h-6'>{headerIcon}</div>}
|
||||||
<div className='text-sm font-semibold text-gray-800'>{title}</div>
|
<div className='text-text-secondary system-sm-semibold'>{title}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex gap-2 items-center'>
|
<div className='flex gap-2 items-center'>
|
||||||
{headerRight && <div>{headerRight}</div>}
|
{headerRight && <div>{headerRight}</div>}
|
||||||
|
@ -23,7 +23,7 @@ const HistoryPanel: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
className='mt-3'
|
className='mt-2'
|
||||||
title={
|
title={
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<div>{t('appDebug.feature.conversationHistory.title')}</div>
|
<div>{t('appDebug.feature.conversationHistory.title')}</div>
|
||||||
|
@ -273,7 +273,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
className="mt-4"
|
className="mt-2"
|
||||||
headerIcon={
|
headerIcon={
|
||||||
<VarIcon className='w-4 h-4 text-primary-500' />
|
<VarIcon className='w-4 h-4 text-primary-500' />
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,84 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import produce from 'immer'
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import Panel from '../base/feature-panel'
|
import { Vision } from '@/app/components/base/icons/src/vender/features'
|
||||||
import ParamConfig from './param-config'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import Switch from '@/app/components/base/switch'
|
import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card'
|
||||||
import { Eye } from '@/app/components/base/icons/src/vender/solid/general'
|
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
|
import { Resolution } from '@/types/app'
|
||||||
|
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
const ConfigVision: FC = () => {
|
const ConfigVision: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const {
|
const { isShowVisionConfig } = useContext(ConfigContext)
|
||||||
isShowVisionConfig,
|
const file = useFeatures(s => s.features.file)
|
||||||
visionConfig,
|
const featuresStore = useFeaturesStore()
|
||||||
setVisionConfig,
|
|
||||||
} = useContext(ConfigContext)
|
const handleChange = useCallback((resolution: Resolution) => {
|
||||||
|
const {
|
||||||
|
features,
|
||||||
|
setFeatures,
|
||||||
|
} = featuresStore!.getState()
|
||||||
|
|
||||||
|
const newFeatures = produce(features, (draft) => {
|
||||||
|
draft.file = {
|
||||||
|
...draft.file,
|
||||||
|
image: { detail: resolution },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setFeatures(newFeatures)
|
||||||
|
}, [featuresStore])
|
||||||
|
|
||||||
if (!isShowVisionConfig)
|
if (!isShowVisionConfig)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
<Panel
|
<div className='mt-2 flex items-center gap-2 p-2 rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn'>
|
||||||
className="mt-4"
|
<div className='shrink-0 p-1'>
|
||||||
headerIcon={
|
<div className='p-1 rounded-lg border-[0.5px] border-divider-subtle shadow-xs bg-util-colors-indigo-indigo-600'>
|
||||||
<Eye className='w-4 h-4 text-[#6938EF]'/>
|
<Vision className='w-4 h-4 text-text-primary-on-surface' />
|
||||||
}
|
</div>
|
||||||
title={
|
</div>
|
||||||
<div className='flex items-center'>
|
<div className='grow flex items-center'>
|
||||||
<div className='mr-1'>{t('appDebug.vision.name')}</div>
|
<div className='mr-1 text-text-secondary system-sm-semibold'>{t('appDebug.vision.name')}</div>
|
||||||
|
<Tooltip
|
||||||
|
popupContent={
|
||||||
|
<div className='w-[180px]' >
|
||||||
|
{t('appDebug.vision.description')}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='shrink-0 flex items-center'>
|
||||||
|
<div className='mr-2 flex items-center gap-0.5'>
|
||||||
|
<div className='text-text-tertiary system-xs-medium-uppercase'>{t('appDebug.vision.visionSettings.resolution')}</div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={
|
popupContent={
|
||||||
<div className='w-[180px]' >
|
<div className='w-[180px]' >
|
||||||
{t('appDebug.vision.description')}
|
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
|
||||||
|
<div key={item}>{item}</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
<div className='flex items-center gap-1'>
|
||||||
headerRight={
|
<OptionCard
|
||||||
<div className='flex items-center'>
|
title={t('appDebug.vision.visionSettings.high')}
|
||||||
<ParamConfig />
|
selected={file?.image?.detail === Resolution.high}
|
||||||
<div className='ml-4 mr-3 w-[1px] h-3.5 bg-gray-200'></div>
|
onSelect={() => handleChange(Resolution.high)}
|
||||||
<Switch
|
/>
|
||||||
defaultValue={visionConfig.enabled}
|
<OptionCard
|
||||||
onChange={value => setVisionConfig({
|
title={t('appDebug.vision.visionSettings.low')}
|
||||||
...visionConfig,
|
selected={file?.image?.detail === Resolution.low}
|
||||||
enabled: value,
|
onSelect={() => handleChange(Resolution.low)}
|
||||||
})}
|
|
||||||
size='md'
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
noBodySpacing
|
</div>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default React.memo(ConfigVision)
|
export default React.memo(ConfigVision)
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import React from 'react'
|
|
||||||
import { useContext } from 'use-context-selector'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import RadioGroup from './radio-group'
|
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
|
||||||
import { Resolution, TransferMethod } from '@/types/app'
|
|
||||||
import ParamItem from '@/app/components/base/param-item'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
|
||||||
|
|
||||||
const MIN = 1
|
|
||||||
const MAX = 6
|
|
||||||
const ParamConfigContent: FC = () => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
const {
|
|
||||||
visionConfig,
|
|
||||||
setVisionConfig,
|
|
||||||
} = useContext(ConfigContext)
|
|
||||||
|
|
||||||
const transferMethod = (() => {
|
|
||||||
if (!visionConfig.transfer_methods || visionConfig.transfer_methods.length === 2)
|
|
||||||
return TransferMethod.all
|
|
||||||
|
|
||||||
return visionConfig.transfer_methods[0]
|
|
||||||
})()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<div className='leading-6 text-base font-semibold text-gray-800'>{t('appDebug.vision.visionSettings.title')}</div>
|
|
||||||
<div className='pt-3 space-y-6'>
|
|
||||||
<div>
|
|
||||||
<div className='mb-2 flex items-center space-x-1'>
|
|
||||||
<div className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.vision.visionSettings.resolution')}</div>
|
|
||||||
<Tooltip
|
|
||||||
popupContent={
|
|
||||||
<div className='w-[180px]' >
|
|
||||||
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
|
|
||||||
<div key={item}>{item}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<RadioGroup
|
|
||||||
className='space-x-3'
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
label: t('appDebug.vision.visionSettings.high'),
|
|
||||||
value: Resolution.high,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('appDebug.vision.visionSettings.low'),
|
|
||||||
value: Resolution.low,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
value={visionConfig.detail}
|
|
||||||
onChange={(value: Resolution) => {
|
|
||||||
setVisionConfig({
|
|
||||||
...visionConfig,
|
|
||||||
detail: value,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className='mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.vision.visionSettings.uploadMethod')}</div>
|
|
||||||
<RadioGroup
|
|
||||||
className='space-x-3'
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
label: t('appDebug.vision.visionSettings.both'),
|
|
||||||
value: TransferMethod.all,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('appDebug.vision.visionSettings.localUpload'),
|
|
||||||
value: TransferMethod.local_file,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('appDebug.vision.visionSettings.url'),
|
|
||||||
value: TransferMethod.remote_url,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
value={transferMethod}
|
|
||||||
onChange={(value: TransferMethod) => {
|
|
||||||
if (value === TransferMethod.all) {
|
|
||||||
setVisionConfig({
|
|
||||||
...visionConfig,
|
|
||||||
transfer_methods: [TransferMethod.remote_url, TransferMethod.local_file],
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setVisionConfig({
|
|
||||||
...visionConfig,
|
|
||||||
transfer_methods: [value],
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ParamItem
|
|
||||||
id='upload_limit'
|
|
||||||
className=''
|
|
||||||
name={t('appDebug.vision.visionSettings.uploadLimit')}
|
|
||||||
noTooltip
|
|
||||||
{...{
|
|
||||||
default: 2,
|
|
||||||
step: 1,
|
|
||||||
min: MIN,
|
|
||||||
max: MAX,
|
|
||||||
}}
|
|
||||||
value={visionConfig.number_limits}
|
|
||||||
enable={true}
|
|
||||||
onChange={(_key: string, value: number) => {
|
|
||||||
if (!value)
|
|
||||||
return
|
|
||||||
|
|
||||||
setVisionConfig({
|
|
||||||
...visionConfig,
|
|
||||||
number_limits: value,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default React.memo(ParamConfigContent)
|
|
@ -1,41 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import { memo, useState } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import VoiceParamConfig from './param-config-content'
|
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
import { Settings01 } from '@/app/components/base/icons/src/vender/line/general'
|
|
||||||
import {
|
|
||||||
PortalToFollowElem,
|
|
||||||
PortalToFollowElemContent,
|
|
||||||
PortalToFollowElemTrigger,
|
|
||||||
} from '@/app/components/base/portal-to-follow-elem'
|
|
||||||
|
|
||||||
const ParamsConfig: FC = () => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [open, setOpen] = useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PortalToFollowElem
|
|
||||||
open={open}
|
|
||||||
onOpenChange={setOpen}
|
|
||||||
placement='bottom-end'
|
|
||||||
offset={{
|
|
||||||
mainAxis: 4,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
|
||||||
<div className={cn('flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200', open && 'bg-gray-200')}>
|
|
||||||
<Settings01 className='w-3.5 h-3.5 ' />
|
|
||||||
<div className='ml-1 leading-[18px] text-xs font-medium '>{t('appDebug.voice.settings')}</div>
|
|
||||||
</div>
|
|
||||||
</PortalToFollowElemTrigger>
|
|
||||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
|
||||||
<div className='w-80 sm:w-[412px] p-4 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg space-y-3'>
|
|
||||||
<VoiceParamConfig />
|
|
||||||
</div>
|
|
||||||
</PortalToFollowElemContent>
|
|
||||||
</PortalToFollowElem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default memo(ParamsConfig)
|
|
@ -1,40 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import React from 'react'
|
|
||||||
import s from './style.module.css'
|
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
|
|
||||||
type OPTION = {
|
|
||||||
label: string
|
|
||||||
value: any
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
className?: string
|
|
||||||
options: OPTION[]
|
|
||||||
value: any
|
|
||||||
onChange: (value: any) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const RadioGroup: FC<Props> = ({
|
|
||||||
className = '',
|
|
||||||
options,
|
|
||||||
value,
|
|
||||||
onChange,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div className={cn(className, 'flex')}>
|
|
||||||
{options.map(item => (
|
|
||||||
<div
|
|
||||||
key={item.value}
|
|
||||||
className={cn(s.item, item.value === value && s.checked)}
|
|
||||||
onClick={() => onChange(item.value)}
|
|
||||||
>
|
|
||||||
<div className={s.radio}></div>
|
|
||||||
<div className='text-[13px] font-medium text-gray-900'>{item.label}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(RadioGroup)
|
|
@ -1,24 +0,0 @@
|
|||||||
.item {
|
|
||||||
@apply grow flex items-center h-8 px-2.5 rounded-lg bg-gray-25 border border-gray-100 cursor-pointer space-x-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item:hover {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-color: #B2CCFF;
|
|
||||||
box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item.checked {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-color: #528BFF;
|
|
||||||
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.06), 0px 1px 3px 0px rgba(16, 24, 40, 0.10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio {
|
|
||||||
@apply w-4 h-4 border-[2px] border-gray-200 rounded-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item.checked .radio {
|
|
||||||
border-width: 5px;
|
|
||||||
border-color: #155eef;
|
|
||||||
}
|
|
@ -58,7 +58,7 @@ const AgentTools: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Panel
|
<Panel
|
||||||
className="mt-4"
|
className="mt-2"
|
||||||
noBodySpacing={tools.length === 0}
|
noBodySpacing={tools.length === 0}
|
||||||
headerIcon={
|
headerIcon={
|
||||||
<RiHammerFill className='w-4 h-4 text-primary-500' />
|
<RiHammerFill className='w-4 h-4 text-primary-500' />
|
||||||
|
@ -70,7 +70,7 @@ const DatasetConfig: FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FeaturePanel
|
<FeaturePanel
|
||||||
className='mt-3'
|
className='mt-2'
|
||||||
headerIcon={Icon}
|
headerIcon={Icon}
|
||||||
title={t('appDebug.feature.dataSet.title')}
|
title={t('appDebug.feature.dataSet.title')}
|
||||||
headerRight={
|
headerRight={
|
||||||
|
@ -49,6 +49,7 @@ const ChatUserInput = ({
|
|||||||
return (
|
return (
|
||||||
<div className={cn('bg-components-panel-on-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle shadow-xs z-[1]')}>
|
<div className={cn('bg-components-panel-on-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle shadow-xs z-[1]')}>
|
||||||
<div className='px-4 pt-3 pb-4'>
|
<div className='px-4 pt-3 pb-4'>
|
||||||
|
{/* ##TODO## file_upload */}
|
||||||
{promptVariables.map(({ key, name, type, options, max_length, required }, index) => (
|
{promptVariables.map(({ key, name, type, options, max_length, required }, index) => (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
|
@ -40,7 +40,6 @@ const ChatItem: FC<ChatItemProps> = ({
|
|||||||
modelConfig,
|
modelConfig,
|
||||||
appId,
|
appId,
|
||||||
inputs,
|
inputs,
|
||||||
visionConfig,
|
|
||||||
collectionList,
|
collectionList,
|
||||||
} = useDebugConfigurationContext()
|
} = useDebugConfigurationContext()
|
||||||
const { textGenerationModelList } = useProviderContext()
|
const { textGenerationModelList } = useProviderContext()
|
||||||
@ -99,7 +98,7 @@ const ChatItem: FC<ChatItemProps> = ({
|
|||||||
model_config: configData,
|
model_config: configData,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visionConfig.enabled && files?.length && supportVision)
|
if ((config.file_upload as any).enabled && files?.length && supportVision)
|
||||||
data.files = files
|
data.files = files
|
||||||
|
|
||||||
handleSend(
|
handleSend(
|
||||||
@ -110,7 +109,7 @@ const ChatItem: FC<ChatItemProps> = ({
|
|||||||
onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
|
onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}, [appId, config, handleSend, inputs, modelAndParameter, textGenerationModelList, visionConfig.enabled])
|
}, [appId, config, handleSend, inputs, modelAndParameter, textGenerationModelList])
|
||||||
|
|
||||||
const { eventEmitter } = useEventEmitterContextContext()
|
const { eventEmitter } = useEventEmitterContextContext()
|
||||||
eventEmitter?.useSubscription((v: any) => {
|
eventEmitter?.useSubscription((v: any) => {
|
||||||
|
@ -21,9 +21,10 @@ import { useStore as useAppStore } from '@/app/components/app/store'
|
|||||||
const DebugWithMultipleModel = () => {
|
const DebugWithMultipleModel = () => {
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
visionConfig,
|
isShowVisionConfig,
|
||||||
} = useDebugConfigurationContext()
|
} = useDebugConfigurationContext()
|
||||||
const speech2text = useFeatures(s => s.features.speech2text)
|
const speech2text = useFeatures(s => s.features.speech2text)
|
||||||
|
const file = useFeatures(s => s.features.file)
|
||||||
const {
|
const {
|
||||||
multipleModelConfigs,
|
multipleModelConfigs,
|
||||||
checkCanSend,
|
checkCanSend,
|
||||||
@ -129,10 +130,11 @@ const DebugWithMultipleModel = () => {
|
|||||||
<div className='shrink-0 pb-0 px-6'>
|
<div className='shrink-0 pb-0 px-6'>
|
||||||
<ChatInputArea
|
<ChatInputArea
|
||||||
showFeatureBar
|
showFeatureBar
|
||||||
|
showFileUpload={isShowVisionConfig}
|
||||||
onFeatureBarClick={setShowAppConfigureFeaturesModal}
|
onFeatureBarClick={setShowAppConfigureFeaturesModal}
|
||||||
onSend={handleSend}
|
onSend={handleSend}
|
||||||
speechToTextConfig={speech2text as any}
|
speechToTextConfig={speech2text as any}
|
||||||
visionConfig={visionConfig}
|
visionConfig={file}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -36,7 +36,6 @@ const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
|||||||
completionPromptConfig,
|
completionPromptConfig,
|
||||||
dataSets,
|
dataSets,
|
||||||
datasetConfigs,
|
datasetConfigs,
|
||||||
visionConfig,
|
|
||||||
} = useDebugConfigurationContext()
|
} = useDebugConfigurationContext()
|
||||||
const { textGenerationModelList } = useProviderContext()
|
const { textGenerationModelList } = useProviderContext()
|
||||||
const features = useFeatures(s => s.features)
|
const features = useFeatures(s => s.features)
|
||||||
@ -58,10 +57,8 @@ const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
|||||||
more_like_this: features.moreLikeThis as any,
|
more_like_this: features.moreLikeThis as any,
|
||||||
sensitive_word_avoidance: features.moderation as any,
|
sensitive_word_avoidance: features.moderation as any,
|
||||||
text_to_speech: features.text2speech as any,
|
text_to_speech: features.text2speech as any,
|
||||||
|
file_upload: features.file as any,
|
||||||
opening_statement: introduction,
|
opening_statement: introduction,
|
||||||
file_upload: {
|
|
||||||
image: visionConfig,
|
|
||||||
},
|
|
||||||
speech_to_text: speechToTextConfig,
|
speech_to_text: speechToTextConfig,
|
||||||
suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
|
suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
|
||||||
retriever_resource: citationConfig,
|
retriever_resource: citationConfig,
|
||||||
@ -103,7 +100,7 @@ const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
|||||||
model_config: configData,
|
model_config: configData,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visionConfig.enabled && files && files?.length > 0) {
|
if ((config.file_upload as any).enabled && files && files?.length > 0) {
|
||||||
data.files = files.map((item) => {
|
data.files = files.map((item) => {
|
||||||
if (item.transfer_method === TransferMethod.local_file) {
|
if (item.transfer_method === TransferMethod.local_file) {
|
||||||
return {
|
return {
|
||||||
|
@ -39,9 +39,9 @@ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSi
|
|||||||
modelConfig,
|
modelConfig,
|
||||||
appId,
|
appId,
|
||||||
inputs,
|
inputs,
|
||||||
visionConfig,
|
|
||||||
collectionList,
|
collectionList,
|
||||||
completionParams,
|
completionParams,
|
||||||
|
isShowVisionConfig,
|
||||||
} = useDebugConfigurationContext()
|
} = useDebugConfigurationContext()
|
||||||
const { textGenerationModelList } = useProviderContext()
|
const { textGenerationModelList } = useProviderContext()
|
||||||
const features = useFeatures(s => s.features)
|
const features = useFeatures(s => s.features)
|
||||||
@ -105,7 +105,7 @@ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSi
|
|||||||
model_config: configData,
|
model_config: configData,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visionConfig.enabled && files?.length && supportVision)
|
if ((config.file_upload as any)?.enabled && files?.length && supportVision)
|
||||||
data.files = files
|
data.files = files
|
||||||
|
|
||||||
handleSend(
|
handleSend(
|
||||||
@ -116,7 +116,7 @@ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSi
|
|||||||
onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
|
onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}, [appId, checkCanSend, completionParams, config, handleSend, inputs, modelConfig, textGenerationModelList, visionConfig.enabled])
|
}, [appId, checkCanSend, completionParams, config, handleSend, inputs, modelConfig, textGenerationModelList])
|
||||||
|
|
||||||
const allToolIcons = useMemo(() => {
|
const allToolIcons = useMemo(() => {
|
||||||
const icons: Record<string, any> = {}
|
const icons: Record<string, any> = {}
|
||||||
@ -142,6 +142,7 @@ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSi
|
|||||||
chatContainerClassName='px-3 pt-6'
|
chatContainerClassName='px-3 pt-6'
|
||||||
chatFooterClassName='px-3 pt-10 pb-0'
|
chatFooterClassName='px-3 pt-10 pb-0'
|
||||||
showFeatureBar
|
showFeatureBar
|
||||||
|
showFileUpload={isShowVisionConfig}
|
||||||
onFeatureBarClick={setShowAppConfigureFeaturesModal}
|
onFeatureBarClick={setShowAppConfigureFeaturesModal}
|
||||||
suggestedQuestions={suggestedQuestions}
|
suggestedQuestions={suggestedQuestions}
|
||||||
onSend={doSend}
|
onSend={doSend}
|
||||||
|
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { setAutoFreeze } from 'immer'
|
import produce, { setAutoFreeze } from 'immer'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import {
|
import {
|
||||||
RiAddLine,
|
RiAddLine,
|
||||||
@ -34,7 +34,7 @@ import Button from '@/app/components/base/button'
|
|||||||
import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
|
import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||||
import TooltipPlus from '@/app/components/base/tooltip'
|
import TooltipPlus from '@/app/components/base/tooltip'
|
||||||
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
|
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
|
||||||
import type { ModelConfig as BackendModelConfig, VisionFile } from '@/types/app'
|
import type { ModelConfig as BackendModelConfig, VisionFile, VisionSettings } from '@/types/app'
|
||||||
import { promptVariablesToUserInputsForm } from '@/utils/model-config'
|
import { promptVariablesToUserInputsForm } from '@/utils/model-config'
|
||||||
import TextGeneration from '@/app/components/app/text-generate/item'
|
import TextGeneration from '@/app/components/app/text-generate/item'
|
||||||
import { IS_CE_EDITION } from '@/config'
|
import { IS_CE_EDITION } from '@/config'
|
||||||
@ -48,7 +48,7 @@ import { useProviderContext } from '@/context/provider-context'
|
|||||||
import AgentLogModal from '@/app/components/base/agent-log-modal'
|
import AgentLogModal from '@/app/components/base/agent-log-modal'
|
||||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
type IDebug = {
|
type IDebug = {
|
||||||
isAPIKeySet: boolean
|
isAPIKeySet: boolean
|
||||||
@ -84,8 +84,6 @@ const Debug: FC<IDebug> = ({
|
|||||||
speechToTextConfig,
|
speechToTextConfig,
|
||||||
textToSpeechConfig,
|
textToSpeechConfig,
|
||||||
citationConfig,
|
citationConfig,
|
||||||
// moderationConfig,
|
|
||||||
// moreLikeThisConfig,
|
|
||||||
formattingChanged,
|
formattingChanged,
|
||||||
setFormattingChanged,
|
setFormattingChanged,
|
||||||
dataSets,
|
dataSets,
|
||||||
@ -93,8 +91,6 @@ const Debug: FC<IDebug> = ({
|
|||||||
completionParams,
|
completionParams,
|
||||||
hasSetContextVar,
|
hasSetContextVar,
|
||||||
datasetConfigs,
|
datasetConfigs,
|
||||||
visionConfig,
|
|
||||||
setVisionConfig,
|
|
||||||
} = useContext(ConfigContext)
|
} = useContext(ConfigContext)
|
||||||
const { eventEmitter } = useEventEmitterContextContext()
|
const { eventEmitter } = useEventEmitterContextContext()
|
||||||
const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
|
const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
|
||||||
@ -203,6 +199,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
const [completionRes, setCompletionRes] = useState('')
|
const [completionRes, setCompletionRes] = useState('')
|
||||||
const [messageId, setMessageId] = useState<string | null>(null)
|
const [messageId, setMessageId] = useState<string | null>(null)
|
||||||
const features = useFeatures(s => s.features)
|
const features = useFeatures(s => s.features)
|
||||||
|
const featuresStore = useFeaturesStore()
|
||||||
|
|
||||||
const sendTextCompletion = async () => {
|
const sendTextCompletion = async () => {
|
||||||
if (isResponding) {
|
if (isResponding) {
|
||||||
@ -252,10 +249,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
more_like_this: features.moreLikeThis as any,
|
more_like_this: features.moreLikeThis as any,
|
||||||
sensitive_word_avoidance: features.moderation as any,
|
sensitive_word_avoidance: features.moderation as any,
|
||||||
text_to_speech: features.text2speech as any,
|
text_to_speech: features.text2speech as any,
|
||||||
// ##TODO## file_upload
|
file_upload: features.file as any,
|
||||||
file_upload: {
|
|
||||||
image: visionConfig,
|
|
||||||
},
|
|
||||||
opening_statement: introduction,
|
opening_statement: introduction,
|
||||||
suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
|
suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
|
||||||
speech_to_text: speechToTextConfig,
|
speech_to_text: speechToTextConfig,
|
||||||
@ -272,7 +266,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
model_config: postModelConfig,
|
model_config: postModelConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visionConfig.enabled && completionFiles && completionFiles?.length > 0) {
|
if ((features.file as any).enabled && completionFiles && completionFiles?.length > 0) {
|
||||||
data.files = completionFiles.map((item) => {
|
data.files = completionFiles.map((item) => {
|
||||||
if (item.transfer_method === TransferMethod.local_file) {
|
if (item.transfer_method === TransferMethod.local_file) {
|
||||||
return {
|
return {
|
||||||
@ -348,7 +342,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleVisionConfigInMultipleModel = () => {
|
const handleVisionConfigInMultipleModel = useCallback(() => {
|
||||||
if (debugWithMultipleModel && mode) {
|
if (debugWithMultipleModel && mode) {
|
||||||
const supportedVision = multipleModelConfigs.some((modelConfig) => {
|
const supportedVision = multipleModelConfigs.some((modelConfig) => {
|
||||||
const currentProvider = textGenerationModelList.find(modelItem => modelItem.provider === modelConfig.provider)
|
const currentProvider = textGenerationModelList.find(modelItem => modelItem.provider === modelConfig.provider)
|
||||||
@ -356,25 +350,24 @@ const Debug: FC<IDebug> = ({
|
|||||||
|
|
||||||
return currentModel?.features?.includes(ModelFeatureEnum.vision)
|
return currentModel?.features?.includes(ModelFeatureEnum.vision)
|
||||||
})
|
})
|
||||||
|
const {
|
||||||
|
features,
|
||||||
|
setFeatures,
|
||||||
|
} = featuresStore!.getState()
|
||||||
|
|
||||||
if (supportedVision) {
|
const newFeatures = produce(features, (draft) => {
|
||||||
setVisionConfig({
|
draft.file = {
|
||||||
...visionConfig,
|
...draft.file,
|
||||||
enabled: true,
|
enabled: supportedVision,
|
||||||
}, true)
|
}
|
||||||
}
|
})
|
||||||
else {
|
setFeatures(newFeatures)
|
||||||
setVisionConfig({
|
|
||||||
...visionConfig,
|
|
||||||
enabled: false,
|
|
||||||
}, true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}, [debugWithMultipleModel, featuresStore, mode, multipleModelConfigs, textGenerationModelList])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleVisionConfigInMultipleModel()
|
handleVisionConfigInMultipleModel()
|
||||||
}, [multipleModelConfigs, mode])
|
}, [multipleModelConfigs, mode, handleVisionConfigInMultipleModel])
|
||||||
|
|
||||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
|
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
|
||||||
currentLogItem: state.currentLogItem,
|
currentLogItem: state.currentLogItem,
|
||||||
@ -455,7 +448,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
onSend={handleSendTextCompletion}
|
onSend={handleSendTextCompletion}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
visionConfig={{
|
visionConfig={{
|
||||||
...visionConfig,
|
...features.file! as VisionSettings,
|
||||||
image_file_size_limit: fileUploadConfigResponse?.image_file_size_limit,
|
image_file_size_limit: fileUploadConfigResponse?.image_file_size_limit,
|
||||||
}}
|
}}
|
||||||
onVisionFilesChange={setCompletionFiles}
|
onVisionFilesChange={setCompletionFiles}
|
||||||
|
@ -598,7 +598,6 @@ const Configuration: FC = () => {
|
|||||||
completionParams: model.completion_params,
|
completionParams: model.completion_params,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ##TODO## new vision config
|
|
||||||
if (modelConfig.file_upload)
|
if (modelConfig.file_upload)
|
||||||
handleSetVisionConfig(modelConfig.file_upload.image, true)
|
handleSetVisionConfig(modelConfig.file_upload.image, true)
|
||||||
|
|
||||||
@ -693,10 +692,7 @@ const Configuration: FC = () => {
|
|||||||
sensitive_word_avoidance: features?.moderation as any,
|
sensitive_word_avoidance: features?.moderation as any,
|
||||||
speech_to_text: features?.speech2text as any,
|
speech_to_text: features?.speech2text as any,
|
||||||
text_to_speech: features?.text2speech as any,
|
text_to_speech: features?.text2speech as any,
|
||||||
// ##TODO## file_upload
|
file_upload: features?.file as any,
|
||||||
file_upload: {
|
|
||||||
image: visionConfig,
|
|
||||||
},
|
|
||||||
suggested_questions_after_answer: features?.suggested as any,
|
suggested_questions_after_answer: features?.suggested as any,
|
||||||
retriever_resource: features?.citation as any,
|
retriever_resource: features?.citation as any,
|
||||||
agent_mode: {
|
agent_mode: {
|
||||||
@ -983,6 +979,7 @@ const Configuration: FC = () => {
|
|||||||
<NewFeaturePanel
|
<NewFeaturePanel
|
||||||
show
|
show
|
||||||
inWorkflow={false}
|
inWorkflow={false}
|
||||||
|
showFileUpload={isShowVisionConfig}
|
||||||
isChatMode={mode !== 'completion'}
|
isChatMode={mode !== 'completion'}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onChange={handleFeaturesChange}
|
onChange={handleFeaturesChange}
|
||||||
|
@ -24,6 +24,7 @@ import type { FileUpload } from '@/app/components/base/features/types'
|
|||||||
|
|
||||||
type ChatInputAreaProps = {
|
type ChatInputAreaProps = {
|
||||||
showFeatureBar?: boolean
|
showFeatureBar?: boolean
|
||||||
|
showFileUpload?: boolean
|
||||||
featureBarDisabled?: boolean
|
featureBarDisabled?: boolean
|
||||||
onFeatureBarClick?: (state: boolean) => void
|
onFeatureBarClick?: (state: boolean) => void
|
||||||
visionConfig?: FileUpload
|
visionConfig?: FileUpload
|
||||||
@ -33,6 +34,7 @@ type ChatInputAreaProps = {
|
|||||||
}
|
}
|
||||||
const ChatInputArea = ({
|
const ChatInputArea = ({
|
||||||
showFeatureBar,
|
showFeatureBar,
|
||||||
|
showFileUpload,
|
||||||
featureBarDisabled,
|
featureBarDisabled,
|
||||||
onFeatureBarClick,
|
onFeatureBarClick,
|
||||||
visionConfig,
|
visionConfig,
|
||||||
@ -155,7 +157,7 @@ const ChatInputArea = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{showFeatureBar && <FeatureBar disabled={featureBarDisabled} onFeatureBarClick={onFeatureBarClick} />}
|
{showFeatureBar && <FeatureBar showFileUpload={showFileUpload} disabled={featureBarDisabled} onFeatureBarClick={onFeatureBarClick} />}
|
||||||
</>
|
</>
|
||||||
</FileContextProvider>
|
</FileContextProvider>
|
||||||
)
|
)
|
||||||
|
@ -62,6 +62,7 @@ export type ChatProps = {
|
|||||||
hideLogModal?: boolean
|
hideLogModal?: boolean
|
||||||
themeBuilder?: ThemeBuilder
|
themeBuilder?: ThemeBuilder
|
||||||
showFeatureBar?: boolean
|
showFeatureBar?: boolean
|
||||||
|
showFileUpload?: boolean
|
||||||
onFeatureBarClick?: (state: boolean) => void
|
onFeatureBarClick?: (state: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +93,7 @@ const Chat: FC<ChatProps> = ({
|
|||||||
hideLogModal,
|
hideLogModal,
|
||||||
themeBuilder,
|
themeBuilder,
|
||||||
showFeatureBar,
|
showFeatureBar,
|
||||||
|
showFileUpload,
|
||||||
onFeatureBarClick,
|
onFeatureBarClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -267,6 +269,7 @@ const Chat: FC<ChatProps> = ({
|
|||||||
!noChatInput && (
|
!noChatInput && (
|
||||||
<ChatInputArea
|
<ChatInputArea
|
||||||
showFeatureBar={showFeatureBar}
|
showFeatureBar={showFeatureBar}
|
||||||
|
showFileUpload={showFileUpload}
|
||||||
featureBarDisabled={isResponding}
|
featureBarDisabled={isResponding}
|
||||||
onFeatureBarClick={onFeatureBarClick}
|
onFeatureBarClick={onFeatureBarClick}
|
||||||
visionConfig={config?.file_upload}
|
visionConfig={config?.file_upload}
|
||||||
|
@ -1,23 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useContext } from 'use-context-selector'
|
|
||||||
import { usePathname, useRouter } from 'next/navigation'
|
|
||||||
import ConfigParamModal from './config-param-modal'
|
|
||||||
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
|
||||||
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { LinkExternal02, Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
|
||||||
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
|
|
||||||
import { fetchAnnotationConfig, updateAnnotationScore } from '@/service/annotation'
|
|
||||||
import type { AnnotationReplyConfig as AnnotationReplyConfigType } from '@/models/debug'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
onEmbeddingChange: (embeddingModel: EmbeddingModelConfig) => void
|
|
||||||
onScoreChange: (score: number, embeddingModel?: EmbeddingModelConfig) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Item: FC<{ title: string; tooltip: string; children: JSX.Element }> = ({
|
export const Item: FC<{ title: string; tooltip: string; children: JSX.Element }> = ({
|
||||||
title,
|
title,
|
||||||
@ -38,87 +22,3 @@ export const Item: FC<{ title: string; tooltip: string; children: JSX.Element }>
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnnotationReplyConfig: FC<Props> = ({
|
|
||||||
onEmbeddingChange,
|
|
||||||
onScoreChange,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const router = useRouter()
|
|
||||||
const pathname = usePathname()
|
|
||||||
const matched = pathname.match(/\/app\/([^/]+)/)
|
|
||||||
const appId = (matched?.length && matched[1]) ? matched[1] : ''
|
|
||||||
const {
|
|
||||||
annotationConfig,
|
|
||||||
} = useContext(ConfigContext)
|
|
||||||
|
|
||||||
const [isShowEdit, setIsShowEdit] = React.useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Panel
|
|
||||||
className="mt-4"
|
|
||||||
headerIcon={
|
|
||||||
<MessageFast className='w-4 h-4 text-[#444CE7]' />
|
|
||||||
}
|
|
||||||
title={t('appDebug.feature.annotation.title')}
|
|
||||||
headerRight={
|
|
||||||
<div className='flex items-center'>
|
|
||||||
<div
|
|
||||||
className='flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200'
|
|
||||||
onClick={() => { setIsShowEdit(true) }}
|
|
||||||
>
|
|
||||||
<Settings04 className="w-[14px] h-[14px]" />
|
|
||||||
<div className='text-xs font-medium'>
|
|
||||||
|
|
||||||
{t('common.operation.params')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className='ml-1 flex items-center h-7 px-3 space-x-1 leading-[18px] text-xs font-medium text-gray-700 rounded-md cursor-pointer hover:bg-gray-200'
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/app/${appId}/annotations`)
|
|
||||||
}}>
|
|
||||||
<div>{t('appDebug.feature.annotation.cacheManagement')}</div>
|
|
||||||
<LinkExternal02 className='w-3.5 h-3.5' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
noBodySpacing
|
|
||||||
/>
|
|
||||||
{isShowEdit && (
|
|
||||||
<ConfigParamModal
|
|
||||||
appId={appId}
|
|
||||||
isShow
|
|
||||||
onHide={() => {
|
|
||||||
setIsShowEdit(false)
|
|
||||||
}}
|
|
||||||
onSave={async (embeddingModel, score) => {
|
|
||||||
const annotationConfig = await fetchAnnotationConfig(appId) as AnnotationReplyConfigType
|
|
||||||
let isEmbeddingModelChanged = false
|
|
||||||
if (
|
|
||||||
embeddingModel.embedding_model_name !== annotationConfig.embedding_model.embedding_model_name
|
|
||||||
&& embeddingModel.embedding_provider_name !== annotationConfig.embedding_model.embedding_provider_name
|
|
||||||
) {
|
|
||||||
await onEmbeddingChange(embeddingModel)
|
|
||||||
isEmbeddingModelChanged = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score !== annotationConfig.score_threshold) {
|
|
||||||
await updateAnnotationScore(appId, annotationConfig.id, score)
|
|
||||||
if (isEmbeddingModelChanged)
|
|
||||||
onScoreChange(score, embeddingModel)
|
|
||||||
|
|
||||||
else
|
|
||||||
onScoreChange(score)
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsShowEdit(false)
|
|
||||||
}}
|
|
||||||
annotationConfig={annotationConfig}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(AnnotationReplyConfig)
|
|
||||||
|
@ -10,12 +10,14 @@ import cn from '@/utils/classnames'
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isChatMode?: boolean
|
isChatMode?: boolean
|
||||||
|
showFileUpload?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
onFeatureBarClick?: (state: boolean) => void
|
onFeatureBarClick?: (state: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const FeatureBar = ({
|
const FeatureBar = ({
|
||||||
isChatMode = true,
|
isChatMode = true,
|
||||||
|
showFileUpload = true,
|
||||||
disabled,
|
disabled,
|
||||||
onFeatureBarClick,
|
onFeatureBarClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
@ -28,9 +30,10 @@ const FeatureBar = ({
|
|||||||
const data = {
|
const data = {
|
||||||
...features,
|
...features,
|
||||||
citation: { enabled: isChatMode ? features.citation?.enabled : false },
|
citation: { enabled: isChatMode ? features.citation?.enabled : false },
|
||||||
|
file: showFileUpload ? features.file! : { enabled: false },
|
||||||
}
|
}
|
||||||
return !Object.values(data).some(f => f.enabled)
|
return !Object.values(data).some(f => f.enabled)
|
||||||
}, [features, isChatMode])
|
}, [features, isChatMode, showFileUpload])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='-translate-y-2 m-1 mt-0 px-2.5 py-2 pt-4 bg-util-colors-indigo-indigo-50 rounded-b-[10px] border-l border-b border-r border-components-panel-border-subtle'>
|
<div className='-translate-y-2 m-1 mt-0 px-2.5 py-2 pt-4 bg-util-colors-indigo-indigo-50 rounded-b-[10px] border-l border-b border-r border-components-panel-border-subtle'>
|
||||||
@ -91,7 +94,7 @@ const FeatureBar = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</VoiceSettings>
|
</VoiceSettings>
|
||||||
)}
|
)}
|
||||||
{!!features.file?.enabled && (
|
{showFileUpload && !!features.file?.enabled && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('appDebug.feature.fileUpload.title')}
|
popupContent={t('appDebug.feature.fileUpload.title')}
|
||||||
>
|
>
|
||||||
|
@ -24,6 +24,7 @@ type Props = {
|
|||||||
onChange?: OnFeaturesChange
|
onChange?: OnFeaturesChange
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
inWorkflow?: boolean
|
inWorkflow?: boolean
|
||||||
|
showFileUpload?: boolean
|
||||||
promptVariables?: PromptVariable[]
|
promptVariables?: PromptVariable[]
|
||||||
onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
|
onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
|
||||||
}
|
}
|
||||||
@ -35,6 +36,7 @@ const NewFeaturePanel = ({
|
|||||||
onChange,
|
onChange,
|
||||||
onClose,
|
onClose,
|
||||||
inWorkflow = true,
|
inWorkflow = true,
|
||||||
|
showFileUpload = true,
|
||||||
promptVariables,
|
promptVariables,
|
||||||
onAutoAddPromptVariable,
|
onAutoAddPromptVariable,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
@ -77,7 +79,7 @@ const NewFeaturePanel = ({
|
|||||||
{text2speechDefaultModel && (
|
{text2speechDefaultModel && (
|
||||||
<TextToSpeech disabled={disabled} onChange={onChange} />
|
<TextToSpeech disabled={disabled} onChange={onChange} />
|
||||||
)}
|
)}
|
||||||
<FileUpload disabled={disabled} onChange={onChange} />
|
{showFileUpload && <FileUpload disabled={disabled} onChange={onChange} />}
|
||||||
{isChatMode && (
|
{isChatMode && (
|
||||||
<FollowUp disabled={disabled} onChange={onChange} />
|
<FollowUp disabled={disabled} onChange={onChange} />
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user