feat:合并memory配置,优化webui交互和展示
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Activity, Boxes, Database, FileSearch, FileText, Hash, Home, MessageSquare, Network, Package, ScrollText, Server, Settings, Sliders, Smile } from 'lucide-react'
|
||||
import { Activity, Boxes, Database, FileSearch, FileText, Hash, Home, MessageSquare, Network, Package, ScrollText, Settings, Sliders, Smile } from 'lucide-react'
|
||||
|
||||
import type { MenuSection } from './types'
|
||||
|
||||
@@ -14,7 +14,6 @@ export const menuSections: MenuSection[] = [
|
||||
title: 'sidebar.groups.botConfig',
|
||||
items: [
|
||||
{ icon: FileText, label: 'sidebar.menu.botMainConfig', path: '/config/bot', searchDescription: 'search.items.botConfigDesc' },
|
||||
{ icon: Server, label: 'sidebar.menu.aiModelProvider', path: '/config/modelProvider', searchDescription: 'search.items.modelProviderDesc', tourId: 'sidebar-model-provider' },
|
||||
{ icon: Boxes, label: 'sidebar.menu.modelManagement', path: '/config/model', searchDescription: 'search.items.modelDesc', tourId: 'sidebar-model-management' },
|
||||
{ icon: ScrollText, label: 'sidebar.menu.promptManagement', path: '/config/prompts' },
|
||||
],
|
||||
|
||||
@@ -58,8 +58,8 @@ function unwrapConfigSchema(payload: unknown): ConfigSchema | null {
|
||||
return null
|
||||
}
|
||||
|
||||
function getModelConfigPath(fieldPath: string) {
|
||||
return fieldPath.startsWith('api_providers') ? '/config/modelProvider' : '/config/model'
|
||||
function getModelConfigPath(_fieldPath: string) {
|
||||
return '/config/model'
|
||||
}
|
||||
|
||||
function buildFieldSearchText(field: FieldSchema, fieldPath: string, sectionTitle: string, language?: string) {
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
import type { Step, Placement } from 'react-joyride'
|
||||
import type { Placement, Step } from 'react-joyride'
|
||||
|
||||
export const MODEL_ASSIGNMENT_TOUR_ID = 'model-assignment-tour'
|
||||
|
||||
// Tour 步骤定义
|
||||
export const modelAssignmentTourSteps: Step[] = [
|
||||
// Step 1: 全屏介绍
|
||||
{
|
||||
target: 'body',
|
||||
content: '本引导旨在帮助你配置模型提供商和对应的模型,并为麦麦的各个组件分配合适的模型。',
|
||||
content: '本引导会帮你在同一个页面完成模型厂商、模型列表和功能分配配置。',
|
||||
placement: 'center' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 2: 侧边栏 - 模型提供商按钮(点击下一步会自动导航)
|
||||
{
|
||||
target: '[data-tour="sidebar-model-provider"]',
|
||||
content: '第一步,你需要配置模型提供商。模型提供商决定了你要使用谁家的模型,无论是单一厂商(如 DeepSeek),还是模型平台(如 Siliconflow),都可以在这里进行配置。点击"下一步"进入配置页面。',
|
||||
placement: 'right' as Placement,
|
||||
target: '[data-tour="providers-tab-trigger"]',
|
||||
content: '第一步,进入"模型厂商设置"。这里用于配置要连接的模型服务厂商或模型平台。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 3: 添加提供商按钮
|
||||
{
|
||||
target: '[data-tour="add-provider-button"]',
|
||||
content: '点击"添加提供商"按钮,开始配置你的模型提供商。',
|
||||
content: '点击"添加提供商"按钮,开始配置模型厂商的连接信息。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -35,70 +33,63 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 4: 添加提供商弹窗
|
||||
{
|
||||
target: '[data-tour="provider-dialog"]',
|
||||
content: '在这里,你可以选择你想要配置的模型提供商,填写相关信息后保存即可。',
|
||||
content: '在这里可以选择厂商模板,填写 API Key、URL 和连接参数,保存后即可供模型引用。',
|
||||
placement: 'left' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 5: 名称输入框
|
||||
{
|
||||
target: '[data-tour="provider-name-input"]',
|
||||
content: '这里的名称是你为这个模型提供商起的一个名字,方便你在后续使用时识别它。',
|
||||
content: '这里的名称用于在后续模型配置中识别这个厂商。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 6: API 密钥输入框
|
||||
{
|
||||
target: '[data-tour="provider-apikey-input"]',
|
||||
content: '这里需要填写你从模型提供商那里获取的 API 密钥,用于验证和调用模型服务。对于不同的提供商,获取 API 密钥的方式可能有所不同,请参考对应提供商的文档。',
|
||||
content: '这里填写从模型厂商获取的 API Key,用于验证并调用模型服务。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 7: URL 输入框
|
||||
{
|
||||
target: '[data-tour="provider-url-input"]',
|
||||
content: '这里需要填写模型提供商的 API 访问地址,确保填写正确以便系统能够连接到模型服务。对于不同的提供商,API 地址可能有所不同,请参考对应提供商的文档。',
|
||||
content: '这里填写模型厂商的 API 访问地址。不同厂商或平台的地址可能不同。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 8: 模板选择下拉框
|
||||
{
|
||||
target: '[data-tour="provider-template-select"]',
|
||||
content: '当然,如果你不知道如何填写这些信息,很多模型提供商在这里都提供了预设的模板供你选择,选择对应的模板后,相关信息会自动填充。',
|
||||
content: '如果不确定如何填写,可以从预设模板中选择常用厂商,相关信息会自动填充。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 9: 保存按钮
|
||||
{
|
||||
target: '[data-tour="provider-save-button"]',
|
||||
content: '填写完所有信息后,点击保存按钮,模型提供商就配置完成了。',
|
||||
content: '填写完成后点击保存,模型厂商就配置好了。',
|
||||
placement: 'top' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 10: 取消按钮
|
||||
{
|
||||
target: '[data-tour="provider-cancel-button"]',
|
||||
content: '因为这次咱们什么都没有填写,所以点击取消按钮退出吧。',
|
||||
content: '这次只是演示流程,点击取消关闭厂商配置窗口。',
|
||||
placement: 'top' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -106,20 +97,19 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 11: 侧边栏 - 模型管理与分配按钮(点击下一步会自动导航)
|
||||
{
|
||||
target: '[data-tour="sidebar-model-management"]',
|
||||
content: '配置好模型提供商后,接下来我们需要为麦麦添加模型并分配功能。点击"下一步"进入模型管理页面。',
|
||||
placement: 'right' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 12: 添加模型按钮
|
||||
{
|
||||
target: '[data-tour="add-model-button"]',
|
||||
content: '在为麦麦的组件分配模型之前,首先需要添加你想要分配的模型,点击"添加模型"按钮开始添加。',
|
||||
target: '[data-tour="models-tab-trigger"]',
|
||||
content: '厂商配置完成后,切换到"添加模型",把具体要使用的模型加入列表。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
{
|
||||
target: '[data-tour="add-model-button"]',
|
||||
content: '点击"添加模型"按钮,开始添加一个可分配给功能的模型。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -127,60 +117,54 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 13: 添加模型弹窗
|
||||
{
|
||||
target: '[data-tour="model-dialog"]',
|
||||
content: '在这里,你可以选择你之前配置好的模型提供商,然后选择对应的模型来添加。',
|
||||
content: '在这里选择刚才配置好的厂商,并填写模型名称、标识符、价格和能力参数。',
|
||||
placement: 'left' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 14: 模型名称输入框
|
||||
{
|
||||
target: '[data-tour="model-name-input"]',
|
||||
content: '这里的模型名称是你为这个模型起的一个名字,方便你在后续使用时识别它。',
|
||||
content: '模型名称用于在任务分配时识别这个模型。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 15: API 提供商下拉框
|
||||
{
|
||||
target: '[data-tour="model-provider-select"]',
|
||||
content: '在这里选择你之前配置好的模型提供商,这样系统才能知道你要添加哪个提供商的模型。',
|
||||
content: '这里选择模型所属的厂商,系统会根据厂商配置获取或调用对应模型。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 16: 模型标识符输入框
|
||||
{
|
||||
target: '[data-tour="model-identifier-input"]',
|
||||
content: '这里需要填写你想要添加的模型的标识符,不同的模型提供商可能有不同的标识符格式,请参考对应提供商的文档。',
|
||||
content: '这里填写模型标识符。不同厂商的模型标识符格式可能不同,请参考对应厂商文档。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 17: 保存按钮
|
||||
{
|
||||
target: '[data-tour="model-save-button"]',
|
||||
content: '填写完所有信息后,点击保存按钮,模型就添加完成了。',
|
||||
content: '填写完成后点击保存,模型就会加入可用模型列表。',
|
||||
placement: 'top' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
hideCloseButton: false,
|
||||
spotlightClicks: false,
|
||||
},
|
||||
// Step 18: 取消按钮
|
||||
{
|
||||
target: '[data-tour="model-cancel-button"]',
|
||||
content: '当然,因为这次咱们什么都没有填写,所以直接点击取消按钮退出吧,等你准备好了再来添加模型。',
|
||||
content: '这次只是演示流程,点击取消关闭模型配置窗口。',
|
||||
placement: 'top' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -188,10 +172,9 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 19: 为模型分配功能标签页
|
||||
{
|
||||
target: '[data-tour="tasks-tab-trigger"]',
|
||||
content: '最后一步,添加好模型后,切换到"为模型分配功能"标签页,为麦麦的各个组件分配合适的模型。',
|
||||
content: '最后切换到"为模型分配功能",为麦麦的各个组件选择合适的模型。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -199,10 +182,9 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
spotlightClicks: true,
|
||||
hideFooter: true,
|
||||
},
|
||||
// Step 20: 组件模型卡片的模型选择
|
||||
{
|
||||
target: '[data-tour="task-model-select"]',
|
||||
content: '在这里,你可以为每个组件选择一个或多个合适的模型,选择完成后配置会自动保存。恭喜你完成了模型配置的学习!',
|
||||
content: '在这里可以为每个组件选择一个或多个模型,选择完成后配置会自动保存。',
|
||||
placement: 'bottom' as Placement,
|
||||
disableBeacon: true,
|
||||
disableOverlayClose: true,
|
||||
@@ -212,33 +194,9 @@ export const modelAssignmentTourSteps: Step[] = [
|
||||
]
|
||||
|
||||
// 需要用户点击才能继续的步骤索引(0-based)
|
||||
// Step 2 (index 2): 点击添加提供商按钮
|
||||
// Step 9 (index 9): 点击取消按钮关闭提供商弹窗
|
||||
// Step 11 (index 11): 点击添加模型按钮
|
||||
// Step 17 (index 17): 点击取消按钮关闭模型弹窗
|
||||
// Step 18 (index 18): 点击标签页切换
|
||||
export const CLICK_TO_CONTINUE_STEPS = new Set([2, 9, 11, 17, 18])
|
||||
export const CLICK_TO_CONTINUE_STEPS = new Set([1, 2, 9, 10, 11, 17, 18])
|
||||
|
||||
// 步骤与路由的映射
|
||||
export const STEP_ROUTE_MAP: Record<number, string> = {
|
||||
0: '/config/model', // 起始页面
|
||||
1: '/config/model', // 侧边栏可见
|
||||
2: '/config/modelProvider', // 需要在模型提供商页面
|
||||
3: '/config/modelProvider',
|
||||
4: '/config/modelProvider',
|
||||
5: '/config/modelProvider',
|
||||
6: '/config/modelProvider',
|
||||
7: '/config/modelProvider',
|
||||
8: '/config/modelProvider',
|
||||
9: '/config/modelProvider',
|
||||
10: '/config/modelProvider',
|
||||
11: '/config/model', // 需要在模型管理页面
|
||||
12: '/config/model',
|
||||
13: '/config/model',
|
||||
14: '/config/model',
|
||||
15: '/config/model',
|
||||
16: '/config/model',
|
||||
17: '/config/model',
|
||||
18: '/config/model',
|
||||
19: '/config/model',
|
||||
}
|
||||
// 合并后所有步骤都在模型管理与分配页面内完成
|
||||
export const STEP_ROUTE_MAP: Record<number, string> = Object.fromEntries(
|
||||
modelAssignmentTourSteps.map((_, index) => [index, '/config/model'])
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
@@ -10,7 +10,7 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
"grid place-content-center peer h-4 w-4 shrink-0 cursor-pointer rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -114,7 +114,7 @@ const CommandItem = React.forwardRef<
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"relative flex cursor-pointer gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -18,7 +18,7 @@ const SelectTrigger = React.forwardRef<
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
"flex h-9 w-full cursor-pointer items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -117,7 +117,7 @@ const SelectItem = React.forwardRef<
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-2 pl-2 pr-8 text-sm outline-none bg-white dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-gray-800 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex w-full cursor-pointer select-none items-center rounded-sm py-2 pl-2 pr-8 text-sm outline-none bg-white dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-gray-800 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
||||
"inline-flex cursor-pointer items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user