From 62b77cc9fa5c6bf9a5ee295d51ca17064b9d20d4 Mon Sep 17 00:00:00 2001 From: scarqin Date: Tue, 7 Jan 2025 17:21:21 +0800 Subject: [PATCH 1/6] fix: error line --- .../core/src/pages/aiSetting/AIFlowChart.tsx | 48 +++++++++++++++---- .../pages/aiSetting/components/CustomEdge.tsx | 10 +++- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx index b61d82da..8ea31773 100644 --- a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx +++ b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx @@ -39,6 +39,7 @@ const calculateNodePositions = (models: ModelListData[], startY = LAYOUT.NODE_ST return models.reduce( (acc, model, index) => { const y = startY + index * gap + return { ...acc, [model.id]: { @@ -134,15 +135,46 @@ const AIFlowChart = () => { })) ] + const successModel = modelData.find((model) => model.status !== 'abnormal') as ModelListData const newEdges: any = [ - ...modelData.map((model) => ({ - id: `service-${model.id}`, - source: 'apiService', - target: model.id, - label: `${model.api_count} apis`, - data: { id: model.id }, - animated: true - })), + ...modelData.flatMap((model, modelIndex) => { + if (model.status === 'enabled') { + return [ + { + id: `service-${model.id}`, + source: 'apiService', + target: model.id, + label: `${model.api_count} apis`, + data: { + id: model.id, + offset: modelIndex * 20 // Add vertical offset based on model index + }, + animated: true, + style: { stroke: '#52c41a' } + } + ] + } else { + return [ + { + id: `service-${model.id}-failed`, + source: 'apiService', + target: model.id, + label: ``, + data: { id: model.id }, + style: { stroke: '#ff4d4f' } + }, + { + id: `service-${model.id}-backup`, + source: 'apiService', + target: successModel.id, + label: 'backup', + data: { id: model.id, isBackup: true }, + animated: true, + style: { stroke: '#52c41a' } + } + ] + } + }), ...modelData.map((model) => ({ id: `${model.id}-keys-edge`, source: model.id, diff --git a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx index 7e350a2c..e7c2d4e6 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx @@ -27,7 +27,14 @@ export default function CustomEdge({ return ( <> - + {label && ( Date: Tue, 7 Jan 2025 17:54:53 +0800 Subject: [PATCH 2/6] fix: When the current supplier is abnormal, there should be a line on the model pointing to the next model, which means that the APIs on this link are associated with the next valid supplier. --- .../core/src/pages/aiSetting/AIFlowChart.tsx | 2 +- .../pages/aiSetting/components/CustomEdge.tsx | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx index 8ea31773..03bd7345 100644 --- a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx +++ b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx @@ -167,7 +167,7 @@ const AIFlowChart = () => { id: `service-${model.id}-backup`, source: 'apiService', target: successModel.id, - label: 'backup', + label: `${model.api_count} apis`, data: { id: model.id, isBackup: true }, animated: true, style: { stroke: '#52c41a' } diff --git a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx index e7c2d4e6..35d585f5 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx @@ -1,4 +1,4 @@ -import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath } from '@xyflow/react' +import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath, useStore } from '@xyflow/react' export default function CustomEdge({ id, @@ -11,14 +11,26 @@ export default function CustomEdge({ style = {}, markerEnd, label, - data + data, + source, + target }: EdgeProps) { - const [edgePath, labelX, labelY] = getSmoothStepPath({ + // Get all edges to check for duplicates + const edges = useStore((state) => state.edges) + + // Find duplicate edges between the same source and target + const duplicateEdges = edges.filter((edge) => edge.source === source && edge.target === target) + const edgeIndex = duplicateEdges.findIndex((edge) => edge.id === id) + + // Adjust the path if this is a duplicate edge + const offset = edgeIndex * 20 // 20px offset for each duplicate edge + + const [edgePath] = getSmoothStepPath({ sourceX, - sourceY, + sourceY: sourceY, sourcePosition, targetX, - targetY, + targetY: targetY + offset, targetPosition, borderRadius: 16 }) @@ -42,7 +54,7 @@ export default function CustomEdge({ target="_blank" style={{ position: 'absolute', - transform: `translate(${targetX - 80}px,${targetY - 20}px)`, + transform: `translate(${targetX - 80}px,${targetY - 20 + offset}px)`, borderRadius: '4px', fontSize: 12, fontWeight: 500, @@ -50,7 +62,6 @@ export default function CustomEdge({ pointerEvents: 'all', textDecoration: 'none' }} - className="nodrag nopan" > {label} From 29c74bbbe196fe74dd38aa08b6e1a113937fb5e6 Mon Sep 17 00:00:00 2001 From: scarqin Date: Tue, 7 Jan 2025 17:56:16 +0800 Subject: [PATCH 3/6] fix: jump link error --- .../core/src/pages/aiApis/aiApisLayout.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx b/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx index 3a67332c..b956887a 100644 --- a/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx +++ b/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx @@ -1,14 +1,15 @@ -import { useEffect } from "react"; -import { Outlet, useLocation, useNavigate } from "react-router-dom"; +import { useEffect } from 'react' +import { Outlet, useLocation, useNavigate } from 'react-router-dom' -export default function GlobalPolicyLayout(){ - const location = useLocation() - const pathName = location.pathname - const navigator = useNavigate() - useEffect(()=>{ - if(pathName === '/aiApis'){ - navigator('/aiApis/list') - } - },[pathName]) - return () -} \ No newline at end of file +export default function GlobalPolicyLayout() { + const location = useLocation() + const pathName = location.pathname + const navigator = useNavigate() + useEffect(() => { + if (pathName === '/aiApis') { + const queryParams = new URLSearchParams(location.search).toString() + navigator(`/aiApis/list${queryParams ? `?${queryParams}` : ''}`) + } + }, [pathName]) + return +} From 28745e81f876ce12077765159b20a9bfeb8558ae Mon Sep 17 00:00:00 2001 From: scarqin Date: Tue, 7 Jan 2025 18:14:25 +0800 Subject: [PATCH 4/6] fix: The language option is wrong. The current language is Chinese, but the option is displayed as English. --- .../components/aoplatform/LanguageSetting.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/frontend/packages/common/src/components/aoplatform/LanguageSetting.tsx b/frontend/packages/common/src/components/aoplatform/LanguageSetting.tsx index c54bc0a4..90a20efa 100644 --- a/frontend/packages/common/src/components/aoplatform/LanguageSetting.tsx +++ b/frontend/packages/common/src/components/aoplatform/LanguageSetting.tsx @@ -1,8 +1,8 @@ -import { Dropdown, Button } from 'antd' -import i18n from '@common/locales' -import { memo, useEffect, useMemo } from 'react' import { useGlobalContext } from '@common/contexts/GlobalStateContext' +import i18n from '@common/locales' import { Icon } from '@iconify/react/dist/iconify.js' +import { Button, Dropdown } from 'antd' +import { memo, useEffect, useMemo } from 'react' const LanguageSetting = ({ mode = 'light' }: { mode?: 'dark' | 'light' }) => { const { dispatch, state } = useGlobalContext() @@ -48,12 +48,17 @@ const LanguageSetting = ({ mode = 'light' }: { mode?: 'dark' | 'light' }) => { const langLabel = useMemo(() => items.find((item) => item?.key === state.language)?.title, [state.language]) useEffect(() => { - const savedLang = sessionStorage.getItem('i18nextLng') - const browserLang = navigator.language || navigator.userLanguage - if (savedLang) return - - dispatch({ type: 'UPDATE_LANGUAGE', language: browserLang }) + const savedLang = i18n.language || sessionStorage.getItem('i18nextLng') + if (savedLang && state.language !== savedLang) { + dispatch({ type: 'UPDATE_LANGUAGE', language: savedLang }) + } else if (!savedLang) { + const browserLang = navigator.language + const supportedLang = items.find((item) => item.key === browserLang) ? browserLang : 'zh-CN' + dispatch({ type: 'UPDATE_LANGUAGE', language: supportedLang }) + i18n.changeLanguage(supportedLang) + } }, []) + return ( { const { key } = e dispatch({ type: 'UPDATE_LANGUAGE', language: key }) i18n.changeLanguage(key) + sessionStorage.setItem('i18nextLng', key) } }} > From a087a535d231e62040aab8a47695dfbe05f57842 Mon Sep 17 00:00:00 2001 From: scarqin Date: Tue, 7 Jan 2025 18:40:43 +0800 Subject: [PATCH 5/6] fix: When the current supplier is abnormal, there should be a line on the model pointing to the next model, which means that the APIs on this link are associated with the next valid supplier. --- .../core/src/pages/aiSetting/AIFlowChart.tsx | 58 ++++++------------- .../aiSetting/components/ModelCardNode.tsx | 8 ++- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx index 03bd7345..dfd90d5c 100644 --- a/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx +++ b/frontend/packages/core/src/pages/aiSetting/AIFlowChart.tsx @@ -39,7 +39,6 @@ const calculateNodePositions = (models: ModelListData[], startY = LAYOUT.NODE_ST return models.reduce( (acc, model, index) => { const y = startY + index * gap - return { ...acc, [model.id]: { @@ -95,6 +94,9 @@ const AIFlowChart = () => { if (!modelData.length) return const positions = calculateNodePositions(modelData) + const firstSuccessModel = modelData.find((model) => model.status === 'enabled') + console.log(firstSuccessModel) + // subtract 5 to make sure the service node is aligned with the top model node const serviceY = positions[modelData[0].id].y - 5 const newNodes = [ @@ -117,7 +119,8 @@ const AIFlowChart = () => { status: model.status, defaultLlm: model.defaultLlm, logo: model.logo, - id: model.id + id: model.id, + alternativeModel: firstSuccessModel } })), ...modelData.map((model) => ({ @@ -135,46 +138,19 @@ const AIFlowChart = () => { })) ] - const successModel = modelData.find((model) => model.status !== 'abnormal') as ModelListData const newEdges: any = [ - ...modelData.flatMap((model, modelIndex) => { - if (model.status === 'enabled') { - return [ - { - id: `service-${model.id}`, - source: 'apiService', - target: model.id, - label: `${model.api_count} apis`, - data: { - id: model.id, - offset: modelIndex * 20 // Add vertical offset based on model index - }, - animated: true, - style: { stroke: '#52c41a' } - } - ] - } else { - return [ - { - id: `service-${model.id}-failed`, - source: 'apiService', - target: model.id, - label: ``, - data: { id: model.id }, - style: { stroke: '#ff4d4f' } - }, - { - id: `service-${model.id}-backup`, - source: 'apiService', - target: successModel.id, - label: `${model.api_count} apis`, - data: { id: model.id, isBackup: true }, - animated: true, - style: { stroke: '#52c41a' } - } - ] - } - }), + ...modelData.map((model) => ({ + id: `service-${model.id}`, + source: 'apiService', + target: model.id, + label: `${model.api_count} apis`, + data: { + id: model.id, + status: model.status + }, + animated: true, + style: { stroke: model.status === 'enabled' ? '#52c41a' : '#ff4d4f' } + })), ...modelData.map((model) => ({ id: `${model.id}-keys-edge`, source: model.id, diff --git a/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx b/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx index 115177e1..c08bac0b 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx @@ -8,10 +8,11 @@ import { AiSettingListItem, ModelDetailData, ModelStatus } from '../types' type ModelCardNodeData = ModelDetailData & { id: string position: { x: number; y: number } + alternativeModel?: ModelDetailData } export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) => { - const { name, status, defaultLlm, logo } = data + const { name, status, defaultLlm, logo, alternativeModel } = data const { openConfigModal } = useAiSetting() const getStatusIcon = (status: ModelStatus) => { @@ -62,6 +63,11 @@ export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) = {$t('默认:')} {defaultLlm} + {status !== 'enabled' && alternativeModel && ( +
+ {$t('关联 API 已转用')} {alternativeModel.name}/{alternativeModel.defaultLlm} +
+ )} ) From 4e2b424eeb050824fc2c1d9a5b56df9b74458113 Mon Sep 17 00:00:00 2001 From: ningyv <1793599591@qq.com> Date: Tue, 21 Jan 2025 11:50:58 +0800 Subject: [PATCH 6/6] chroe: optimize AI model node graphics --- .../aiSetting/components/KeyStatusNode.tsx | 1 + .../aiSetting/components/ModelCardNode.tsx | 74 ++++++++++--------- .../core/src/pages/aiSetting/styles.css | 6 +- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/frontend/packages/core/src/pages/aiSetting/components/KeyStatusNode.tsx b/frontend/packages/core/src/pages/aiSetting/components/KeyStatusNode.tsx index 5420e9fe..ef24aee6 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/KeyStatusNode.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/KeyStatusNode.tsx @@ -27,6 +27,7 @@ export const KeyStatusNode: React.FC<{ data: KeyStatusNodeData }> = ({ data }) =
5 ? '118px' : 'auto', maxWidth: `calc(${MAX_KEYS} * ${KEY_SIZE} + (${MAX_KEYS} - 1) * ${KEY_GAP})`, minHeight: KEY_SIZE }} diff --git a/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx b/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx index c08bac0b..ede8936b 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/ModelCardNode.tsx @@ -29,46 +29,48 @@ export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) = const statusConfig = getStatusIcon(status) return ( -
- - -
-
-
-
- + <> +
+ + +
+
+
+
+ +
+ {name} +
- {name} - -
- {/* Action buttons */} -
- { - openConfigModal({ id: data.id, defaultLlm: defaultLlm } as AiSettingListItem) - }} - /> + {/* Action buttons */} +
+ { + openConfigModal({ id: data.id, defaultLlm: defaultLlm } as AiSettingListItem) + }} + /> +
+
+
+ {$t('默认:')} + {defaultLlm}
-
- {$t('默认:')} - {defaultLlm} -
- {status !== 'enabled' && alternativeModel && ( -
- {$t('关联 API 已转用')} {alternativeModel.name}/{alternativeModel.defaultLlm} -
- )}
-
+ {status !== 'enabled' && alternativeModel && ( +
+ {$t('关联 API 已转用')} {alternativeModel.name}/{alternativeModel.defaultLlm} +
+ )} + ) } diff --git a/frontend/packages/core/src/pages/aiSetting/styles.css b/frontend/packages/core/src/pages/aiSetting/styles.css index 13d5b62b..bd507aa0 100644 --- a/frontend/packages/core/src/pages/aiSetting/styles.css +++ b/frontend/packages/core/src/pages/aiSetting/styles.css @@ -18,11 +18,15 @@ .react-flow__node { padding: 0; border-radius: 8px; - min-width: 150px; width: auto; max-width: 100%; } +.react-flow__node-modelCard, +.react-flow__node-serviceCard { + min-width: 150px; +} + /* Custom Node Styles */ .custom-node { background: white;