feat: 添加[随机匹配]选项到TemplateSegment匹配规则
- 在Rust后端SegmentMatchingRule枚举中添加RandomMatch变体 - 更新TypeScript前端类型定义和SegmentMatchingRuleHelper工具函数 - 修改SegmentMatchingRuleEditor组件支持随机匹配选项 - 添加绿色样式标识随机匹配规则 - 添加完整的单元测试覆盖新功能 遵循promptx/tauri-desktop-app-expert开发规范
This commit is contained in:
parent
05d29832b0
commit
73c2187757
|
|
@ -70,6 +70,8 @@ pub enum SegmentMatchingRule {
|
|||
FixedMaterial,
|
||||
/// AI分类素材 - 使用指定AI分类的素材
|
||||
AiClassification { category_id: String, category_name: String },
|
||||
/// 随机匹配 - 从项目中随机选择合适的素材
|
||||
RandomMatch,
|
||||
}
|
||||
|
||||
impl Default for SegmentMatchingRule {
|
||||
|
|
@ -84,6 +86,7 @@ impl SegmentMatchingRule {
|
|||
match self {
|
||||
Self::FixedMaterial => "固定素材".to_string(),
|
||||
Self::AiClassification { category_name, .. } => format!("AI分类: {}", category_name),
|
||||
Self::RandomMatch => "随机匹配".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +99,11 @@ impl SegmentMatchingRule {
|
|||
pub fn is_ai_classification(&self) -> bool {
|
||||
matches!(self, Self::AiClassification { .. })
|
||||
}
|
||||
|
||||
/// 检查是否为随机匹配
|
||||
pub fn is_random_match(&self) -> bool {
|
||||
matches!(self, Self::RandomMatch)
|
||||
}
|
||||
}
|
||||
|
||||
/// 轨道片段
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ export const SegmentMatchingRuleEditor: React.FC<SegmentMatchingRuleEditorProps>
|
|||
firstClassification.name
|
||||
));
|
||||
}
|
||||
} else if (ruleType === 'random') {
|
||||
setEditingRule(SegmentMatchingRuleHelper.createRandomMatch());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -106,12 +108,20 @@ export const SegmentMatchingRuleEditor: React.FC<SegmentMatchingRuleEditorProps>
|
|||
};
|
||||
|
||||
const getCurrentRuleType = (rule: SegmentMatchingRule): string => {
|
||||
return SegmentMatchingRuleHelper.isFixedMaterial(rule) ? 'fixed' : 'ai_classification';
|
||||
if (SegmentMatchingRuleHelper.isFixedMaterial(rule)) {
|
||||
return 'fixed';
|
||||
} else if (SegmentMatchingRuleHelper.isAiClassification(rule)) {
|
||||
return 'ai_classification';
|
||||
} else if (SegmentMatchingRuleHelper.isRandomMatch(rule)) {
|
||||
return 'random';
|
||||
}
|
||||
return 'fixed'; // 默认值
|
||||
};
|
||||
|
||||
const ruleTypeOptions = [
|
||||
{ value: 'fixed', label: '固定素材' },
|
||||
{ value: 'ai_classification', label: 'AI分类素材' },
|
||||
{ value: 'random', label: '随机匹配' },
|
||||
];
|
||||
|
||||
const classificationOptions = aiClassifications.map(classification => ({
|
||||
|
|
@ -127,7 +137,11 @@ export const SegmentMatchingRuleEditor: React.FC<SegmentMatchingRuleEditorProps>
|
|||
<span className={`px-2 py-1 rounded text-xs ${
|
||||
SegmentMatchingRuleHelper.isFixedMaterial(currentRule)
|
||||
? 'bg-gray-100 text-gray-800'
|
||||
: 'bg-blue-100 text-blue-800'
|
||||
: SegmentMatchingRuleHelper.isAiClassification(currentRule)
|
||||
? 'bg-blue-100 text-blue-800'
|
||||
: SegmentMatchingRuleHelper.isRandomMatch(currentRule)
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{SegmentMatchingRuleHelper.getDisplayName(currentRule)}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { SegmentMatchingRuleHelper, SegmentMatchingRule } from '../template';
|
||||
|
||||
describe('SegmentMatchingRuleHelper', () => {
|
||||
describe('createFixedMaterial', () => {
|
||||
it('should create a fixed material rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
expect(rule).toBe('FixedMaterial');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createAiClassification', () => {
|
||||
it('should create an AI classification rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
expect(rule).toEqual({
|
||||
AiClassification: {
|
||||
category_id: 'test-id',
|
||||
category_name: 'Test Category'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createRandomMatch', () => {
|
||||
it('should create a random match rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
expect(rule).toBe('RandomMatch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDisplayName', () => {
|
||||
it('should return correct display name for fixed material', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
const displayName = SegmentMatchingRuleHelper.getDisplayName(rule);
|
||||
expect(displayName).toBe('固定素材');
|
||||
});
|
||||
|
||||
it('should return correct display name for AI classification', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
const displayName = SegmentMatchingRuleHelper.getDisplayName(rule);
|
||||
expect(displayName).toBe('AI分类: Test Category');
|
||||
});
|
||||
|
||||
it('should return correct display name for random match', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
const displayName = SegmentMatchingRuleHelper.getDisplayName(rule);
|
||||
expect(displayName).toBe('随机匹配');
|
||||
});
|
||||
|
||||
it('should return unknown rule for invalid rule', () => {
|
||||
const rule = {} as SegmentMatchingRule;
|
||||
const displayName = SegmentMatchingRuleHelper.getDisplayName(rule);
|
||||
expect(displayName).toBe('未知规则');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFixedMaterial', () => {
|
||||
it('should return true for fixed material rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
expect(SegmentMatchingRuleHelper.isFixedMaterial(rule)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for AI classification rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
expect(SegmentMatchingRuleHelper.isFixedMaterial(rule)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for random match rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
expect(SegmentMatchingRuleHelper.isFixedMaterial(rule)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAiClassification', () => {
|
||||
it('should return false for fixed material rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
expect(SegmentMatchingRuleHelper.isAiClassification(rule)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for AI classification rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
expect(SegmentMatchingRuleHelper.isAiClassification(rule)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for random match rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
expect(SegmentMatchingRuleHelper.isAiClassification(rule)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRandomMatch', () => {
|
||||
it('should return false for fixed material rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
expect(SegmentMatchingRuleHelper.isRandomMatch(rule)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for AI classification rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
expect(SegmentMatchingRuleHelper.isRandomMatch(rule)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for random match rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
expect(SegmentMatchingRuleHelper.isRandomMatch(rule)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAiClassificationInfo', () => {
|
||||
it('should return null for fixed material rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createFixedMaterial();
|
||||
const info = SegmentMatchingRuleHelper.getAiClassificationInfo(rule);
|
||||
expect(info).toBeNull();
|
||||
});
|
||||
|
||||
it('should return classification info for AI classification rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createAiClassification('test-id', 'Test Category');
|
||||
const info = SegmentMatchingRuleHelper.getAiClassificationInfo(rule);
|
||||
expect(info).toEqual({
|
||||
category_id: 'test-id',
|
||||
category_name: 'Test Category'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null for random match rule', () => {
|
||||
const rule = SegmentMatchingRuleHelper.createRandomMatch();
|
||||
const info = SegmentMatchingRuleHelper.getAiClassificationInfo(rule);
|
||||
expect(info).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -58,7 +58,8 @@ export interface Track {
|
|||
*/
|
||||
export type SegmentMatchingRule =
|
||||
| "FixedMaterial"
|
||||
| { AiClassification: { category_id: string; category_name: string } };
|
||||
| { AiClassification: { category_id: string; category_name: string } }
|
||||
| "RandomMatch";
|
||||
|
||||
/**
|
||||
* 片段匹配规则辅助函数
|
||||
|
|
@ -78,6 +79,13 @@ export const SegmentMatchingRuleHelper = {
|
|||
return { AiClassification: { category_id: categoryId, category_name: categoryName } };
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建随机匹配规则
|
||||
*/
|
||||
createRandomMatch(): SegmentMatchingRule {
|
||||
return "RandomMatch";
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取规则的显示名称
|
||||
*/
|
||||
|
|
@ -86,6 +94,8 @@ export const SegmentMatchingRuleHelper = {
|
|||
return '固定素材';
|
||||
} else if (typeof rule === 'object' && 'AiClassification' in rule) {
|
||||
return `AI分类: ${rule.AiClassification.category_name}`;
|
||||
} else if (rule === "RandomMatch") {
|
||||
return '随机匹配';
|
||||
}
|
||||
return '未知规则';
|
||||
},
|
||||
|
|
@ -104,6 +114,13 @@ export const SegmentMatchingRuleHelper = {
|
|||
return typeof rule === 'object' && 'AiClassification' in rule;
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查是否为随机匹配
|
||||
*/
|
||||
isRandomMatch(rule: SegmentMatchingRule): boolean {
|
||||
return rule === "RandomMatch";
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取AI分类信息
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue