调整AI自动推理入口文案和图标
- 将左侧工具栏传播入口的可访问名称和 tooltip 从“自动传播”改为“AI自动推理”。 - 新增 AI 大脑样式的 AiAutoInferenceIcon,并替换该入口原本的 AI 智能分割机器人图标。 - 更新 ToolsPalette 和 VideoWorkspace 测试,覆盖新按钮名称和 AI 大脑图标。 - 同步 README、AGENTS、前端审计、API 契约、设计冻结和测试计划文档中的入口描述。
This commit is contained in:
25
src/components/AiAutoInferenceIcon.tsx
Normal file
25
src/components/AiAutoInferenceIcon.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { BrainCircuit, Sparkles } from 'lucide-react';
|
||||
|
||||
interface AiAutoInferenceIconProps {
|
||||
size?: number;
|
||||
strokeWidth?: number;
|
||||
}
|
||||
|
||||
export function AiAutoInferenceIcon({ size = 20, strokeWidth = 2 }: AiAutoInferenceIconProps) {
|
||||
const sparkleSize = Math.max(8, Math.round(size * 0.42));
|
||||
return (
|
||||
<span
|
||||
data-testid="ai-auto-inference-icon"
|
||||
className="relative inline-flex items-center justify-center"
|
||||
style={{ width: size, height: size }}
|
||||
>
|
||||
<BrainCircuit size={size} strokeWidth={strokeWidth} />
|
||||
<Sparkles
|
||||
size={sparkleSize}
|
||||
strokeWidth={Math.max(strokeWidth, 2.1)}
|
||||
className="absolute -right-1 -top-1 text-emerald-200 drop-shadow-[0_0_4px_rgba(110,231,183,0.75)]"
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -109,11 +109,11 @@ describe('ToolsPalette', () => {
|
||||
);
|
||||
|
||||
const eraserButton = screen.getByTitle('橡皮擦 (X)');
|
||||
const autoButton = screen.getByRole('button', { name: '自动传播' });
|
||||
const autoButton = screen.getByRole('button', { name: 'AI自动推理' });
|
||||
fireEvent.click(autoButton);
|
||||
|
||||
expect(autoButton).toHaveClass('bg-cyan-500/10');
|
||||
expect(autoButton.querySelector('[data-testid="ai-segmentation-icon"]')).toBeInTheDocument();
|
||||
expect(autoButton.querySelector('[data-testid="ai-auto-inference-icon"]')).toBeInTheDocument();
|
||||
expect(eraserButton.compareDocumentPosition(autoButton) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
||||
expect(setActiveTool).toHaveBeenCalledWith('auto_propagate');
|
||||
expect(onAutoPropagate).toHaveBeenCalled();
|
||||
@@ -128,7 +128,7 @@ describe('ToolsPalette', () => {
|
||||
const circleButton = screen.getByTitle('创建圆 (O)');
|
||||
const brushButton = screen.getByTitle('画笔 (B)');
|
||||
const eraserButton = screen.getByTitle('橡皮擦 (X)');
|
||||
const autoButton = screen.getByRole('button', { name: '自动传播' });
|
||||
const autoButton = screen.getByRole('button', { name: 'AI自动推理' });
|
||||
const mergeButton = screen.getByTitle('区域合并 (+)');
|
||||
const removeButton = screen.getByTitle('重叠区域去除 (-)');
|
||||
const deleteButton = screen.getByTitle('删除选中遮罩 (Del)');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { MousePointer2, CircleOff, PencilLine, Hexagon, Square, Circle, Brush, Eraser, Combine, Scissors, FileUp, Trash2 } from 'lucide-react';
|
||||
import { cn } from '../lib/utils';
|
||||
import { AiAutoInferenceIcon } from './AiAutoInferenceIcon';
|
||||
import { AiSegmentationIcon } from './AiSegmentationIcon';
|
||||
import { useStore } from '../store/useStore';
|
||||
|
||||
@@ -125,8 +126,8 @@ export function ToolsPalette({
|
||||
onAutoPropagate?.();
|
||||
}}
|
||||
disabled={!canAutoPropagate || isPropagating}
|
||||
aria-label="自动传播"
|
||||
title={isPropagating ? '传播中...' : '自动传播'}
|
||||
aria-label="AI自动推理"
|
||||
title={isPropagating ? 'AI自动推理中...' : 'AI自动推理'}
|
||||
className={cn(
|
||||
"w-9 h-9 rounded-md flex items-center justify-center transition-all p-1.5 border",
|
||||
activeTool === 'auto_propagate'
|
||||
@@ -135,7 +136,7 @@ export function ToolsPalette({
|
||||
(!canAutoPropagate || isPropagating) && "opacity-35 cursor-not-allowed hover:bg-cyan-500/10 hover:text-cyan-200",
|
||||
)}
|
||||
>
|
||||
<AiSegmentationIcon size={17} strokeWidth={2.2} />
|
||||
<AiAutoInferenceIcon size={17} strokeWidth={2.2} />
|
||||
</button>
|
||||
<div className="my-1 h-px w-9 bg-white/15" />
|
||||
</>
|
||||
|
||||
@@ -1438,7 +1438,7 @@ describe('VideoWorkspace', () => {
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '分割结果导出' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '特定范围帧' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
|
||||
expect(screen.getByText('请在播放进度条或视频处理进度条上点击/拖拽选择传播起止帧,再点击“开始传播”')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('SAM 2.1 Tiny').length).toBeGreaterThan(0);
|
||||
@@ -1768,7 +1768,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始传播' }));
|
||||
|
||||
expect(await screen.findByText('当前参考帧无遮罩')).toBeInTheDocument();
|
||||
@@ -1842,7 +1842,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始传播' }));
|
||||
|
||||
await waitFor(() => expect(apiMock.updateAnnotation).toHaveBeenCalledTimes(1));
|
||||
@@ -1919,7 +1919,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
expect(apiMock.queuePropagationTask).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始传播' }));
|
||||
|
||||
@@ -1992,7 +1992,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
|
||||
expect(screen.queryByLabelText('传播权重')).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
const propagationWeightSelect = screen.getByLabelText('传播权重');
|
||||
expect(propagationWeightSelect).toHaveClass('bg-[#050809]');
|
||||
expect(within(propagationWeightSelect).getByRole('option', { name: 'tiny' })).toHaveClass('text-cyan-100');
|
||||
@@ -2054,7 +2054,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始传播' }));
|
||||
|
||||
const progressPanel = await screen.findByLabelText('自动传播进度');
|
||||
@@ -2100,7 +2100,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
const processingBar = screen.getByLabelText('视频处理进度条');
|
||||
vi.spyOn(processingBar, 'getBoundingClientRect').mockReturnValue({
|
||||
left: 0,
|
||||
@@ -2183,7 +2183,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
const processingBar = screen.getByLabelText('视频处理进度条');
|
||||
vi.spyOn(processingBar, 'getBoundingClientRect').mockReturnValue({
|
||||
left: 0,
|
||||
@@ -2286,7 +2286,7 @@ describe('VideoWorkspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '自动传播' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'AI自动推理' }));
|
||||
fireEvent.change(screen.getByLabelText('传播起始帧'), { target: { value: '1' } });
|
||||
fireEvent.change(screen.getByLabelText('传播结束帧'), { target: { value: '3' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始传播' }));
|
||||
|
||||
Reference in New Issue
Block a user