From 5846f6e0c41a54c3f73455dbeec34792843472a4 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Thu, 7 May 2026 00:05:35 +0800 Subject: [PATCH] =?UTF-8?q?perf=EF=BC=9A=E4=BC=98=E5=8C=96webui=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E4=BD=93=E9=AA=8C=EF=BC=8C=E4=BC=98=E5=8C=96=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98=E5=8C=96log?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamic-form/DynamicConfigForm.tsx | 123 +++-- .../components/dynamic-form/DynamicField.tsx | 4 +- dashboard/src/components/layout/LogoArea.tsx | 78 ++- .../src/components/ui/extra-params-dialog.tsx | 8 +- .../components/ui/nested-key-value-editor.tsx | 15 +- dashboard/src/i18n/locales/zh.json | 2 +- dashboard/src/index.css | 24 + dashboard/src/lib/system-api.ts | 28 + dashboard/src/routes/config/bot.tsx | 33 +- .../bot/hooks/ListItemEditorHookFactory.tsx | 27 +- .../config/bot/hooks/complexFieldHooks.tsx | 94 ++++ .../src/routes/config/bot/hooks/index.ts | 2 + .../config/bot/sections/ExpressionSection.tsx | 3 +- dashboard/src/routes/config/model.tsx | 72 ++- .../config/modelProvider/ProviderList.tsx | 37 +- .../src/routes/config/modelProvider/index.tsx | 78 ++- dashboard/src/routes/index.tsx | 169 +++++- pytests/utils_test/statistic_test.py | 8 +- pytests/webui/test_statistics_service.py | 332 ++++++++++++ pytests/webui/test_system_routes.py | 13 + .../core/runtime/sdk_memory_kernel.py | 4 +- src/A_memorix/core/storage/metadata_store.py | 12 +- .../core/utils/web_import_manager.py | 7 +- src/A_memorix/host_service.py | 2 +- src/chat/utils/statistic.py | 98 ++-- src/common/prompt_i18n.py | 2 +- src/config/config.py | 2 +- src/config/official_configs.py | 5 +- src/core/tooling.py | 4 +- src/emoji_system/emoji_manager.py | 7 +- src/main.py | 9 +- src/plugin_runtime/host/message_utils.py | 2 +- src/services/memory_flow_service.py | 27 +- src/services/memory_service.py | 36 +- src/services/statistics_service.py | 491 ++++++++++++++++++ src/webui/routers/chat/service.py | 25 +- src/webui/routers/statistics.py | 342 +----------- src/webui/routers/system.py | 91 +++- src/webui/routers/websocket/manager.py | 6 +- src/webui/routers/websocket/unified.py | 12 +- uv.lock | 8 +- 41 files changed, 1723 insertions(+), 619 deletions(-) create mode 100644 pytests/webui/test_statistics_service.py create mode 100644 pytests/webui/test_system_routes.py create mode 100644 src/services/statistics_service.py diff --git a/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx b/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx index 012c2dbd..ee1d7339 100644 --- a/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx +++ b/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx @@ -5,7 +5,6 @@ import { Button } from '@/components/ui/button' import { Card, CardContent, - CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' @@ -31,20 +30,10 @@ function buildFieldPath(basePath: string, fieldName: string) { return basePath ? `${basePath}.${fieldName}` : fieldName } -function hasTopLevelAdvancedFields(schema: ConfigSchema) { - return schema.fields.some((field) => field.advanced && !schema.nested?.[field.name]) -} - function resolveSectionTitle(schema: ConfigSchema) { return schema.uiLabel || schema.classDoc || schema.className } -function resolveSectionDescription(schema: ConfigSchema, sectionTitle: string) { - return schema.classDoc && schema.classDoc !== sectionTitle - ? schema.classDoc - : undefined -} - function SectionIcon({ iconName }: { iconName?: string }) { if (!iconName) return null const IconComponent = LucideIcons[iconName as keyof typeof LucideIcons] as @@ -54,7 +43,7 @@ function SectionIcon({ iconName }: { iconName?: string }) { return } -function AdvancedSettingsButton({ +export function AdvancedSettingsButton({ active, onClick, }: { @@ -74,51 +63,39 @@ function AdvancedSettingsButton({ } function DynamicConfigSection({ + advancedVisible, basePath, hooks, level, nestedSchema, onChange, - sectionDescription, sectionKey, sectionTitle, values, }: { + advancedVisible: boolean basePath: string hooks: FieldHookRegistry level: number nestedSchema: ConfigSchema onChange: (field: string, value: unknown) => void - sectionDescription?: string sectionKey: string sectionTitle: string values: Record }) { - const [advancedVisible, setAdvancedVisible] = React.useState(false) - const hasAdvanced = hasTopLevelAdvancedFields(nestedSchema) - return ( - +
- {sectionTitle} + {sectionTitle}
- {sectionDescription && ( - {sectionDescription} - )}
- {hasAdvanced && ( - setAdvancedVisible((current) => !current)} - /> - )}
- + @@ -154,8 +131,7 @@ export const DynamicConfigForm: React.FC = ({ advancedVisible, sectionColumns = 1, }) => { - const [localAdvancedVisible, setLocalAdvancedVisible] = React.useState(false) - const resolvedAdvancedVisible = advancedVisible ?? localAdvancedVisible + const resolvedAdvancedVisible = advancedVisible ?? false const fieldMap = React.useMemo( () => new Map(schema.fields.map((field) => [field.name, field])), @@ -230,6 +206,51 @@ export const DynamicConfigForm: React.FC = ({ return hooks.get(fieldPath)?.type === 'replace' } + const schemaHasVisibleContent = React.useCallback( + (targetSchema: ConfigSchema, targetBasePath: string): boolean => { + const targetFields = targetSchema.fields ?? [] + const hasVisibleInlineField = targetFields.some((field) => { + const fieldPath = buildFieldPath(targetBasePath, field.name) + const hookEntry = hooks.get(fieldPath) + + if (hookEntry?.type === 'hidden') { + return false + } + + if (targetSchema.nested?.[field.name] && hookEntry?.type !== 'replace') { + return false + } + + return resolvedAdvancedVisible || !field.advanced + }) + + if (hasVisibleInlineField) { + return true + } + + return Object.entries(targetSchema.nested ?? {}).some(([key, nestedSchema]) => { + const nestedField = targetFields.find((field) => field.name === key) + const nestedFieldPath = buildFieldPath(targetBasePath, key) + const hookEntry = hooks.get(nestedFieldPath) + + if (hookEntry?.type === 'hidden') { + return false + } + + if (nestedField?.advanced && !resolvedAdvancedVisible) { + return false + } + + if (hookEntry?.type === 'replace') { + return true + } + + return schemaHasVisibleContent(nestedSchema, nestedFieldPath) + }) + }, + [hooks, resolvedAdvancedVisible], + ) + const inlineFields = schema.fields.filter(shouldRenderFieldInline) const inlineNestedFieldNames = new Set( inlineFields @@ -302,16 +323,8 @@ export const DynamicConfigForm: React.FC = ({ return (
- {inlineFields.length > 0 && ( + {visibleFields.length > 0 && (
- {advancedVisible === undefined && advancedFields.length > 0 && ( -
- setLocalAdvancedVisible((current) => !current)} - /> -
- )} {renderFieldList(visibleFields)}
)} @@ -327,6 +340,15 @@ export const DynamicConfigForm: React.FC = ({ if (hooks.has(nestedFieldPath)) { const hookEntry = hooks.get(nestedFieldPath) if (!hookEntry) return null + if (hookEntry.type === 'hidden') return null + if (nestedField?.advanced && !resolvedAdvancedVisible) return null + if ( + hookEntry.type !== 'replace' && + nestedSchema && + !schemaHasVisibleContent(nestedSchema, nestedFieldPath) + ) { + return null + } const HookComponent = hookEntry.component if (hookEntry.type === 'replace') { @@ -363,6 +385,7 @@ export const DynamicConfigForm: React.FC = ({ basePath={nestedFieldPath} hooks={hooks} level={level + 1} + advancedVisible={resolvedAdvancedVisible} sectionColumns={1} /> @@ -371,12 +394,15 @@ export const DynamicConfigForm: React.FC = ({ } const sectionTitle = resolveSectionTitle(nestedSchema) - const sectionDescription = resolveSectionDescription(nestedSchema, sectionTitle) + if (!schemaHasVisibleContent(nestedSchema, nestedFieldPath)) { + return null + } if (level === 0) { return ( ) || {}} onChange={onChange} @@ -385,29 +411,23 @@ export const DynamicConfigForm: React.FC = ({ level={level + 1} sectionKey={key} sectionTitle={sectionTitle} - sectionDescription={sectionDescription} /> ) } return ( - +
- {sectionTitle} + {sectionTitle}
- {sectionDescription && ( - - {sectionDescription} - - )}
- + ) || {}} @@ -415,6 +435,7 @@ export const DynamicConfigForm: React.FC = ({ basePath={nestedFieldPath} hooks={hooks} level={level + 1} + advancedVisible={resolvedAdvancedVisible} sectionColumns={1} /> diff --git a/dashboard/src/components/dynamic-form/DynamicField.tsx b/dashboard/src/components/dynamic-form/DynamicField.tsx index 0e6156fc..cfd6171a 100644 --- a/dashboard/src/components/dynamic-form/DynamicField.tsx +++ b/dashboard/src/components/dynamic-form/DynamicField.tsx @@ -158,10 +158,10 @@ export const DynamicField: React.FC = ({ const label = (