### What problem does this PR solve? feat: support AWS Bedrock #308 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.9.0
| @@ -492,6 +492,20 @@ The above is the content you need to summarize.`, | |||
| volcAKMessage: 'Please input your VOLC_ACCESS_KEY', | |||
| addVolcEngineSK: 'VOLC SECRET_KEY', | |||
| volcSKMessage: 'Please input your SECRET_KEY', | |||
| bedrockModelNameMessage: 'Please input your model name!', | |||
| addBedrockEngineAK: 'ACCESS KEY', | |||
| bedrockAKMessage: 'Please input your ACCESS KEY', | |||
| addBedrockSK: 'SECRET KEY', | |||
| bedrockSKMessage: 'Please input your SECRET KEY', | |||
| bedrockRegion: 'AWS Region', | |||
| bedrockRegionMessage: 'Please select!', | |||
| 'us-east-1': 'US East (N. Virginia)', | |||
| 'us-west-2': 'US West (Oregon)', | |||
| 'ap-southeast-1': 'Asia Pacific (Singapore)', | |||
| 'ap-northeast-1': 'Asia Pacific (Tokyo)', | |||
| 'eu-central-1': 'Europe (Frankfurt)', | |||
| 'us-gov-west-1': 'AWS GovCloud (US-West)', | |||
| 'ap-southeast-2': 'Asia Pacific (Sydney)', | |||
| }, | |||
| message: { | |||
| registered: 'Registered!', | |||
| @@ -455,6 +455,20 @@ export default { | |||
| volcAKMessage: '請輸入VOLC_ACCESS_KEY', | |||
| addVolcEngineSK: '火山 SECRET_KEY', | |||
| volcSKMessage: '請輸入VOLC_SECRET_KEY', | |||
| bedrockModelNameMessage: '請輸入名稱!', | |||
| addBedrockEngineAK: 'ACCESS KEY', | |||
| bedrockAKMessage: '請輸入 ACCESS KEY', | |||
| addBedrockSK: 'SECRET KEY', | |||
| bedrockSKMessage: '請輸入 SECRET KEY', | |||
| bedrockRegion: 'AWS Region', | |||
| bedrockRegionMessage: '請選擇!', | |||
| 'us-east-1': '美國東部 (維吉尼亞北部)', | |||
| 'us-west-2': '美國西部 (俄勒岡州)', | |||
| 'ap-southeast-1': '亞太地區 (新加坡)', | |||
| 'ap-northeast-1': '亞太地區 (東京)', | |||
| 'eu-central-1': '歐洲 (法蘭克福)', | |||
| 'us-gov-west-1': 'AWS GovCloud (US-West)', | |||
| 'ap-southeast-2': '亞太地區 (雪梨)', | |||
| }, | |||
| message: { | |||
| registered: '註冊成功', | |||
| @@ -472,6 +472,20 @@ export default { | |||
| volcAKMessage: '请输入VOLC_ACCESS_KEY', | |||
| addVolcEngineSK: '火山 SECRET_KEY', | |||
| volcSKMessage: '请输入VOLC_SECRET_KEY', | |||
| bedrockModelNameMessage: '请输入名称!', | |||
| addBedrockEngineAK: 'ACCESS KEY', | |||
| bedrockAKMessage: '请输入 ACCESS KEY', | |||
| addBedrockSK: 'SECRET KEY', | |||
| bedrockSKMessage: '请输入 SECRET KEY', | |||
| bedrockRegion: 'AWS Region', | |||
| bedrockRegionMessage: '请选择!', | |||
| 'us-east-1': '美国东部 (弗吉尼亚北部)', | |||
| 'us-west-2': '美国西部 (俄勒冈州)', | |||
| 'ap-southeast-1': '亚太地区 (新加坡)', | |||
| 'ap-northeast-1': '亚太地区 (东京)', | |||
| 'eu-central-1': '欧洲 (法兰克福)', | |||
| 'us-gov-west-1': 'AWS GovCloud (US-West)', | |||
| 'ap-southeast-2': '亚太地区 (悉尼)', | |||
| }, | |||
| message: { | |||
| registered: '注册成功', | |||
| @@ -0,0 +1,119 @@ | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import { IAddLlmRequestBody } from '@/interfaces/request/llm'; | |||
| import { Flex, Form, Input, Modal, Select, Space } from 'antd'; | |||
| import { useMemo } from 'react'; | |||
| import { BedrockRegionList } from '../constant'; | |||
| type FieldType = IAddLlmRequestBody & { | |||
| bedrock_ak: string; | |||
| bedrock_sk: string; | |||
| bedrock_region: string; | |||
| }; | |||
| const { Option } = Select; | |||
| const BedrockModal = ({ | |||
| visible, | |||
| hideModal, | |||
| onOk, | |||
| loading, | |||
| llmFactory, | |||
| }: IModalProps<IAddLlmRequestBody> & { llmFactory: string }) => { | |||
| const [form] = Form.useForm<FieldType>(); | |||
| const { t } = useTranslate('setting'); | |||
| const options = useMemo( | |||
| () => BedrockRegionList.map((x) => ({ value: x, label: t(x) })), | |||
| [t], | |||
| ); | |||
| const handleOk = async () => { | |||
| const values = await form.validateFields(); | |||
| const data = { | |||
| ...values, | |||
| llm_factory: llmFactory, | |||
| }; | |||
| onOk?.(data); | |||
| }; | |||
| return ( | |||
| <Modal | |||
| title={t('addLlmTitle', { name: llmFactory })} | |||
| open={visible} | |||
| onOk={handleOk} | |||
| onCancel={hideModal} | |||
| okButtonProps={{ loading }} | |||
| footer={(originNode: React.ReactNode) => { | |||
| return ( | |||
| <Flex justify={'space-between'}> | |||
| <a | |||
| href="https://console.aws.amazon.com/" | |||
| target="_blank" | |||
| rel="noreferrer" | |||
| > | |||
| {t('ollamaLink', { name: llmFactory })} | |||
| </a> | |||
| <Space>{originNode}</Space> | |||
| </Flex> | |||
| ); | |||
| }} | |||
| > | |||
| <Form | |||
| name="basic" | |||
| style={{ maxWidth: 600 }} | |||
| autoComplete="off" | |||
| layout={'vertical'} | |||
| form={form} | |||
| > | |||
| <Form.Item<FieldType> | |||
| label={t('modelType')} | |||
| name="model_type" | |||
| initialValue={'chat'} | |||
| rules={[{ required: true, message: t('modelTypeMessage') }]} | |||
| > | |||
| <Select placeholder={t('modelTypeMessage')}> | |||
| <Option value="chat">chat</Option> | |||
| <Option value="embedding">embedding</Option> | |||
| </Select> | |||
| </Form.Item> | |||
| <Form.Item<FieldType> | |||
| label={t('modelName')} | |||
| name="llm_name" | |||
| rules={[{ required: true, message: t('bedrockModelNameMessage') }]} | |||
| > | |||
| <Input placeholder={t('bedrockModelNameMessage')} /> | |||
| </Form.Item> | |||
| <Form.Item<FieldType> | |||
| label={t('addBedrockEngineAK')} | |||
| name="bedrock_ak" | |||
| rules={[{ required: true, message: t('bedrockAKMessage') }]} | |||
| > | |||
| <Input placeholder={t('bedrockAKMessage')} /> | |||
| </Form.Item> | |||
| <Form.Item<FieldType> | |||
| label={t('addBedrockSK')} | |||
| name="bedrock_sk" | |||
| rules={[{ required: true, message: t('bedrockSKMessage') }]} | |||
| > | |||
| <Input placeholder={t('bedrockSKMessage')} /> | |||
| </Form.Item> | |||
| <Form.Item<FieldType> | |||
| label={t('bedrockRegion')} | |||
| name="bedrock_region" | |||
| rules={[{ required: true, message: t('bedrockRegionMessage') }]} | |||
| > | |||
| <Select | |||
| placeholder={t('bedrockRegionMessage')} | |||
| options={options} | |||
| allowClear | |||
| ></Select> | |||
| </Form.Item> | |||
| </Form> | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default BedrockModal; | |||
| @@ -0,0 +1,33 @@ | |||
| // Please lowercase the file name | |||
| export const IconMap = { | |||
| 'Tongyi-Qianwen': 'tongyi', | |||
| Moonshot: 'moonshot', | |||
| OpenAI: 'openai', | |||
| 'ZHIPU-AI': 'zhipu', | |||
| 文心一言: 'wenxin', | |||
| Ollama: 'ollama', | |||
| Xinference: 'xinference', | |||
| DeepSeek: 'deepseek', | |||
| VolcEngine: 'volc_engine', | |||
| BaiChuan: 'baichuan', | |||
| Jina: 'jina', | |||
| MiniMax: 'chat-minimax', | |||
| Mistral: 'mistral', | |||
| 'Azure-OpenAI': 'azure', | |||
| Bedrock: 'bedrock', | |||
| Gemini: 'gemini', | |||
| Groq: 'groq-next', | |||
| OpenRouter: 'open-router', | |||
| LocalAI: 'local-ai', | |||
| StepFun: 'stepfun', | |||
| }; | |||
| export const BedrockRegionList = [ | |||
| 'us-east-1', | |||
| 'us-west-2', | |||
| 'ap-southeast-1', | |||
| 'ap-northeast-1', | |||
| 'eu-central-1', | |||
| 'us-gov-west-1', | |||
| 'ap-southeast-2', | |||
| ]; | |||
| @@ -168,7 +168,6 @@ export const useSubmitOllama = () => { | |||
| export const useSubmitVolcEngine = () => { | |||
| const loading = useOneNamespaceEffectsLoading('settingModel', ['add_llm']); | |||
| const [selectedVolcFactory, setSelectedVolcFactory] = useState<string>(''); | |||
| const addLlm = useAddLlm(); | |||
| const { | |||
| visible: volcAddingVisible, | |||
| @@ -186,18 +185,40 @@ export const useSubmitVolcEngine = () => { | |||
| [hideVolcAddingModal, addLlm], | |||
| ); | |||
| const handleShowVolcAddingModal = (llmFactory: string) => { | |||
| setSelectedVolcFactory(llmFactory); | |||
| showVolcAddingModal(); | |||
| }; | |||
| return { | |||
| volcAddingLoading: loading, | |||
| onVolcAddingOk, | |||
| volcAddingVisible, | |||
| hideVolcAddingModal, | |||
| showVolcAddingModal: handleShowVolcAddingModal, | |||
| selectedVolcFactory, | |||
| showVolcAddingModal, | |||
| }; | |||
| }; | |||
| export const useSubmitBedrock = () => { | |||
| const loading = useOneNamespaceEffectsLoading('settingModel', ['add_llm']); | |||
| const addLlm = useAddLlm(); | |||
| const { | |||
| visible: bedrockAddingVisible, | |||
| hideModal: hideBedrockAddingModal, | |||
| showModal: showBedrockAddingModal, | |||
| } = useSetModalState(); | |||
| const onBedrockAddingOk = useCallback( | |||
| async (payload: IAddLlmRequestBody) => { | |||
| const ret = await addLlm(payload); | |||
| if (ret === 0) { | |||
| hideBedrockAddingModal(); | |||
| } | |||
| }, | |||
| [hideBedrockAddingModal, addLlm], | |||
| ); | |||
| return { | |||
| bedrockAddingLoading: loading, | |||
| onBedrockAddingOk, | |||
| bedrockAddingVisible, | |||
| hideBedrockAddingModal, | |||
| showBedrockAddingModal, | |||
| }; | |||
| }; | |||
| @@ -28,14 +28,17 @@ import { | |||
| Tooltip, | |||
| Typography, | |||
| } from 'antd'; | |||
| import { useCallback } from 'react'; | |||
| import { useCallback, useMemo } from 'react'; | |||
| import SettingTitle from '../components/setting-title'; | |||
| import { isLocalLlmFactory } from '../utils'; | |||
| import ApiKeyModal from './api-key-modal'; | |||
| import BedrockModal from './bedrock-modal'; | |||
| import { IconMap } from './constant'; | |||
| import { | |||
| useHandleDeleteLlm, | |||
| useSelectModelProvidersLoading, | |||
| useSubmitApiKey, | |||
| useSubmitBedrock, | |||
| useSubmitOllama, | |||
| useSubmitSystemModelSetting, | |||
| useSubmitVolcEngine, | |||
| @@ -43,31 +46,7 @@ import { | |||
| import styles from './index.less'; | |||
| import OllamaModal from './ollama-modal'; | |||
| import SystemModelSettingModal from './system-model-setting-modal'; | |||
| import VolcEngineModal from './volcengine-model'; | |||
| // Please lowercase the file name | |||
| const IconMap = { | |||
| 'Tongyi-Qianwen': 'tongyi', | |||
| Moonshot: 'moonshot', | |||
| OpenAI: 'openai', | |||
| 'ZHIPU-AI': 'zhipu', | |||
| 文心一言: 'wenxin', | |||
| Ollama: 'ollama', | |||
| Xinference: 'xinference', | |||
| DeepSeek: 'deepseek', | |||
| VolcEngine: 'volc_engine', | |||
| BaiChuan: 'baichuan', | |||
| Jina: 'jina', | |||
| MiniMax: 'chat-minimax', | |||
| Mistral: 'mistral', | |||
| 'Azure-OpenAI': 'azure', | |||
| Bedrock: 'bedrock', | |||
| Gemini: 'gemini', | |||
| Groq: 'groq-next', | |||
| OpenRouter: 'open-router', | |||
| LocalAI:'local-ai', | |||
| StepFun:'stepfun' | |||
| }; | |||
| import VolcEngineModal from './volcengine-modal'; | |||
| const LlmIcon = ({ name }: { name: string }) => { | |||
| const icon = IconMap[name as keyof typeof IconMap]; | |||
| @@ -188,32 +167,37 @@ const UserSettingModel = () => { | |||
| showVolcAddingModal, | |||
| onVolcAddingOk, | |||
| volcAddingLoading, | |||
| selectedVolcFactory, | |||
| } = useSubmitVolcEngine(); | |||
| const handleApiKeyClick = useCallback( | |||
| const { | |||
| bedrockAddingLoading, | |||
| onBedrockAddingOk, | |||
| bedrockAddingVisible, | |||
| hideBedrockAddingModal, | |||
| showBedrockAddingModal, | |||
| } = useSubmitBedrock(); | |||
| const ModalMap = useMemo( | |||
| () => ({ | |||
| Bedrock: showBedrockAddingModal, | |||
| VolcEngine: showVolcAddingModal, | |||
| }), | |||
| [showBedrockAddingModal, showVolcAddingModal], | |||
| ); | |||
| const handleAddModel = useCallback( | |||
| (llmFactory: string) => { | |||
| if (isLocalLlmFactory(llmFactory)) { | |||
| showLlmAddingModal(llmFactory); | |||
| } else if (llmFactory === 'VolcEngine') { | |||
| showVolcAddingModal('VolcEngine'); | |||
| } else if (llmFactory in ModalMap) { | |||
| ModalMap[llmFactory as keyof typeof ModalMap](); | |||
| } else { | |||
| showApiKeyModal({ llm_factory: llmFactory }); | |||
| } | |||
| }, | |||
| [showApiKeyModal, showLlmAddingModal, showVolcAddingModal], | |||
| [showApiKeyModal, showLlmAddingModal, ModalMap], | |||
| ); | |||
| const handleAddModel = (llmFactory: string) => () => { | |||
| if (isLocalLlmFactory(llmFactory)) { | |||
| showLlmAddingModal(llmFactory); | |||
| } else if (llmFactory === 'VolcEngine') { | |||
| showVolcAddingModal('VolcEngine'); | |||
| } else { | |||
| handleApiKeyClick(llmFactory); | |||
| } | |||
| }; | |||
| const items: CollapseProps['items'] = [ | |||
| { | |||
| key: '1', | |||
| @@ -223,7 +207,7 @@ const UserSettingModel = () => { | |||
| grid={{ gutter: 16, column: 1 }} | |||
| dataSource={llmList} | |||
| renderItem={(item) => ( | |||
| <ModelCard item={item} clickApiKey={handleApiKeyClick}></ModelCard> | |||
| <ModelCard item={item} clickApiKey={handleAddModel}></ModelCard> | |||
| )} | |||
| /> | |||
| ), | |||
| @@ -254,7 +238,7 @@ const UserSettingModel = () => { | |||
| </Flex> | |||
| </Flex> | |||
| <Divider></Divider> | |||
| <Button type="link" onClick={handleAddModel(item.name)}> | |||
| <Button type="link" onClick={() => handleAddModel(item.name)}> | |||
| {t('addTheModel')} | |||
| </Button> | |||
| </Card> | |||
| @@ -305,8 +289,15 @@ const UserSettingModel = () => { | |||
| hideModal={hideVolcAddingModal} | |||
| onOk={onVolcAddingOk} | |||
| loading={volcAddingLoading} | |||
| llmFactory={selectedVolcFactory} | |||
| llmFactory={'VolcEngine'} | |||
| ></VolcEngineModal> | |||
| <BedrockModal | |||
| visible={bedrockAddingVisible} | |||
| hideModal={hideBedrockAddingModal} | |||
| onOk={onBedrockAddingOk} | |||
| loading={bedrockAddingLoading} | |||
| llmFactory={'Bedrock'} | |||
| ></BedrockModal> | |||
| </section> | |||
| ); | |||
| }; | |||