feat: select file types

This commit is contained in:
Joel 2024-08-02 18:17:04 +08:00
parent a05d16375e
commit 0be99ad01c
7 changed files with 212 additions and 4 deletions

View File

@ -11,10 +11,11 @@ import Field from './field'
import Toast from '@/app/components/base/toast'
import { checkKeys, getNewVarInWorkflow } from '@/utils/var'
import ConfigContext from '@/context/debug-configuration'
import type { InputVar, MoreInfo } from '@/app/components/workflow/types'
import type { InputVar, MoreInfo, UploadFileSetting } from '@/app/components/workflow/types'
import Modal from '@/app/components/base/modal'
import Switch from '@/app/components/base/switch'
import { ChangeType, InputVarType } from '@/app/components/workflow/types'
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
const TEXT_MAX_LENGTH = 256
@ -98,7 +99,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
if (isStringInput || type === InputVarType.number) {
onConfirm(tempPayload, moreInfo)
}
else {
else if (type === InputVarType.select) {
if (options?.length === 0) {
Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.atLeastOneOption') })
return
@ -118,6 +119,9 @@ const ConfigModal: FC<IConfigModalProps> = ({
}
onConfirm(tempPayload, moreInfo)
}
else {
onConfirm(tempPayload, moreInfo)
}
}
return (
@ -174,6 +178,14 @@ const ConfigModal: FC<IConfigModalProps> = ({
</Field>
)}
{[InputVarType.singleFile, InputVarType.multiFiles].includes(type) && (
<FileUploadSetting
payload={tempPayload as UploadFileSetting}
onChange={(p: UploadFileSetting) => setTempPayload(p as InputVar)}
isMultiple={type === InputVarType.multiFiles}
/>
)}
<Field title={t('appDebug.variableConig.required')}>
<Switch defaultValue={tempPayload.required} onChange={handlePayloadChange('required')} />
</Field>

View File

@ -1,4 +1,4 @@
import type { ValueSelector } from '../../workflow/types'
import { SupportUploadFileTypes, type ValueSelector } from '../../workflow/types'
export const CONTEXT_PLACEHOLDER_TEXT = '{{#context#}}'
export const HISTORY_PLACEHOLDER_TEXT = '{{#histories#}}'
@ -49,3 +49,10 @@ export const getInputVars = (text: string): ValueSelector[] => {
}
return []
}
export const FILE_EXTS = {
[SupportUploadFileTypes.image]: ['JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG'],
[SupportUploadFileTypes.document]: ['TXT', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB'],
[SupportUploadFileTypes.audio]: ['MP3', 'M4A', 'WAV', 'WEBM', 'AMR'],
[SupportUploadFileTypes.video]: ['MP4', 'MOV', 'MPEG', 'MPGA'],
}

View File

@ -0,0 +1,48 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import type { SupportUploadFileTypes } from '../../../types'
import cn from '@/utils/classnames'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
type Props = {
type: SupportUploadFileTypes.image | SupportUploadFileTypes.document | SupportUploadFileTypes.audio | SupportUploadFileTypes.video
selected: boolean
onSelect: (type: SupportUploadFileTypes) => void
}
const FileTypeItem: FC<Props> = ({
type,
selected,
onSelect,
}) => {
const { t } = useTranslation()
const handleOnSelect = useCallback(() => {
if (!selected)
onSelect(type)
}, [selected, onSelect, type])
return (
<div
className={cn(
'py-2 px-3 rounded-lg bg-components-option-card-option-bg border border-components-option-card-option-border',
selected && 'border-[1.5px] bg-components-option-card-option-selected-bg border-components-option-card-option-selected-border',
!selected && 'cursor-pointer hover:bg-components-option-card-option-bg-hover hover:border-components-option-card-option-border-hover',
)}
onClick={handleOnSelect}
>
<div className='flex items-center'>
{/* TODO: Wait File type icon */}
<span className='shrink-0 w-4 h-4 bg-[#00B2EA]'></span>
<div className='ml-2'>
<div className='text-text-primary system-sm-medium'>{t(`appDebug.variableConig.file.${type}.name`)}</div>
<div className='mt-1 text-text-tertiary system-2xs-regular-uppercase'>{FILE_EXTS[type].join(', ')}</div>
</div>
</div>
</div>
)
}
export default React.memo(FileTypeItem)

View File

@ -0,0 +1,98 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import produce from 'immer'
import type { UploadFileSetting } from '../../../types'
import { SupportUploadFileTypes } from '../../../types'
import OptionCard from './option-card'
import FileTypeItem from './file-type-item'
import Field from '@/app/components/app/configuration/config-var/config-modal/field'
import { TransferMethod } from '@/types/app'
type Props = {
payload: UploadFileSetting
isMultiple: boolean
onChange: (payload: UploadFileSetting) => void
}
const FileUploadSetting: FC<Props> = ({
payload,
isMultiple,
onChange,
}) => {
const {
uploadMethod,
maxUploadNumLimit,
supportFileTypes,
customFileTypes,
} = payload
const handleSupportFileTypeChange = useCallback((type: SupportUploadFileTypes) => {
const newPayload = produce(payload, (draft) => {
draft.supportFileTypes = type
})
onChange(newPayload)
}, [onChange, payload])
const handleUploadMethodChange = useCallback((method: TransferMethod) => {
return () => {
const newPayload = produce(payload, (draft) => {
draft.uploadMethod = method
})
onChange(newPayload)
}
}, [onChange, payload])
return (
<div>
<Field
title='SupportFile Types'
>
<div className='space-y-1'>
{
[SupportUploadFileTypes.image, SupportUploadFileTypes.document, SupportUploadFileTypes.audio, SupportUploadFileTypes.video].map((type: SupportUploadFileTypes) => (
<FileTypeItem
key={type}
type={type as SupportUploadFileTypes.image | SupportUploadFileTypes.document | SupportUploadFileTypes.audio | SupportUploadFileTypes.video}
selected={supportFileTypes === type}
onSelect={handleSupportFileTypeChange}
/>
))
}
</div>
</Field>
<Field
title='Upload File Types'
>
<div className='grid grid-cols-3 gap-2'>
<OptionCard
title='Local Upload'
selected={uploadMethod === TransferMethod.local_file}
onSelect={handleUploadMethodChange(TransferMethod.local_file)}
/>
<OptionCard
title="URL"
selected={uploadMethod === TransferMethod.remote_url}
onSelect={handleUploadMethodChange(TransferMethod.remote_url)}
/>
<OptionCard
title="Both"
selected={uploadMethod === TransferMethod.all}
onSelect={handleUploadMethodChange(TransferMethod.all)}
/>
</div>
</Field>
{isMultiple && (
<Field
title='Max number of uploads'
>
<div>
<span>Max number of uploads</span>
</div>
</Field>
)}
</div>
)
}
export default React.memo(FileUploadSetting)

View File

@ -144,7 +144,7 @@ export type InputVar = {
hint?: string
options?: string[]
value_selector?: ValueSelector
}
} & Partial<UploadFileSetting>
export type ModelConfig = {
provider: string
@ -329,3 +329,18 @@ export type MoreInfo = {
export type ToolWithProvider = Collection & {
tools: Tool[]
}
export enum SupportUploadFileTypes {
image = 'image',
document = 'document',
audio = 'audio',
video = 'video',
custom = 'custom',
}
export type UploadFileSetting = {
uploadMethod: TransferMethod
maxUploadNumLimit?: number // multiple files upload limit
supportFileTypes: SupportUploadFileTypes
customFileTypes?: string[]
}

View File

@ -324,6 +324,20 @@ const translation = {
'inputPlaceholder': 'Please input',
'content': 'Content',
'required': 'Required',
'file': {
image: {
name: 'Image',
},
audio: {
name: 'Audio',
},
document: {
name: 'Document',
},
video: {
name: 'Video',
},
},
'errorMsg': {
varNameRequired: 'Variable name is required',
labelNameRequired: 'Label name is required',

View File

@ -320,6 +320,20 @@ const translation = {
'inputPlaceholder': '请输入',
'labelName': '显示名称',
'required': '必填',
'file': {
image: {
name: '图片',
},
audio: {
name: '音频',
},
document: {
name: '文档',
},
video: {
name: '视频',
},
},
'content': '内容',
'errorMsg': {
varNameRequired: '变量名称必填',