diff --git a/web/src/assets/svg/llm/github.svg b/web/src/assets/svg/llm/github.svg new file mode 100644 index 0000000000000000000000000000000000000000..6f80a87ed11bf8dd59faece50b0d8b4367d72fda --- /dev/null +++ b/web/src/assets/svg/llm/github.svg @@ -0,0 +1,10 @@ +<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_660_5)"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M8.50662 0.453613C4.07917 0.453613 0.5 4.05917 0.5 8.51972C0.5 12.0853 2.79329 15.1035 5.9747 16.1717C6.37246 16.252 6.51816 15.9981 6.51816 15.7846C6.51816 15.5976 6.50505 14.9566 6.50505 14.2888C4.2778 14.7696 3.81399 13.3272 3.81399 13.3272C3.45606 12.3924 2.92572 12.1522 2.92572 12.1522C2.19674 11.658 2.97882 11.658 2.97882 11.658C3.78744 11.7115 4.21175 12.486 4.21175 12.486C4.92745 13.7145 6.08074 13.3674 6.54471 13.1537C6.61092 12.6328 6.82315 12.2723 7.0485 12.072C5.27211 11.885 3.40312 11.1906 3.40312 8.0923C3.40312 7.21091 3.72107 6.4898 4.22486 5.92897C4.14538 5.7287 3.86693 4.90057 4.30451 3.79219C4.30451 3.79219 4.98055 3.57848 6.50488 4.62016C7.1575 4.44359 7.83054 4.35377 8.50662 4.35302C9.18266 4.35302 9.87181 4.4466 10.5082 4.62016C12.0327 3.57848 12.7087 3.79219 12.7087 3.79219C13.1463 4.90057 12.8677 5.7287 12.7882 5.92897C13.3053 6.4898 13.6101 7.21091 13.6101 8.0923C13.6101 11.1906 11.7411 11.8716 9.95146 12.072C10.2432 12.3257 10.4949 12.8064 10.4949 13.5677C10.4949 14.6493 10.4818 15.5174 10.4818 15.7844C10.4818 15.9981 10.6277 16.252 11.0253 16.1719C14.2067 15.1033 16.5 12.0853 16.5 8.51972C16.5131 4.05917 12.9208 0.453613 8.50662 0.453613Z" fill="#24292F"/> +</g> +<defs> +<clipPath id="clip0_660_5"> +<rect width="16" height="16" fill="white" transform="translate(0.5 0.453613)"/> +</clipPath> +</defs> +</svg> diff --git a/web/src/assets/svg/llm/google.svg b/web/src/assets/svg/llm/google.svg new file mode 100644 index 0000000000000000000000000000000000000000..f0d10ecfd99def924bdc3dc181ea5be3fef67c41 --- /dev/null +++ b/web/src/assets/svg/llm/google.svg @@ -0,0 +1,13 @@ +<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_660_28)"> +<path d="M8 6.99902V10.0972H12.3054C12.1164 11.0936 11.549 11.9372 10.6981 12.5045L13.2945 14.5191C14.8072 13.1227 15.68 11.0718 15.68 8.63547C15.68 8.0682 15.6291 7.5227 15.5345 6.99911L8 6.99902Z" fill="#4285F4"/> +<path d="M3.51649 9.97632L2.93092 10.4246L0.858154 12.0391C2.17451 14.65 4.8725 16.4536 7.99974 16.4536C10.1597 16.4536 11.9706 15.7409 13.2942 14.5191L10.6979 12.5046C9.98516 12.9846 9.07606 13.2755 7.99974 13.2755C5.91976 13.2755 4.15254 11.8719 3.51976 9.98094L3.51649 9.97632Z" fill="#34A853"/> +<path d="M0.858119 4.86816C0.312695 5.94448 0 7.15905 0 8.45357C0 9.74809 0.312695 10.9627 0.858119 12.039C0.858119 12.0462 3.51998 9.97352 3.51998 9.97352C3.35998 9.49352 3.26541 8.98446 3.26541 8.45349C3.26541 7.92251 3.35998 7.41345 3.51998 6.93345L0.858119 4.86816Z" fill="#FBBC05"/> +<path d="M7.99991 3.63907C9.17811 3.63907 10.2254 4.04633 11.0617 4.83179L13.3526 2.54091C11.9635 1.24639 10.1599 0.453613 7.99991 0.453613C4.87266 0.453613 2.17451 2.24997 0.858154 4.86816L3.51994 6.93362C4.15263 5.04269 5.91992 3.63907 7.99991 3.63907Z" fill="#EA4335"/> +</g> +<defs> +<clipPath id="clip0_660_28"> +<rect width="16" height="16" fill="white" transform="translate(0 0.453613)"/> +</clipPath> +</defs> +</svg> diff --git a/web/src/icons/moonshot.svg b/web/src/assets/svg/llm/moonshot.svg similarity index 100% rename from web/src/icons/moonshot.svg rename to web/src/assets/svg/llm/moonshot.svg diff --git a/web/src/assets/svg/llm/ollama.svg b/web/src/assets/svg/llm/ollama.svg new file mode 100644 index 0000000000000000000000000000000000000000..6e9fb283c01ac55c929b4adcc57ec58c23a0fb3b --- /dev/null +++ b/web/src/assets/svg/llm/ollama.svg @@ -0,0 +1,9 @@ +<svg width="133" height="185" viewBox="0 0 133 185" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<rect width="133" height="185" fill="url(#pattern0)"/> +<defs> +<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1"> +<use xlink:href="#image0_406_1657" transform="matrix(0.00552486 0 0 0.00397193 0 -0.00840675)"/> +</pattern> +<image id="image0_406_1657" width="181" height="256" xlink:href="data:image/png;base64,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"/> +</defs> +</svg> diff --git a/web/src/icons/openai.svg b/web/src/assets/svg/llm/openai.svg similarity index 100% rename from web/src/icons/openai.svg rename to web/src/assets/svg/llm/openai.svg diff --git a/web/src/icons/tongyi.svg b/web/src/assets/svg/llm/tongyi.svg similarity index 100% rename from web/src/icons/tongyi.svg rename to web/src/assets/svg/llm/tongyi.svg diff --git a/web/src/icons/wenxin.svg b/web/src/assets/svg/llm/wenxin.svg similarity index 100% rename from web/src/icons/wenxin.svg rename to web/src/assets/svg/llm/wenxin.svg diff --git a/web/src/icons/zhipu.svg b/web/src/assets/svg/llm/zhipu.svg similarity index 100% rename from web/src/icons/zhipu.svg rename to web/src/assets/svg/llm/zhipu.svg diff --git a/web/src/components/svg-icon.tsx b/web/src/components/svg-icon.tsx index f740f2c9c3ece90c021ee63b092214f22cdc3483..2171fc42cc17898e59a55b1f0a57acc4bbdb1eea 100644 --- a/web/src/components/svg-icon.tsx +++ b/web/src/components/svg-icon.tsx @@ -21,13 +21,16 @@ try { interface IProps extends IconComponentProps { name: string; width: string | number; + height?: string | number; } -const SvgIcon = ({ name, width, ...restProps }: IProps) => { +const SvgIcon = ({ name, width, height, ...restProps }: IProps) => { const ListItem = routeList.find((item) => item.name === name); return ( <Icon - component={() => <img src={ListItem?.value} alt="" width={width} />} + component={() => ( + <img src={ListItem?.value} alt="" width={width} height={height} /> + )} {...(restProps as any)} /> ); diff --git a/web/src/hooks/llmHooks.ts b/web/src/hooks/llmHooks.ts index 3e2e75709fbeb37dcc79fe4126366ee2750d17f0..9068ebd43e0e7fdf2280452e7769f3d2fe7c512d 100644 --- a/web/src/hooks/llmHooks.ts +++ b/web/src/hooks/llmHooks.ts @@ -4,6 +4,7 @@ import { IMyLlmValue, IThirdOAIModelCollection, } from '@/interfaces/database/llm'; +import { IAddLlmRequestBody } from '@/interfaces/request/llm'; import { useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'umi'; @@ -206,3 +207,19 @@ export const useSaveTenantInfo = () => { return saveTenantInfo; }; + +export const useAddLlm = () => { + const dispatch = useDispatch(); + + const saveTenantInfo = useCallback( + (requestBody: IAddLlmRequestBody) => { + return dispatch<any>({ + type: 'settingModel/add_llm', + payload: requestBody, + }); + }, + [dispatch], + ); + + return saveTenantInfo; +}; diff --git a/web/src/interfaces/common.ts b/web/src/interfaces/common.ts index 518d077c04a07163e1ca7e5aed63873f3f4de644..76a385fee5c7121569f4e7f28020cfc5df5e9dbf 100644 --- a/web/src/interfaces/common.ts +++ b/web/src/interfaces/common.ts @@ -7,3 +7,11 @@ export interface BaseState { pagination: Pagination; searchString: string; } + +export interface IModalProps<T> { + showModal?(): void; + hideModal(): void; + visible: boolean; + loading?: boolean; + onOk?(payload?: T): Promise<void> | void; +} diff --git a/web/src/interfaces/request/llm.ts b/web/src/interfaces/request/llm.ts new file mode 100644 index 0000000000000000000000000000000000000000..0505c0a474c5a0fa33a4f26daaea21451b8ed395 --- /dev/null +++ b/web/src/interfaces/request/llm.ts @@ -0,0 +1,6 @@ +export interface IAddLlmRequestBody { + llm_factory: string; // Ollama + llm_name: string; + model_type: string; + api_base?: string; // chat|embedding|speech2text|image2text +} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 661af3ca571073b2b0f9a448d9415017be30ed08..b6d1cec1fc1aa2504818bb326f289149f273c793 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -390,6 +390,14 @@ export default { 'The default ASR model all the newly created knowledgebase will use. Use this model to translate voices to corresponding text.', workspace: 'Workspace', upgrade: 'Upgrade', + addLlmTitle: 'Add LLM', + modelName: 'Model name', + modelNameMessage: 'Please input your model name!', + modelType: 'Model type', + modelTypeMessage: 'Please input your model type!', + addLlmBaseUrl: 'Base url', + baseUrlNameMessage: 'Please input your base url!', + vision: 'Does it support Vision?', }, message: { registered: 'Registered!', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index e2165ea72893cc55b66fea645b16ca4cd654559d..a8b18fb36c3f284f696331d77243bad32a83ff73 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -375,6 +375,14 @@ export default { '所有新ĺ›ĺ»şçš„知识库é˝ĺ°†ä˝żç”¨é»č®¤çš„ ASR 模型。 使用ć¤ć¨ˇĺž‹ĺ°†čŻéźłçż»čŻ‘ä¸şç›¸ĺş”çš„ć–‡ćś¬ă€‚', workspace: '工作空间', upgrade: '升级', + addLlmTitle: 'ć·»ĺŠ LLM', + modelName: '模型ĺŤç§°', + modelType: '模型类型', + addLlmBaseUrl: '基础 Url', + vision: 'ćŻĺ¦ć”ŻćŚ Vision', + modelNameMessage: '请输入模型ĺŤç§°ďĽ', + modelTypeMessage: '请输入模型类型ďĽ', + baseUrlNameMessage: '请输入基础 UrlďĽ', }, message: { registered: '注册ć功', diff --git a/web/src/pages/user-setting/model.ts b/web/src/pages/user-setting/model.ts index fa4add77b32754c872c5f1911cba657c00736d01..da2ceed7d40a283419ac4e31d9c297c5be0a550d 100644 --- a/web/src/pages/user-setting/model.ts +++ b/web/src/pages/user-setting/model.ts @@ -151,6 +151,17 @@ const model: DvaModel<SettingModelState> = { } return retcode; }, + *add_llm({ payload = {} }, { call, put }) { + const { data } = yield call(userService.add_llm, payload); + const { retcode } = data; + if (retcode === 0) { + message.success(i18n.t('message.modified')); + + yield put({ type: 'my_llm' }); + yield put({ type: 'factories_list' }); + } + return retcode; + }, }, }; export default model; diff --git a/web/src/pages/user-setting/setting-model/api-key-modal/index.tsx b/web/src/pages/user-setting/setting-model/api-key-modal/index.tsx index 7a4850797168d7a668b60f4414be141124c9e14d..f841cba06b34db54201f141c00e6e23951e07b22 100644 --- a/web/src/pages/user-setting/setting-model/api-key-modal/index.tsx +++ b/web/src/pages/user-setting/setting-model/api-key-modal/index.tsx @@ -46,8 +46,10 @@ const ApiKeyModal = ({ }; useEffect(() => { - form.setFieldValue('api_key', initialValue); - }, [initialValue, form]); + if (visible) { + form.setFieldValue('api_key', initialValue); + } + }, [initialValue, form, visible]); return ( <Modal diff --git a/web/src/pages/user-setting/setting-model/hooks.ts b/web/src/pages/user-setting/setting-model/hooks.ts index f36aa02d6bc80a219f18bb1e10a62a373b3d1ef7..5e9bd8c351fdbb700f972980fc9f48244df8272b 100644 --- a/web/src/pages/user-setting/setting-model/hooks.ts +++ b/web/src/pages/user-setting/setting-model/hooks.ts @@ -2,6 +2,7 @@ import { useSetModalState } from '@/hooks/commonHooks'; import { IApiKeySavingParams, ISystemModelSettingSavingParams, + useAddLlm, useFetchLlmList, useSaveApiKey, useSaveTenantInfo, @@ -12,6 +13,7 @@ import { useFetchTenantInfo, useSelectTenantInfo, } from '@/hooks/userSettingHook'; +import { IAddLlmRequestBody } from '@/interfaces/request/llm'; import { useCallback, useEffect, useState } from 'react'; type SavingParamsState = Omit<IApiKeySavingParams, 'api_key'>; @@ -127,3 +129,31 @@ export const useSelectModelProvidersLoading = () => { return loading; }; + +export const useSubmitOllama = () => { + const loading = useOneNamespaceEffectsLoading('settingModel', ['add_llm']); + const addLlm = useAddLlm(); + const { + visible: llmAddingVisible, + hideModal: hideLlmAddingModal, + showModal: showLlmAddingModal, + } = useSetModalState(); + + const onLlmAddingOk = useCallback( + async (payload: IAddLlmRequestBody) => { + const ret = await addLlm(payload); + if (ret === 0) { + hideLlmAddingModal(); + } + }, + [hideLlmAddingModal, addLlm], + ); + + return { + llmAddingLoading: loading, + onLlmAddingOk, + llmAddingVisible, + hideLlmAddingModal, + showLlmAddingModal, + }; +}; diff --git a/web/src/pages/user-setting/setting-model/index.tsx b/web/src/pages/user-setting/setting-model/index.tsx index 03dd050d7461444edf57ec414beaa45db5c38335..272ffb5bcd9152ad1ea9624133ecc27c40767923 100644 --- a/web/src/pages/user-setting/setting-model/index.tsx +++ b/web/src/pages/user-setting/setting-model/index.tsx @@ -1,15 +1,11 @@ import { ReactComponent as MoreModelIcon } from '@/assets/svg/more-model.svg'; +import SvgIcon from '@/components/svg-icon'; import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; import { LlmItem, useFetchLlmFactoryListOnMount, useFetchMyLlmListOnMount, } from '@/hooks/llmHooks'; -import { ReactComponent as MoonshotIcon } from '@/icons/moonshot.svg'; -import { ReactComponent as OpenAiIcon } from '@/icons/openai.svg'; -import { ReactComponent as TongYiIcon } from '@/icons/tongyi.svg'; -import { ReactComponent as WenXinIcon } from '@/icons/wenxin.svg'; -import { ReactComponent as ZhiPuIcon } from '@/icons/zhipu.svg'; import { SettingOutlined, UserOutlined } from '@ant-design/icons'; import { Avatar, @@ -33,24 +29,27 @@ import ApiKeyModal from './api-key-modal'; import { useSelectModelProvidersLoading, useSubmitApiKey, + useSubmitOllama, useSubmitSystemModelSetting, } from './hooks'; -import SystemModelSettingModal from './system-model-setting-modal'; - import styles from './index.less'; +import OllamaModal from './ollama-modal'; +import SystemModelSettingModal from './system-model-setting-modal'; const IconMap = { - 'Tongyi-Qianwen': TongYiIcon, - Moonshot: MoonshotIcon, - OpenAI: OpenAiIcon, - 'ZHIPU-AI': ZhiPuIcon, - ć–‡ĺżä¸€č¨€: WenXinIcon, + 'Tongyi-Qianwen': 'tongyi', + Moonshot: 'moonshot', + OpenAI: 'openai', + 'ZHIPU-AI': 'zhipu', + ć–‡ĺżä¸€č¨€: 'wenxin', + Ollama: 'ollama', }; const LlmIcon = ({ name }: { name: string }) => { - const Icon = IconMap[name as keyof typeof IconMap]; - return Icon ? ( - <Icon width={48} height={48}></Icon> + const icon = IconMap[name as keyof typeof IconMap]; + + return icon ? ( + <SvgIcon name={`llm/${icon}`} width={48} height={48}></SvgIcon> ) : ( <Avatar shape="square" size="large" icon={<UserOutlined />} /> ); @@ -90,7 +89,7 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => { <Col span={12} className={styles.factoryOperationWrapper}> <Space size={'middle'}> <Button onClick={handleApiKeyClick}> - API-Key + {item.name === 'Ollama' ? t('addTheModel') : 'API-Key'} <SettingOutlined /> </Button> <Button onClick={handleShowMoreClick}> @@ -142,16 +141,31 @@ const UserSettingModel = () => { showSystemSettingModal, } = useSubmitSystemModelSetting(); const { t } = useTranslate('setting'); + const { + llmAddingVisible, + hideLlmAddingModal, + showLlmAddingModal, + onLlmAddingOk, + llmAddingLoading, + } = useSubmitOllama(); const handleApiKeyClick = useCallback( (llmFactory: string) => { - showApiKeyModal({ llm_factory: llmFactory }); + if (llmFactory === 'Ollama') { + showLlmAddingModal(); + } else { + showApiKeyModal({ llm_factory: llmFactory }); + } }, - [showApiKeyModal], + [showApiKeyModal, showLlmAddingModal], ); const handleAddModel = (llmFactory: string) => () => { - handleApiKeyClick(llmFactory); + if (llmFactory === 'Ollama') { + showLlmAddingModal(); + } else { + handleApiKeyClick(llmFactory); + } }; const items: CollapseProps['items'] = [ @@ -216,7 +230,7 @@ const UserSettingModel = () => { clickButton={showSystemSettingModal} ></SettingTitle> <Divider></Divider> - <Collapse defaultActiveKey={['1']} ghost items={items} /> + <Collapse defaultActiveKey={['1', '2']} ghost items={items} /> </section> </Spin> <ApiKeyModal @@ -233,6 +247,12 @@ const UserSettingModel = () => { hideModal={hideSystemSettingModal} loading={saveSystemModelSettingLoading} ></SystemModelSettingModal> + <OllamaModal + visible={llmAddingVisible} + hideModal={hideLlmAddingModal} + onOk={onLlmAddingOk} + loading={llmAddingLoading} + ></OllamaModal> </> ); }; diff --git a/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx b/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..797de714ff387c646fd2006432f5ad0867653b61 --- /dev/null +++ b/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx @@ -0,0 +1,96 @@ +import { useTranslate } from '@/hooks/commonHooks'; +import { IModalProps } from '@/interfaces/common'; +import { IAddLlmRequestBody } from '@/interfaces/request/llm'; +import { Form, Input, Modal, Select, Switch } from 'antd'; +import omit from 'lodash/omit'; + +type FieldType = IAddLlmRequestBody & { vision: boolean }; + +const { Option } = Select; + +const OllamaModal = ({ + visible, + hideModal, + onOk, + loading, +}: IModalProps<IAddLlmRequestBody>) => { + const [form] = Form.useForm<FieldType>(); + + const { t } = useTranslate('setting'); + + const handleOk = async () => { + const values = await form.validateFields(); + const modelType = + values.model_type === 'chat' && values.vision + ? 'image2text' + : values.model_type; + + const data = { + ...omit(values, ['vision']), + model_type: modelType, + llm_factory: 'Ollama', + }; + console.info(data); + + onOk?.(data); + }; + + return ( + <Modal + title={t('addLlmTitle')} + open={visible} + onOk={handleOk} + onCancel={hideModal} + okButtonProps={{ loading }} + > + <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('modelNameMessage') }]} + > + <Input placeholder={t('modelNameMessage')} /> + </Form.Item> + <Form.Item<FieldType> + label={t('addLlmBaseUrl')} + name="api_base" + rules={[{ required: true, message: t('baseUrlNameMessage') }]} + > + <Input placeholder={t('baseUrlNameMessage')} /> + </Form.Item> + <Form.Item noStyle dependencies={['model_type']}> + {({ getFieldValue }) => + getFieldValue('model_type') === 'chat' && ( + <Form.Item + label={t('vision')} + valuePropName="checked" + name={'vision'} + > + <Switch /> + </Form.Item> + ) + } + </Form.Item> + </Form> + </Modal> + ); +}; + +export default OllamaModal; diff --git a/web/src/pages/user-setting/setting-model/system-model-setting-modal/index.tsx b/web/src/pages/user-setting/setting-model/system-model-setting-modal/index.tsx index 53ee20631e02d63037b13b5b8db26e4bd50f0ace..e3a8149ddea7cf62144d0b320024892aa171b654 100644 --- a/web/src/pages/user-setting/setting-model/system-model-setting-modal/index.tsx +++ b/web/src/pages/user-setting/setting-model/system-model-setting-modal/index.tsx @@ -30,8 +30,10 @@ const SystemModelSettingModal = ({ }; useEffect(() => { - form.setFieldsValue(initialValues); - }, [form, initialValues]); + if (visible) { + form.setFieldsValue(initialValues); + } + }, [form, initialValues, visible]); const onFormLayoutChange = () => {}; diff --git a/web/src/services/userService.ts b/web/src/services/userService.ts index 665a7d5876bdfe70c391b9561e3357bcfed577f8..9f255168a28613192e9055fa18465b47966cf662 100644 --- a/web/src/services/userService.ts +++ b/web/src/services/userService.ts @@ -14,6 +14,7 @@ const { my_llm, set_api_key, set_tenant_info, + add_llm, } = api; const methods = { @@ -61,6 +62,10 @@ const methods = { url: set_api_key, method: 'post', }, + add_llm: { + url: add_llm, + method: 'post', + }, } as const; const userService = registerServer<keyof typeof methods>(methods, request); diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index e64c1697a703f10e239ff8bd8feb80305db8b8ad..54b1b1263abcf27bbf2adc8a06790306a15197f6 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -17,6 +17,7 @@ export default { llm_list: `${api_host}/llm/list`, my_llm: `${api_host}/llm/my_llms`, set_api_key: `${api_host}/llm/set_api_key`, + add_llm: `${api_host}/llm/add_llm`, //çźĄčŻ†ĺş“ç®ˇç† kb_list: `${api_host}/kb/list`,