From ee5c30934bbc0ef016e284f0268e4852f380fde9 Mon Sep 17 00:00:00 2001 From: jialin Date: Tue, 11 Nov 2025 11:36:00 +0800 Subject: [PATCH] feat: generic_proxy --- src/components/icon-font/icons.ts | 4 +- src/components/icon-font/index.tsx | 2 +- src/hooks/use-table-fetch.ts | 11 +++ src/locales/en-US/models.ts | 5 +- src/locales/ja-JP/models.ts | 10 ++- src/locales/ru-RU/models.ts | 10 ++- src/locales/zh-CN/models.ts | 5 +- src/pages/cluster-management/credentials.tsx | 2 +- src/pages/llmodels/config/button-actions.ts | 7 +- src/pages/llmodels/config/types.ts | 1 + src/pages/llmodels/forms/advance-config.tsx | 15 +++- src/pages/llmodels/forms/schedule-type.tsx | 2 +- .../llmodels/hooks/use-generic-proxy.tsx | 76 +++++++++++++++++++ 13 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 src/pages/llmodels/hooks/use-generic-proxy.tsx diff --git a/src/components/icon-font/icons.ts b/src/components/icon-font/icons.ts index c0ddce6b..119d661a 100644 --- a/src/components/icon-font/icons.ts +++ b/src/components/icon-font/icons.ts @@ -56,7 +56,9 @@ const icons = { type: 'icon-lock_open_right' }), LockPerson: React.createElement(IconFont, { type: 'icon-lock_person' }), - LockOpen: React.createElement(IconFont, { type: 'icon-lock_open' }) + LockOpen: React.createElement(IconFont, { type: 'icon-lock_open' }), + Permission: React.createElement(IconFont, { type: 'icon-permission' }), + CaptivePortal: React.createElement(IconFont, { type: 'icon-captive_portal' }) }; export default icons; diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index afb6996f..a97d2e79 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; // import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_ipdaaask7g.js' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_ga8perwfeom.js' }); export default IconFont; diff --git a/src/hooks/use-table-fetch.ts b/src/hooks/use-table-fetch.ts index 76d68239..519a4bdb 100644 --- a/src/hooks/use-table-fetch.ts +++ b/src/hooks/use-table-fetch.ts @@ -14,6 +14,17 @@ type WatchConfig = | { watch: true; API: string; polling?: false | undefined } | { polling: true; watch: false | undefined; API?: string }; +/** + * + * @param contentForDelete i18n key for delete confirmation modal content + * @param fetchAPI API function to fetch data, should return a promise with Global.PageResponse + * @param deleteAPI API function to delete an item, should return a promise + * @param defaultData default data list + * @param events events to watch for chunked updates, default: ['UPDATE', 'DELETE'] + * @param defaultQueryParams default query parameters for fetching data + * @param isInfiniteScroll whether to use infinite scroll mode , use in card list + * @returns + */ export default function useTableFetch( options: { fetchAPI: (params: any) => Promise>; diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts index 36b42350..128a94d1 100644 --- a/src/locales/en-US/models.ts +++ b/src/locales/en-US/models.ts @@ -244,5 +244,8 @@ export default { 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.', 'models.catalog.button.explore': 'Explore Other Models', 'models.catalog.precision': 'Precision', - 'models.form.gpuPerReplica.tips': 'Enter a custom number' + 'models.form.gpuPerReplica.tips': 'Enter a custom number', + 'models.form.generic_proxy': 'Enable Generic Proxy', + 'models.form.generic_proxy.tips': 'Enable Generic Proxy', + 'models.form.generic_proxy.button': 'Generic Proxy' }; diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts index b570d6ee..73003c0e 100644 --- a/src/locales/ja-JP/models.ts +++ b/src/locales/ja-JP/models.ts @@ -244,7 +244,10 @@ export default { 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.', 'models.catalog.button.explore': 'Explore Other Models', 'models.catalog.precision': 'Precision', - 'models.form.gpuPerReplica.tips': 'Enter a custom number' + 'models.form.gpuPerReplica.tips': 'Enter a custom number', + 'models.form.generic_proxy': 'Enable Generic Proxy', + 'models.form.generic_proxy.tips': 'Enable Generic Proxy', + 'models.form.generic_proxy.button': 'Generic Proxy' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -316,6 +319,9 @@ export default { // 49. 'models.form.rules.name': 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.', // 50. 'models.catalog.button.explore': 'Explore Other Models', // 51. 'models.catalog.precision': 'Precision', -// 52. 'models.form.gpuPerReplica.tips': 'Enter a custom number' +// 52. 'models.form.gpuPerReplica.tips': 'Enter a custom number', +// 53. 'models.form.generic_proxy': 'Enable Generic Proxy', +// 54. 'models.form.generic_proxy.tips': 'Enable Generic Proxy', +// 55. 'models.form.generic_proxy.button': 'Generic Proxy' // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index bb920470..97759936 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -245,10 +245,16 @@ export default { 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.', 'models.catalog.button.explore': 'Изучить другие модели', 'models.catalog.precision': 'Точность', - 'models.form.gpuPerReplica.tips': 'Enter a custom number' + 'models.form.gpuPerReplica.tips': 'Enter a custom number', + 'models.form.generic_proxy': 'Enable Generic Proxy', + 'models.form.generic_proxy.tips': 'Enable Generic Proxy', + 'models.form.generic_proxy.button': 'Generic Proxy' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== // 1. 'models.form.rules.name': 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.', -// 2. 'models.form.gpuPerReplica.tips': 'Enter a custom number' +// 2. 'models.form.gpuPerReplica.tips': 'Enter a custom number', +// 3. 'models.form.generic_proxy': 'Enable Generic Proxy', +// 4. 'models.form.generic_proxy.tips': 'Enable Generic Proxy', +// 5. 'models.form.generic_proxy.button': 'Generic Proxy' // ========== End of To-Do List ========== diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts index 8e5c04ed..fc175c0a 100644 --- a/src/locales/zh-CN/models.ts +++ b/src/locales/zh-CN/models.ts @@ -231,5 +231,8 @@ export default { '长度不超过 63 个字符,只能包含字母、数字、点(.)、下划线(_)和连字符(-),且必须以字母或数字开头和结尾。', 'models.catalog.button.explore': '浏览其他模型', 'models.catalog.precision': '精度', - 'models.form.gpuPerReplica.tips': '输入自定义数值' + 'models.form.gpuPerReplica.tips': '输入自定义数值', + 'models.form.generic_proxy': '启用通用代理', + 'models.form.generic_proxy.tips': '启用通用代理', + 'models.form.generic_proxy.button': '通用代理' }; diff --git a/src/pages/cluster-management/credentials.tsx b/src/pages/cluster-management/credentials.tsx index a774baab..eb018429 100644 --- a/src/pages/cluster-management/credentials.tsx +++ b/src/pages/cluster-management/credentials.tsx @@ -28,7 +28,7 @@ import useCredentialColumns from './hooks/use-credential-columns'; const addActions = [ { - label: 'Digital Ocean', + label: 'DigitalOcean', locale: false, key: ProviderValueMap.DigitalOcean, value: ProviderValueMap.DigitalOcean, diff --git a/src/pages/llmodels/config/button-actions.ts b/src/pages/llmodels/config/button-actions.ts index 89d8a8b9..3e7b1502 100644 --- a/src/pages/llmodels/config/button-actions.ts +++ b/src/pages/llmodels/config/button-actions.ts @@ -50,6 +50,11 @@ export const ActionList: ActionItem[] = [ key: 'chat', icon: icons.ExperimentOutlined }, + // { + // label: 'models.form.generic_proxy.button', + // key: 'proxy', + // icon: icons.CaptivePortal + // }, { label: 'models.table.button.apiAccessInfo', key: 'api', @@ -68,7 +73,7 @@ export const ActionList: ActionItem[] = [ { label: 'models.button.accessSettings', key: 'accessControl', - icon: icons.Private + icon: icons.Permission }, { label: 'common.button.delete', diff --git a/src/pages/llmodels/config/types.ts b/src/pages/llmodels/config/types.ts index 532ef75d..1b75540e 100644 --- a/src/pages/llmodels/config/types.ts +++ b/src/pages/llmodels/config/types.ts @@ -60,6 +60,7 @@ export interface FormData { local_path?: string; model_scope_model_id?: string; model_scope_file_path?: string; + generic_proxy?: boolean; gpu_selector?: { gpu_ids?: string[]; gpu_type?: string; diff --git a/src/pages/llmodels/forms/advance-config.tsx b/src/pages/llmodels/forms/advance-config.tsx index b40f01c2..2e45304d 100644 --- a/src/pages/llmodels/forms/advance-config.tsx +++ b/src/pages/llmodels/forms/advance-config.tsx @@ -25,7 +25,6 @@ const AdvanceConfig = () => { }, [backend, backendOptions]); const handleEnviromentVarsChange = (labels: Record) => { - console.log('handleEnviromentVarsChange', labels); form.setFieldValue('env', labels); }; @@ -134,6 +133,20 @@ const AdvanceConfig = () => { })} > + {/* + name="generic_proxy" + valuePropName="checked" + style={{ marginBottom: 8 }} + > + + */} ); }; diff --git a/src/pages/llmodels/forms/schedule-type.tsx b/src/pages/llmodels/forms/schedule-type.tsx index 9892f879..b7e58ca6 100644 --- a/src/pages/llmodels/forms/schedule-type.tsx +++ b/src/pages/llmodels/forms/schedule-type.tsx @@ -220,7 +220,7 @@ const ScheduleTypeForm: React.FC = () => { ) => { + const host = window.location.origin; + const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API); + + // ========================= Curl ========================= + const curlCode = ` +curl ${host}${api} \\ +-H "Content-Type: application/json" \\ +-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ +${formatCurlArgs(parameters, false)}`.trim(); +}; + +const useGenericProxy = () => { + const intl = useIntl(); + const [modalStatus, setModalStatus] = useState<{ + open: boolean; + codeValue: string; + }>({ open: false, codeValue: '' }); + + const onCancel = () => { + setModalStatus({ + open: false, + codeValue: '' + }); + }; + + const openProxyModal = (data?: any) => { + setModalStatus({ + open: true, + codeValue: data?.generic_proxy_command || '' + }); + }; + + const GenericProxyModal = () => { + return ( + + + + ); + }; + + return { + GenericProxyModal, + openProxyModal, + setModalStatus + }; +}; + +export default useGenericProxy;