Commit eca9d861 authored by StyleZhang's avatar StyleZhang

fix: data structure

parent 89c59e39
export default {
type: 'provider',
title: {
'en-US': 'Anthropic',
'en': 'Anthropic',
'zh-Hans': 'Anthropic',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en-US': 'Get your API key from Anthropic',
'en': 'Get your API key from Anthropic',
'zh-Hans': '从 Anthropic 获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'text',
key: 'anthropic_api_key',
is_required: true,
toggle_enabled: false,
is_obfuscated: true,
key: 'apiKey',
required: true,
label: {
'en-US': 'API Key',
'en': 'API Key',
'zh-Hans': 'API Key',
},
place_holder: {
'en-US': 'Enter your API key here',
placeholder: {
'en': 'Enter your API key here',
'zh-Hans': '在此输入您的 API Key',
},
},
{
visible: () => true,
type: 'text',
key: 'anthropic_api_url',
is_required: false,
toggle_enabled: true,
key: 'customApiDomain',
required: true,
switch: true,
label: {
'en-US': 'Custom API Domain',
'en': 'Custom API Domain',
'zh-Hans': '自定义 API 域名',
},
place_holder: {
'en-US': 'Enter your API domain, eg: https://example.com/xxx',
placeholder: {
'en': 'Enter your API domain, eg: https://example.com/xxx',
'zh-Hans': '在此输入您的 API 域名,如:https://example.com/xxx',
},
help: {
'en-US': 'Configurable custom Anthropic API server url.',
'en': 'Configurable custom Anthropic API server url.',
'zh-Hans': '可配置自定义 Anthropic API 服务器地址。',
},
},
......
export default {
hit: {
'en': '🐑 Llama 2 Supported',
'zh-Hans': '🐑 Llama 2 支持',
},
title: {
'en': 'Azure OpenAI',
'zh-Hans': 'Azure OpenAI',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'Get your API key from Azure',
'zh-Hans': '从 Azure 获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'radio',
key: 'modelType',
required: true,
label: {
'en': 'Model Type',
'zh-Hans': '模型类型',
},
options: [
{
key: '1',
label: {
'en': 'Text Generation',
'zh-Hans': '文本生成',
},
},
{
key: '2',
label: {
'en': 'Embeddings',
'zh-Hans': 'Embeddings',
},
},
{
key: '3',
label: {
'en': 'Speech To Text',
'zh-Hans': '语音转文字',
},
},
],
},
{
visible: () => true,
type: 'text',
key: 'apiToken',
required: true,
obfuscated: true,
label: {
'en': 'API Endpoint URL',
'zh-Hans': 'API 域名',
},
placeholder: {
'en': 'Enter your API Endpoint, eg: https://example.com/xxx',
'zh-Hans': '在此输入您的 API 域名,如:https://example.com/xxx',
},
},
{
visible: () => true,
type: 'text',
key: 'apiKey',
required: true,
obfuscated: true,
label: {
'en': 'API Key',
'zh-Hans': 'API Key',
},
placeholder: {
'en': 'Enter your API key here',
'zh-Hans': 'Enter your API key here',
},
},
{
visible: () => true,
type: 'text',
key: 'modelName',
required: true,
label: {
'en': 'Deployment Name',
'zh-Hans': '部署名称',
},
placeholder: {
'en': 'Enter your Deployment Name here',
'zh-Hans': '在此输入您的部署名称',
},
},
],
}
export default {
title: {
'en': 'ChatGLM',
'zh-Hans': 'ChatGLM',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'How to deploy ChatGLM',
'zh-Hans': '如何部署 ChatGLM',
},
},
fields: [
{
visible: () => true,
type: 'text',
key: 'customApiDomain',
required: true,
label: {
'en': 'Custom API Domain',
'zh-Hans': '自定义 API 域名',
},
placeholder: {
'en': 'Enter your API domain, eg: https://example.com/xxx',
'zh-Hans': '在此输入您的 API 域名,如:https://example.com/xxx',
},
},
],
}
import type { FormValue } from '../declarations'
export default {
hit: {
'en': '🐑 Llama 2 Supported',
'zh-Hans': '🐑 Llama 2 支持',
},
title: {
'en': 'Hugging Face Hub',
'zh-Hans': 'Hugging Face Hub',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'Get your API key from Hugging Face Hub',
'zh-Hans': '从 Hugging Face Hub 获取 API Key',
},
},
defaultValue: {
modelType: '1',
endpointType: '1',
},
fields: [
{
visible: () => true,
type: 'radio',
key: 'modelType',
required: true,
label: {
'en': 'Model Type',
'zh-Hans': '模型类型',
},
options: [
{
key: '1',
label: {
'en': 'Text Generation',
'zh-Hans': '文本生成',
},
},
{
key: '2',
label: {
'en': 'Embeddings',
'zh-Hans': 'Embeddings',
},
},
{
key: '3',
label: {
'en': 'Speech To Text',
'zh-Hans': '语音转文字',
},
},
],
},
{
visible: () => true,
type: 'radio',
key: 'endpointType',
required: true,
label: {
'en': 'Endpoint Type',
'zh-Hans': '端点类型',
},
options: [
{
key: '1',
label: {
'en': 'Hosted Inference API',
'zh-Hans': '托管推理 API',
},
},
{
key: '2',
label: {
'en': 'Inference Endpoints',
'zh-Hans': '自部署推理端点',
},
},
],
},
{
visible: () => true,
type: 'text',
key: 'apiToken',
required: true,
obfuscated: true,
label: {
'en': 'API Token',
'zh-Hans': 'API Token',
},
placeholder: {
'en': 'Enter your Hugging Face Hub API Token here',
'zh-Hans': '在此输入您的 Hugging Face Hub API Token',
},
},
{
visible: () => true,
type: 'text',
key: 'modelName',
required: true,
label: {
'en': 'Model Name',
'zh-Hans': '模型名称',
},
placeholder: {
'en': 'Enter your Model Name here',
'zh-Hans': '在此输入您的模型名称',
},
},
{
visible: (value?: FormValue) => value?.modelType === '1' && value.endpointType === '2',
type: 'text',
key: 'endpointUrl',
label: {
'en': 'Endpoint URL',
'zh-Hans': '端点 URL',
},
placeholder: {
'en': 'Enter your Endpoint URL here',
'zh-Hans': '在此输入您的端点 URL',
},
},
{
visible: (value?: FormValue) => value?.modelType === '1',
type: 'radio',
key: 'taskType',
required: true,
label: {
'en': 'Task Type',
'zh-Hans': '任务类型',
},
options: [
{
key: '1',
label: {
'en': 'Text Generation',
'zh-Hans': '文本生成',
},
},
{
key: '2',
label: {
'en': 'Text to Text Generation',
'zh-Hans': '文本转文本生成',
},
},
],
},
],
}
import anthropicConfig from './anthropic.config'
import openaiConfig from './openai.config'
import huggingfaceConfig from './huggingface.config'
import minimaxConfig from './minimax.config'
import tongyiConfig from './tongyi.config'
import chatglmConfig from './chatglm.config'
import replicateConfig from './replicate.config'
import azure_openaiConfig from './azure_openai.config'
export default {
anthropic: anthropicConfig,
openai: openaiConfig,
huggingface_hub: huggingfaceConfig,
minimax: minimaxConfig,
tongyi: tongyiConfig,
chatglm: chatglmConfig,
replicate: replicateConfig,
azure_openai: azure_openaiConfig,
}
export default {
title: {
'en': 'MiniMax',
'zh-Hans': 'MiniMax',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'Get your API key from MiniMax',
'zh-Hans': '从 MiniMax 获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'text',
key: 'apiKey',
required: true,
obfuscated: true,
label: {
'en': 'API Key',
'zh-Hans': 'API Key',
},
placeholder: {
'en': 'Enter your API key here',
'zh-Hans': '在此输入您的 API Key',
},
},
{
visible: () => true,
type: 'text',
key: 'groupId',
required: true,
label: {
'en': 'Group ID',
'zh-Hans': 'Group ID',
},
placeholder: {
'en': 'Enter your Group ID here',
'zh-Hans': '在此输入您的 Group ID',
},
},
],
}
export default {
type: 'provider',
title: {
'en-US': 'OpenAI',
'en': 'OpenAI',
'zh-Hans': 'OpenAI',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en-US': 'Get your API key from OpenAI',
'en': 'Get your API key from OpenAI',
'zh-Hans': '从 OpenAI 获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'text',
key: 'openai_api_key',
is_required: true,
toggle_enabled: false,
is_obfuscated: true,
key: 'apiKey',
required: true,
obfuscated: true,
label: {
'en-US': 'API Key',
'en': 'API Key',
'zh-Hans': 'API Key',
},
place_holder: {
'en-US': 'Enter your API key here',
placeholder: {
'en': 'Enter your API key here',
'zh-Hans': '在此输入您的 API Key',
},
},
{
visible: () => true,
type: 'text',
key: 'openai_api_base',
is_required: false,
toggle_enabled: true,
key: 'customApiDomain',
required: false,
switch: true,
label: {
'en-US': 'Custom API Domain',
'en': 'Custom API Domain',
'zh-Hans': '自定义 API 域名',
},
place_holder: {
'en-US': 'Enter your API domain, eg: https://example.com/xxx',
placeholder: {
'en': 'Enter your API domain, eg: https://example.com/xxx',
'zh-Hans': '在此输入您的 API 域名,如:https://example.com/xxx',
},
help: {
'en-US': 'You can configure your server compatible with the OpenAI API specification, or proxy mirror address',
'en': 'You can configure your server compatible with the OpenAI API specification, or proxy mirror address',
'zh-Hans': '可配置您的兼容 OpenAI API 规范的服务器,或者代理镜像地址',
},
},
{
type: 'text',
key: 'openai_organization',
is_required: false,
toggle_enabled: true,
label: {
'en-US': 'Organization ID',
'zh-Hans': '组织 ID',
},
place_holder: {
'en-US': 'Enter your Organization ID, eg: org-xxxxxxxxxxxxxxxx',
'zh-Hans': '在此输入您的组织 ID,如:org-xxxxxxxxxxxxxxxx',
},
},
],
}
export default {
hit: {
'en': '🐑 Llama 2 Supported',
'zh-Hans': '🐑 Llama 2 支持',
},
title: {
'en': 'Replicate',
'zh-Hans': 'Replicate',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'Get your API key from Replicate',
'zh-Hans': '从 Replicate 获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'radio',
key: 'modelType',
required: true,
label: {
'en': 'Model Type',
'zh-Hans': '模型类型',
},
options: [
{
key: '1',
label: {
'en': 'Text Generation',
'zh-Hans': '文本生成',
},
},
{
key: '2',
label: {
'en': 'Embeddings',
'zh-Hans': 'Embeddings',
},
},
{
key: '3',
label: {
'en': 'Speech To Text',
'zh-Hans': '语音转文字',
},
},
],
},
{
visible: () => true,
type: 'text',
key: 'apiKey',
required: true,
obfuscated: true,
label: {
'en': 'API Key',
'zh-Hans': 'API Key',
},
placeholder: {
'en': 'Enter your Replicate API key here',
'zh-Hans': '在此输入您的 Replicate API Key',
},
},
{
visible: () => true,
type: 'text',
key: 'modelName',
required: true,
label: {
'en': 'Model Name',
'zh-Hans': '模型名称',
},
placeholder: {
'en': 'Enter your Model Name here',
'zh-Hans': '在此输入您的模型名称',
},
},
{
visible: () => true,
type: 'text',
key: 'modelVersion',
label: {
'en': 'Model Version',
'zh-Hans': '模型版本',
},
placeholder: {
'en': 'Enter your Model Version here',
'zh-Hans': '在此输入您的模型版本',
},
},
],
}
export default {
title: {
'en': 'Tongyi',
'zh-Hans': '通义千问',
},
link: {
href: 'https://docs.dify.ai',
label: {
'en': 'Get your API key from AliCloud',
'zh-Hans': '从阿里云获取 API Key',
},
},
fields: [
{
visible: () => true,
type: 'text',
key: 'apiKey',
required: true,
obfuscated: true,
label: {
'en': 'API Key',
'zh-Hans': 'API Key',
},
placeholder: {
'en': 'Enter your API key here',
'zh-Hans': '在此输入您的 API Key',
},
},
],
}
export type ProviderType = 'system' | 'custom'
export type ProviderName = keyof ProviderFixedMap | keyof ProviderConfigurableMap
export type ProviderFixedMap = {
'openai': {
openai_api_key: string
openai_api_base: string
openai_organization: string
}
'anthropic': {
anthropic_api_key: string
anthropic_api_url: string
}
'minimax': {
minimax_group_id: string
minimax_api_key: string
}
'tongyi': {
dashscope_api_key: string
}
'chatglm': {
api_base: string
}
}
export type ProviderConfigurableMap = {
'azure_openai': {
openai_api_key: string
openai_api_base: string
}
'huggingface_hub': {
huggingfacehub_api_type: string
huggingfacehub_api_token: string
huggingfacehub_task: string
huggingfacehub_endpoint_url: string
}
'replicate': {
replicate_api_token: string
model_version: string
}
}
export type ProviderSystem = {
quota_type: 'trail' | 'paid'
quota_unit: 'times' | 'tokens'
quota_limit: number
quota_used: number
last_used: number
}
export type ProviderModelFlexibility = 'fixed' | 'configurable'
export type Model<T extends keyof ProviderConfigurableMap> = {
model_name: string
model_type: string
config: ProviderConfigurableMap[T]
is_valid: boolean
}
export type I18NMap = {
'en-US': string
export type FormValue = Record<string, string>
export type I18NText = {
'en': string
'zh-Hans': string
}
export type ProviderFieldMap = {
provider: {}
model: {
list_show_as: string
}
}
export type FormMap = {
text: {
place_holder: I18NMap
is_obfuscated: boolean
}
radio: {
options: {
key: string
label: I18NMap
}[]
}
}
export type Field<T extends keyof ProviderFieldMap> = {
[F in keyof FormMap]: {
type: F
key: string
is_required: boolean
toggle_enabled: boolean
help: I18NMap | null
} & FormMap[F] & ProviderFieldMap[T]
}[keyof FormMap]
export type Form = {
[T in keyof ProviderFieldMap]: {
type: T
title: I18NMap
link: {
href: string
label: I18NMap
}
fields: Field<T>[]
}
}[keyof ProviderFieldMap]
export type ProviderTypeMap = {
'custom': { form: Form }
'system': ProviderSystem
}
export type Provider<T extends ProviderName> = {
[P in keyof ProviderTypeMap]: {
provider_name: T
provider_type: P
config: T extends keyof ProviderFixedMap ? ProviderFixedMap[T] : null
models: T extends keyof ProviderConfigurableMap ? Model<T>[] : null
} & ProviderTypeMap[P]
}[keyof ProviderTypeMap]
export type Providers = {
[k in ProviderName]: {
preferred_provider_type: ProviderType
model_flexibility: ProviderModelFlexibility
providers: k extends ProviderName ? Provider<k>[] : null
}
export type Option = {
key: string
label: I18NText
}
export type Field = {
visible: (v?: FormValue) => boolean
type: string
key: string
required?: boolean
obfuscated?: boolean
switch?: boolean
label: I18NText
options?: Option[]
placeholder?: I18NText
help?: I18NText
}
export type Config = {
hit?: I18NText
title: I18NText
link: {
href: string
label: I18NText
}
defaultValue?: FormValue
fields: Field[]
}
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { Config } from './declarations'
import ModelSelector from './model-selector'
import ModelCard from './model-card'
import ModelItem from './model-item'
import ModelModal from './model-modal'
import config from './configs'
import { ChevronDownDouble } from '@/app/components/base/icons/src/vender/line/arrows'
import { HelpCircle } from '@/app/components/base/icons/src/vender/line/general'
import {
Anthropic,
AnthropicText,
AzureOpenaiServiceText,
ChatglmText,
HuggingfaceText,
OpenaiBlack,
OpenaiText,
ReplicateText,
} from '@/app/components/base/icons/src/public/llm'
import {
......@@ -17,36 +23,69 @@ import {
TongyiText,
} from '@/app/components/base/icons/src/image/llm'
const MODEL_CARD_LIST = [
{
key: 'openai',
type: 'add',
bgColor: 'bg-gray-200',
iconText: <OpenaiText className='h-5' />,
icon: <OpenaiBlack className='w-6 h-6' />,
config: config.openai,
desc: {
'en': 'Models provided by OpenAI, such as GPT-3.5-Turbo and GPT-4.',
'zh-Hans': 'Models provided by OpenAI, such as GPT-3.5-Turbo and GPT-4.',
},
},
{
key: 'anthropic',
type: 'add',
bgColor: 'bg-[#F0F0EB]',
iconText: <AnthropicText className='h-5' />,
icon: <Anthropic className='w-6 h-6' />,
config: config.anthropic,
desc: {
'en': 'Anthropic’s powerful models, such as Claude 2 and Claude Instant.',
'zh-Hans': 'Anthropic’s powerful models, such as Claude 2 and Claude Instant.',
},
},
]
const MODEL_LIST = [
{
key: 'azure_openai',
type: 'add',
icon: <AzureOpenaiServiceText className='h-6' />,
config: config.azure_openai,
},
{
key: 'replicate',
type: 'add',
icon: <ReplicateText className='h-6' />,
config: config.replicate,
},
{
key: 'huggingface_hub',
type: 'add',
icon: <HuggingfaceText className='h-6' />,
config: config.huggingface_hub,
},
{
key: 'tongyi',
type: 'setup',
icon: <TongyiText className='w-[88px] h-6' />,
config: config.tongyi,
},
{
key: 'minimax',
type: 'setup',
icon: <MinimaxText className='w-[84px] h-6' />,
config: config.minimax,
},
{
key: 'chatglm',
type: 'setup',
icon: <ChatglmText className='h-6' />,
config: config.chatglm,
},
]
......@@ -60,7 +99,13 @@ ml-0.5 w-[14px] h-[14px] text-gray-400
const ModelPage = () => {
const { t } = useTranslation()
const [showMoreModel, setShowMoreModel] = useState(false)
const [modelModalShow, setModelModalShow] = useState(false)
const [showModal, setShowModal] = useState(false)
const [modalConfig, setModalConfig] = useState<Config | undefined>(undefined)
const handleOpenModal = (config?: Config) => {
setShowModal(true)
setModalConfig(config)
}
return (
<div className='pt-1'>
......@@ -96,15 +141,22 @@ const ModelPage = () => {
<div className='mb-5 h-[0.5px] bg-gray-100' />
<div className='mb-3 text-sm font-medium text-gray-800'>{t('common.modelProvider.models')}</div>
<div className='grid grid-cols-2 gap-4 mb-6'>
<ModelCard onOpenModal={() => {}} />
<ModelCard onOpenModal={() => {}} type='anthropic' />
{
MODEL_CARD_LIST.map(model => (
<ModelCard
key={model.key}
provider={model}
onOpenModal={() => handleOpenModal(model.config)}
/>
))
}
</div>
{
MODEL_LIST.slice(0, showMoreModel ? MODEL_LIST.length : 3).map(model => (
<ModelItem
key={model.key}
provider={model}
onOperate={() => setModelModalShow(true)}
onOpenModal={() => handleOpenModal(model.config)}
/>
))
}
......@@ -117,8 +169,9 @@ const ModelPage = () => {
)
}
<ModelModal
isShow={modelModalShow}
onCancel={() => setModelModalShow(false)}
isShow={showModal}
config={modalConfig}
onCancel={() => setShowModal(false)}
/>
</div>
)
......
import type { FC } from 'react'
import type { FC, ReactElement } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import type { I18NText } from '../declarations'
import Indicator from '../../../indicator'
import PrioritySelector from './PrioritySelector'
import { IS_CE_EDITION } from '@/config'
import I18n from '@/context/i18n'
import Button from '@/app/components/base/button'
import { InfoCircle, Plus } from '@/app/components/base/icons/src/vender/line/general'
import { Anthropic, AnthropicText, OpenaiBlack, OpenaiText } from '@/app/components/base/icons/src/public/llm'
const PROVIDER_MAP = {
openai: {
bgColor: 'bg-gray-200',
title: <OpenaiText className='h-5' />,
desc: <OpenaiBlack className='w-6 h-6' />,
},
anthropic: {
bgColor: 'bg-[#F0F0EB]',
title: <AnthropicText className='h-5' />,
desc: <Anthropic className='w-6 h-6' />,
},
}
type ModelCardProps = {
type?: 'openai' | 'anthropic'
provider: { key: string; type: string; bgColor: string; icon: ReactElement; desc: I18NText; iconText?: ReactElement }
onOpenModal: () => void
}
const ModelCard: FC<ModelCardProps> = ({
type = 'openai',
provider,
onOpenModal,
}) => {
const { locale } = useContext(I18n)
const { t } = useTranslation()
return (
<div className='rounded-xl border-[0.5px] border-gray-200 shadow-xs'>
<div className={`flex px-4 pt-4 pb-3 rounded-t-lg ${PROVIDER_MAP[type].bgColor}`}>
<div className={`flex px-4 pt-4 pb-3 rounded-t-lg ${provider.bgColor}`}>
<div className='mr-3'>
<div className='mb-1'>
{PROVIDER_MAP[type].title}
{provider.iconText}
</div>
<div className='text-xs text-black opacity-60'>{t(`common.modelProvider.card.${type}.desc`)}</div>
<div className='text-xs text-black opacity-60'>{provider.desc[locale]}</div>
</div>
{PROVIDER_MAP[type].desc}
{provider.icon}
</div>
{
!IS_CE_EDITION && (
......
import type { FC } from 'react'
import type { FC, ReactElement } from 'react'
import { useTranslation } from 'react-i18next'
import Indicator from '../../../indicator'
import Operation from './Operation'
import Button from '@/app/components/base/button'
type ModelItemProps = {
provider: { key: string; type: string; icon: any }
onOperate: () => void
provider: { key: string; type: string; icon: ReactElement }
onOpenModal: () => void
}
const ModelItem: FC<ModelItemProps> = ({
provider,
onOperate,
onOpenModal,
}) => {
const { t } = useTranslation()
......@@ -20,7 +20,7 @@ const ModelItem: FC<ModelItemProps> = ({
{provider.icon}
<Button
className='!px-3 !h-7 rounded-md bg-white !text-xs font-medium text-gray-700'
onClick={onOperate}
onClick={onOpenModal}
>
{t(`common.operation.${provider.type}`)}
</Button>
......@@ -28,7 +28,7 @@ const ModelItem: FC<ModelItemProps> = ({
<Indicator className='mr-3' />
<Button
className='mr-1 !px-3 !h-7 rounded-md bg-white !text-xs font-medium text-gray-700'
onClick={onOperate}
onClick={onOpenModal}
>
{t('common.operation.edit')}
</Button>
......
import { useState } from 'react'
import type { FC } from 'react'
import { useContext } from 'use-context-selector'
import type { Field, FormValue } from '../declarations'
import I18n from '@/context/i18n'
import Switch from '@/app/components/base/switch'
import { HelpCircle } from '@/app/components/base/icons/src/vender/line/general'
type FormProps = {
initValue?: FormValue
fields: Field[]
}
const nameClassName = `
py-2 text-sm text-gray-900
`
const Form: FC<FormProps> = ({
initValue,
fields,
}) => {
const { locale } = useContext(I18n)
const [value, setValue] = useState(initValue)
const handleFormChange = (k: string, v: string) => {
setValue({ ...value, [k]: v })
}
const renderField = (field: Field) => {
if (field.type === 'text' && field.visible(value)) {
if (field.switch) {
return (
<div key={field.key} className='py-3'>
<div className='flex items-center'>
<Switch onChange={() => {}} />
<div className='ml-2 text-sm font-medium text-gray-900'>{field.label[locale]}</div>
<div className='flex items-center justify-center ml-1'>
<HelpCircle className='w-[14px] h-[14px] text-gray-400' />
</div>
</div>
</div>
)
}
return (
<div key={field.key} className='py-3'>
<div className={nameClassName}>{field.label[locale]}</div>
<input
placeholder={field?.placeholder?.[locale]}
/>
</div>
)
}
if (field.type === 'radio' && field.visible(value)) {
return (
<div key={field.key} className='py-3'>
<div className={nameClassName}>{field.label[locale]}</div>
<div className={`grid grid-cols-${field?.options?.length} gap-3`}>
{
field?.options?.map(option => (
<div
className={`
flex items-center px-3 h-9 rounded-lg border border-gray-100 bg-gray-25 cursor-pointer
${value?.[field.key] === option.key && 'bg-white border-[1.5px] border-primary-400 shadow-sm'}
`}
onClick={() => handleFormChange(field.key, option.key)}
key={`${field.key}-${option.key}`}
>
<div className={`
flex justify-center items-center mr-2 w-4 h-4 border border-gray-300 rounded-full
${value?.[field.key] === option.key && 'border-[5px] border-primary-600'}
`} />
<div className='text-sm text-gray-900'>{option.label[locale]}</div>
</div>
))
}
</div>
</div>
)
}
}
return (
<div>
{
fields.map(field => renderField(field))
}
</div>
)
}
export default Form
import KeyInput from '../../key-validator/KeyInput'
const OpenaiForm = () => {
return (
<div>
<div className=''>API Key</div>
<KeyInput
name='API Key'
placeholder={'xx'}
value={''}
onChange={() => {}}
onFocus={() => {}}
validating={false}
validatedStatusState={{}}
/>
</div>
)
}
export default OpenaiForm
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import OpenaiForm from './OpenaiForm'
import { useContext } from 'use-context-selector'
import type { Config } from '../declarations'
import Form from './Form'
import I18n from '@/context/i18n'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
type ModelModalProps = {
type?: string
isShow: boolean
config?: Config
onCancel: () => void
}
const ModelModal: FC<ModelModalProps> = ({
type,
isShow,
onCancel,
config,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
return (
<Modal
......@@ -24,15 +29,20 @@ const ModelModal: FC<ModelModalProps> = ({
onClose={() => {}}
className='!p-0 !w-[640px] !max-w-[640px]'
>
<div className='px-8 pt-8 pb-6'>
<div className='flex justify-between items-center mb-7'>
<div className='text-xl font-semibold text-gray-900'>Setup OpenAI</div>
<div className='px-8 pt-8'>
<div className='flex justify-between items-center mb-2'>
<div className='text-xl font-semibold text-gray-900'>{config?.title[locale]}</div>
</div>
<div>
<OpenaiForm />
</div>
<div className='flex justify-between items-center'>
<div></div>
<Form fields={config?.fields || []} initValue={config?.defaultValue} />
<div className='flex justify-between items-center py-6'>
<a
href={config?.link.href}
target='_blank'
className='inline-flex items-center text-xs text-primary-600'
>
{config?.link.label[locale]}
<LinkExternal02 className='ml-1 w-3 h-3' />
</a>
<div>
<Button className='mr-2 !h-9 !text-sm font-medium text-gray-700' onClick={onCancel}>{t('common.operation.cancel')}</Button>
<Button className='!h-9 !text-sm font-medium' type='primary'>{t('common.operation.save')}</Button>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment