feat: 数据处理向导新增生成控制选项
提取 GenerationOptionsPanel 组件统一管理生成模型、温度、最大长度、JSON 模式与质量过滤配置,StructuredProcessOptions 与 UnstructuredProcessOptions 继承 GenerationControlOptions,CreateView、TaskSetupStep 及各子步骤同步接入,详情/列表小幅调整,回归脚本扩充生成选项断言。
This commit is contained in:
@@ -126,6 +126,8 @@ assert.match(previewSource, /@media \(max-width: 900px\)/, '第三步缺少窄
|
||||
|
||||
const taskSetupPath = path.join(createDir, 'TaskSetupStep.vue')
|
||||
const taskSetupSource = await readFile(taskSetupPath, 'utf8')
|
||||
const generationOptionsPath = path.join(createDir, 'GenerationOptionsPanel.vue')
|
||||
const generationControlSource = await readFile(generationOptionsPath, 'utf8')
|
||||
const sourceUploadPath = path.join(createDir, 'SourceUploadStep.vue')
|
||||
const sourceUploadSource = await readFile(sourceUploadPath, 'utf8')
|
||||
|
||||
@@ -135,7 +137,7 @@ for (const marker of ['<el-upload', '源数据上传', '数据源配置', 'uploa
|
||||
assert.match(viewSource, /<SourceUploadStep\s+[\s\S]*?v-else-if="currentStepId === 'upload'"/, '第二步没有挂载独立上传组件')
|
||||
assert.match(viewSource, /if \(currentStepId\.value === 'create'\) return '继续:上传文件'/, '第一步主按钮没有指向上传文件')
|
||||
assert.match(viewSource, /if \(currentStepId\.value === 'upload'\) return '继续:数据预览'/, '第二步主按钮没有指向数据预览')
|
||||
assert.match(viewSource, /const DRAFT_SCHEMA_VERSION = 4/, '五步索引变更后必须升级草稿版本')
|
||||
assert.match(viewSource, /const DRAFT_SCHEMA_VERSION = 5/, '生成配置扩展后必须升级草稿版本')
|
||||
|
||||
const nextFromCreateStart = viewSource.indexOf('async function nextFromCreate()')
|
||||
const nextFromUploadStart = viewSource.indexOf('function nextFromUpload()', nextFromCreateStart)
|
||||
@@ -195,6 +197,40 @@ assert.match(viewSource, /structuredOptions\.value = \{[\s\S]*\.\.\.snapshot\.st
|
||||
assert.match(viewSource, /v-model:structured-options="structuredOptions"/, '父页面没有双向绑定结构化配置')
|
||||
assert.match(viewSource, /createResults\([\s\S]*structuredOptions\.value/, '每行生成数量没有接入结果生成逻辑')
|
||||
|
||||
for (const field of [
|
||||
'generationModelId',
|
||||
'generationPrompt',
|
||||
'qualityFilterEnabled',
|
||||
'filterLowQuality',
|
||||
'filterShortContent',
|
||||
'minOutputLength',
|
||||
]) {
|
||||
assert.ok(typesSource.includes(field), `生成控制配置缺少字段:${field}`)
|
||||
assert.ok(viewSource.includes(field), `父页面默认值或草稿状态缺少字段:${field}`)
|
||||
}
|
||||
assert.match(taskSetupSource, /GenerationOptionsPanel/, '生成选项没有复用统一的大模型与质量筛选组件')
|
||||
assert.match(taskSetupSource, /:options="structuredOptions"/, '结构化生成选项未接入统一配置组件')
|
||||
assert.match(taskSetupSource, /:options="unstructuredOptions"/, '非结构化生成选项未接入统一配置组件')
|
||||
assert.match(taskSetupSource, /<h3>大模型<\/h3>/, '大模型必须作为与生成选项平级的独立分类')
|
||||
assert.match(taskSetupSource, /section="model"/, '独立大模型分类没有挂载模型配置')
|
||||
assert.match(taskSetupSource, /section="quality"/, '质量筛选没有保留在生成选项分类中')
|
||||
assert.doesNotMatch(generationControlSource, /<h4>大模型<\/h4>/, '大模型不应继续作为生成选项内部子分类')
|
||||
for (const label of ['大模型', '数据生成模型', '默认提示语', '质量筛选', '过滤低质量内容', '过滤过短内容', '最少字数']) {
|
||||
assert.ok(generationControlSource.includes(label), `生成控制界面缺少:${label}`)
|
||||
}
|
||||
assert.match(generationControlSource, /filterable/, '数据生成模型下拉必须支持搜索')
|
||||
assert.match(generationControlSource, /maxlength="500"/, '默认提示语缺少合理的长度限制')
|
||||
assert.match(generationControlSource, /\.model-option-row\s*\{[\s\S]*?display:\s*flex[\s\S]*?border:\s*1px solid #e2e5ec/, '大模型配置没有与上方生成选项使用一致的配置行样式')
|
||||
assert.match(viewSource, /const DEFAULT_GENERATION_PROMPT\s*=\s*['"][^'"]{40,}['"]/, '大模型配置缺少可直接使用的默认提示语')
|
||||
assert.equal((viewSource.match(/generationPrompt:\s*DEFAULT_GENERATION_PROMPT/g) || []).length, 2, '结构化与非结构化任务必须共用默认提示语')
|
||||
assert.match(generationControlSource, /v-if="options\.qualityFilterEnabled"/, '质量规则没有随总开关渐进显示')
|
||||
assert.match(generationControlSource, /v-if="options\.filterShortContent"/, '最少字数没有随短内容规则显示')
|
||||
assert.match(generationControlSource, /:min="1"[\s\S]*:max="1000"/, '最少字数缺少 1 到 1000 的边界限制')
|
||||
assert.match(taskSetupSource, /generationValidationMessage/, '生成模型与质量规则缺少继续前校验')
|
||||
assert.match(viewSource, /useModelsStore/, '创建页没有加载模型列表')
|
||||
assert.match(viewSource, /model\.type === 'LLM'/, '数据生成模型列表没有排除非大模型')
|
||||
assert.match(viewSource, /:generation-models="generationModels"/, '创建页没有向生成选项传递模型列表')
|
||||
|
||||
assert.match(typesSource, /export interface UnstructuredProcessOptions/, '缺少非结构化处理选项类型')
|
||||
for (const field of [
|
||||
'preprocessOptions',
|
||||
@@ -298,7 +334,17 @@ const generationOptionsStart = viewSource.indexOf('function generationAffectingO
|
||||
const generationOptionsEnd = viewSource.indexOf('const generationOptionsSignature', generationOptionsStart)
|
||||
assert.ok(generationOptionsStart >= 0 && generationOptionsEnd > generationOptionsStart, '缺少生成影响配置签名函数')
|
||||
const generationOptionsSource = viewSource.slice(generationOptionsStart, generationOptionsEnd)
|
||||
for (const field of ['semanticEnrichment', 'qaPairsPerChunk', 'datasetSplit']) {
|
||||
for (const field of [
|
||||
'semanticEnrichment',
|
||||
'qaPairsPerChunk',
|
||||
'datasetSplit',
|
||||
'generationModelId',
|
||||
'generationPrompt',
|
||||
'qualityFilterEnabled',
|
||||
'filterLowQuality',
|
||||
'filterShortContent',
|
||||
'minOutputLength',
|
||||
]) {
|
||||
assert.ok(generationOptionsSource.includes(field), `生成签名缺少字段:${field}`)
|
||||
}
|
||||
assert.match(
|
||||
@@ -341,6 +387,12 @@ const baseUnstructuredOptions = {
|
||||
semanticEnrichment: false,
|
||||
qaPairsPerChunk: 3,
|
||||
datasetSplit: { train: 80, validation: 10, test: 10 },
|
||||
generationModelId: 1,
|
||||
generationPrompt: '仅输出问答对',
|
||||
qualityFilterEnabled: false,
|
||||
filterLowQuality: true,
|
||||
filterShortContent: true,
|
||||
minOutputLength: 20,
|
||||
}
|
||||
|
||||
for (const chunkMethod of ['semantic', 'heading', 'fixed', 'custom']) {
|
||||
@@ -434,6 +486,31 @@ assert.ok(samplePreviewItems.length > 12, '测试文档未生成足够的切片'
|
||||
const generatedResults = previewModelModule.createResults(samplePreviewItems.slice(0, 13), baseUnstructuredOptions)
|
||||
assert.equal(generatedResults.length, 39, '每个切片生成 3 个问答对未完整应用到所有切片')
|
||||
|
||||
const shortContentItems = [{
|
||||
...samplePreviewItems[0],
|
||||
editedContent: '问:示例\n短回答',
|
||||
}]
|
||||
const filteredShortResults = previewModelModule.createResults(shortContentItems, {
|
||||
...baseUnstructuredOptions,
|
||||
qualityFilterEnabled: true,
|
||||
filterLowQuality: false,
|
||||
filterShortContent: true,
|
||||
minOutputLength: 20,
|
||||
})
|
||||
assert.equal(filteredShortResults.length, 0, '开启过短内容过滤后仍保留低于最少字数的结果')
|
||||
|
||||
const invalidContentItems = [{
|
||||
...samplePreviewItems[0],
|
||||
status: 'invalid',
|
||||
}]
|
||||
const filteredInvalidResults = previewModelModule.createResults(invalidContentItems, {
|
||||
...baseUnstructuredOptions,
|
||||
qualityFilterEnabled: true,
|
||||
filterLowQuality: true,
|
||||
filterShortContent: false,
|
||||
})
|
||||
assert.equal(filteredInvalidResults.length, 0, '开启低质量过滤后仍保留标记为无效的结果')
|
||||
|
||||
const legacyExternalItems = previewModelModule.buildPreviewItems('a\nb\nc\nd', 'external', 'legacy-check')
|
||||
assert.equal(legacyExternalItems.length, 2, '外来数据原有的每 3 行分组行为被破坏')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user