Commit 2197f976 authored by StyleZhang's avatar StyleZhang

feat: add model-selector

parent a0bd1524
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Icon_2" d="M12.25 12.75L10.2084 10.7083M11.6667 7.20833C11.6667 9.94675 9.44675 12.1667 6.70833 12.1667C3.96992 12.1667 1.75 9.94675 1.75 7.20833C1.75 4.46992 3.96992 2.25 6.70833 2.25C9.44675 2.25 11.6667 4.46992 11.6667 7.20833Z" stroke="#98A2B3" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "14",
"height": "15",
"viewBox": "0 0 14 15",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "Icon"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon_2",
"d": "M12.25 12.75L10.2084 10.7083M11.6667 7.20833C11.6667 9.94675 9.44675 12.1667 6.70833 12.1667C3.96992 12.1667 1.75 9.94675 1.75 7.20833C1.75 4.46992 3.96992 2.25 6.70833 2.25C9.44675 2.25 11.6667 4.46992 11.6667 7.20833Z",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "SearchLg"
}
\ No newline at end of file
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './SearchLg.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
export default Icon
...@@ -4,6 +4,7 @@ export { default as Hash02 } from './Hash02' ...@@ -4,6 +4,7 @@ export { default as Hash02 } from './Hash02'
export { default as LinkExternal02 } from './LinkExternal02' export { default as LinkExternal02 } from './LinkExternal02'
export { default as Loading02 } from './Loading02' export { default as Loading02 } from './Loading02'
export { default as LogOut01 } from './LogOut01' export { default as LogOut01 } from './LogOut01'
export { default as SearchLg } from './SearchLg'
export { default as Trash03 } from './Trash03' export { default as Trash03 } from './Trash03'
export { default as XClose } from './XClose' export { default as XClose } from './XClose'
export { default as X } from './X' export { default as X } from './X'
.modal { .modal {
max-width: 720px !important; max-width: 1024px !important;
border-radius: 12px !important;
padding: 0 !important; padding: 0 !important;
overflow-y: auto; overflow-y: auto;
} }
\ No newline at end of file
...@@ -8,9 +8,9 @@ import AccountPage from './account-page' ...@@ -8,9 +8,9 @@ import AccountPage from './account-page'
import MembersPage from './members-page' import MembersPage from './members-page'
import IntegrationsPage from './Integrations-page' import IntegrationsPage from './Integrations-page'
import LanguagePage from './language-page' import LanguagePage from './language-page'
import ProviderPage from './provider-page'
import PluginPage from './plugin-page' import PluginPage from './plugin-page'
import DataSourcePage from './data-source-page' import DataSourcePage from './data-source-page'
import ModelPage from './model-page'
import s from './index.module.css' import s from './index.module.css'
import Modal from '@/app/components/base/modal' import Modal from '@/app/components/base/modal'
import { Database03, PuzzlePiece01 } from '@/app/components/base/icons/src/vender/line/development' import { Database03, PuzzlePiece01 } from '@/app/components/base/icons/src/vender/line/development'
...@@ -143,17 +143,17 @@ export default function AccountSetting({ ...@@ -143,17 +143,17 @@ export default function AccountSetting({
} }
</div> </div>
</div> </div>
<div ref={scrollRef} className='relative w-[520px] h-[580px] pb-4 overflow-y-auto'> <div ref={scrollRef} className='relative w-[824px] h-[720px] pb-4 overflow-y-auto'>
<div className={cn('sticky top-0 px-6 py-4 flex items-center justify-between h-14 mb-4 bg-white text-base font-medium text-gray-900', scrolled && scrolledClassName)}> <div className={cn('sticky top-0 px-8 py-4 flex items-center justify-between h-14 bg-white text-base font-medium text-gray-900', scrolled && scrolledClassName)}>
{[...menuItems[0].items, ...menuItems[1].items].find(item => item.key === activeMenu)?.name} {[...menuItems[0].items, ...menuItems[1].items].find(item => item.key === activeMenu)?.name}
<XMarkIcon className='w-4 h-4 cursor-pointer' onClick={onCancel} /> <XMarkIcon className='w-4 h-4 cursor-pointer' onClick={onCancel} />
</div> </div>
<div className='px-6'> <div className='px-8'>
{activeMenu === 'account' && <AccountPage />} {activeMenu === 'account' && <AccountPage />}
{activeMenu === 'members' && <MembersPage />} {activeMenu === 'members' && <MembersPage />}
{activeMenu === 'integrations' && <IntegrationsPage />} {activeMenu === 'integrations' && <IntegrationsPage />}
{activeMenu === 'language' && <LanguagePage />} {activeMenu === 'language' && <LanguagePage />}
{activeMenu === 'provider' && <ProviderPage />} {activeMenu === 'provider' && <ModelPage />}
{activeMenu === 'data-source' && <DataSourcePage />} {activeMenu === 'data-source' && <DataSourcePage />}
{activeMenu === 'plugin' && <PluginPage />} {activeMenu === 'plugin' && <PluginPage />}
</div> </div>
......
import { useTranslation } from 'react-i18next'
import ModelSelector from './model-selector'
const ModelPage = () => {
const { t } = useTranslation()
return (
<div className='pt-1'>
<div className='grid grid-cols-2 gap-4'>
<div className='w-full'>
<div className='py-2 text-sm font-medium text-gray-900'>
{t('common.modelProvider.systemReasoningModel.key')}
</div>
<div>
<ModelSelector />
</div>
</div>
</div>
</div>
)
}
export default ModelPage
.options {
box-shadow: 0px 4px 6px 0px rgba(0, 0, 0, 0.05), 0px 10px 15px -3px rgba(0, 0, 0, 0.10)
}
\ No newline at end of file
import { Fragment, useState } from 'react'
import { Popover, Transition } from '@headlessui/react'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import s from './index.module.css'
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
import { Check, SearchLg } from '@/app/components/base/icons/src/vender/line/general'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
import { Anthropic, Gpt3, Gpt4 } from '@/app/components/base/icons/src/public/llm'
const iconClassName = 'mr-2 w-4 h-4'
const models = [
{ type: 'provider', name: 'OpenAI' },
{ type: 'model', name: 'GPT-3.5-Turbo-16K', value: 'GPT-3.5-Turbo-16K', icon: <Gpt3 className={iconClassName} />, i: 'Gpt3' },
{ type: 'model', name: 'GPT-4', value: 'GPT-4', icon: <Gpt4 className={iconClassName} />, i: 'Gpt4' },
{ type: 'provider', name: 'Anthropic' },
{ type: 'model', name: 'Claude-2', value: 'Claude-2', icon: <Anthropic className={iconClassName} />, i: 'Anthropic' },
{ type: 'model', name: 'Claude-Instant', value: 'Claude-Instant', icon: <Anthropic className={iconClassName} />, i: 'Anthropic' },
]
const ModelSelector = () => {
const { t } = useTranslation()
const [selected, setSelected] = useState('Claude-2')
const [search, setSearch] = useState('')
return (
<div className=''>
<Popover className='relative'>
<Popover.Button className='flex items-center px-2.5 w-full h-9 bg-gray-100 rounded-lg'>
{
({ open }) => (
<>
<div className='mr-1.5 w-5 h-5' />
<div className='mr-1.5 grow text-left text-sm text-gray-900'>{selected}</div>
<ChevronDown className={`w-4 h-4 text-gray-700 ${open ? 'opacity-100' : 'opacity-60'}`} />
</>
)
}
</Popover.Button>
<Transition
as={Fragment}
leave='transition ease-in duration-100'
leaveFrom='opacity-100'
leaveTo='opacity-0'
>
<Popover.Panel className={cn(
s.options,
'absolute top-10 p-1 w-full max-h-[366px] border-[0.5px] border-gray-200 rounded-lg overflow-auto',
)}>
<div className='px-2 pt-2 pb-1'>
<div className='flex items-center px-2 h-8 bg-gray-100 rounded-lg'>
<div className='mr-1.5 p-[1px]'><SearchLg className='w-[14px] h-[14px] text-gray-400' /></div>
<div className='grow px-0.5'>
<input
value={search}
onChange={e => setSearch(e.target.value)}
className={`
block w-full h-8 bg-transparent text-[13px] text-gray-700
outline-none appearance-none border-none
`}
placeholder={t('common.modelProvider.searchModel') || ''}
/>
</div>
{
search && (
<div className='ml-1 p-0.5 cursor-pointer' onClick={() => setSearch('')}>
<XCircle className='w-3 h-3 text-gray-400' />
</div>
)
}
</div>
</div>
{
models.map((model) => {
if (model.type === 'provider') {
return (
<div
className='px-3 pt-2 pb-1 text-xs font-medium text-gray-500'
key={`${model.type}-${model.name}`}
>
{model.name}
</div>
)
}
if (model.type === 'model') {
return (
<Popover.Button
key={`${model.type}-${model.name}`}
className={`
flex items-center px-3 w-full h-8 rounded-lg cursor-pointer hover:bg-gray-50
${selected === model.value && 'bg-gray-50'}
`}
>
{model.icon}
<div className='grow text-left text-sm text-gray-900'>{model.name}</div>
{ selected === model.value && <Check className='w-4 h-4 text-primary-600' /> }
</Popover.Button>
)
}
return null
})
}
</Popover.Panel>
</Transition>
</Popover>
</div>
)
}
export default ModelSelector
...@@ -202,6 +202,20 @@ const translation = { ...@@ -202,6 +202,20 @@ const translation = {
back: ' technology.', back: ' technology.',
}, },
}, },
modelProvider: {
systemReasoningModel: {
key: 'System Reasoning Model',
tip: 'System Reasoning Model',
},
embeddingModel: {
key: 'Embedding Model',
tip: 'Embedding Model',
},
searchModel: 'Search model',
noModelFound: 'No model found for {{model}}',
models: 'Models',
showMoreModelProvider: 'Show more model provider',
},
dataSource: { dataSource: {
add: 'Add a data source', add: 'Add a data source',
connect: 'Connect', connect: 'Connect',
......
...@@ -202,6 +202,20 @@ const translation = { ...@@ -202,6 +202,20 @@ const translation = {
back: ' 技术进行加密和存储。', back: ' 技术进行加密和存储。',
}, },
}, },
modelProvider: {
systemReasoningModel: {
key: 'System Reasoning Model',
tip: 'System Reasoning Model',
},
embeddingModel: {
key: 'Embedding Model',
tip: 'Embedding Model',
},
searchModel: 'Search model',
noModelFound: 'No model found for {{model}}',
models: 'Models',
showMoreModelProvider: 'Show more model provider',
},
dataSource: { dataSource: {
add: '添加数据源', add: '添加数据源',
connect: '绑定', connect: '绑定',
......
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