feat: 数据集版本管理
新增数据集版本创建、切换、激活与历史追溯能力,Mock 通过 localStorage 持久化版本状态并接入版本接口路由,预览页支持版本对比与内容回滚,列表补充版本入口,回归脚本扩充断言。
This commit is contained in:
@@ -118,7 +118,7 @@ onMounted(loadData)
|
||||
<template #actions="{ row }">
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" link size="small" @click="handlePreview(row)">
|
||||
<i class="fa fa-eye" style="margin-right: 4px" />预览
|
||||
<i class="fa fa-eye" style="margin-right: 4px" />详情
|
||||
</el-button>
|
||||
<el-button type="success" link size="small" @click="handleDownload(row)">
|
||||
<i class="fa fa-download" style="margin-right: 4px" />下载
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
121
frontend/src/views/dataset/datasetRecords.ts
Normal file
121
frontend/src/views/dataset/datasetRecords.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
export type DatasetRecordKind = 'object' | 'primitive' | 'invalid'
|
||||
|
||||
export interface DatasetRecord {
|
||||
sourceIndex: number
|
||||
displayIndex: number
|
||||
raw: string
|
||||
kind: DatasetRecordKind
|
||||
value: unknown
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface DatasetRecordResult {
|
||||
supported: boolean
|
||||
records: DatasetRecord[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
function parseValue(raw: string, sourceIndex: number, displayIndex: number): DatasetRecord {
|
||||
try {
|
||||
const value: unknown = JSON.parse(raw)
|
||||
return {
|
||||
sourceIndex,
|
||||
displayIndex,
|
||||
raw,
|
||||
kind: isObjectRecord(value) ? 'object' : 'primitive',
|
||||
value,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
sourceIndex,
|
||||
displayIndex,
|
||||
raw,
|
||||
kind: 'invalid',
|
||||
value: raw,
|
||||
error: error instanceof Error ? error.message : 'JSON 格式不正确',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 将 JSONL 或 JSON 文件解析为可逐条编辑的样本,保留原始物理位置。 */
|
||||
export function parseDatasetRecords(content: string, fileName: string): DatasetRecordResult {
|
||||
const normalizedName = fileName.toLowerCase()
|
||||
if (normalizedName.endsWith('.jsonl')) {
|
||||
const records: DatasetRecord[] = []
|
||||
content.split('\n').forEach((line, sourceIndex) => {
|
||||
if (!line.trim()) return
|
||||
records.push(parseValue(line, sourceIndex, records.length + 1))
|
||||
})
|
||||
return { supported: true, records }
|
||||
}
|
||||
|
||||
if (normalizedName.endsWith('.json')) {
|
||||
try {
|
||||
const root: unknown = JSON.parse(content)
|
||||
const values = Array.isArray(root) ? root : [root]
|
||||
return {
|
||||
supported: true,
|
||||
records: values.map((value, sourceIndex) => ({
|
||||
sourceIndex,
|
||||
displayIndex: sourceIndex + 1,
|
||||
raw: JSON.stringify(value),
|
||||
kind: isObjectRecord(value) ? 'object' : 'primitive',
|
||||
value,
|
||||
})),
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
supported: true,
|
||||
records: [{
|
||||
sourceIndex: 0,
|
||||
displayIndex: 1,
|
||||
raw: content,
|
||||
kind: 'invalid',
|
||||
value: content,
|
||||
error: error instanceof Error ? error.message : 'JSON 格式不正确',
|
||||
}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { supported: false, records: [] }
|
||||
}
|
||||
|
||||
/** 仅替换目标样本;JSONL 中其他行(包括空行和原格式)保持不变。 */
|
||||
export function updateDatasetRecord(
|
||||
content: string,
|
||||
fileName: string,
|
||||
sourceIndex: number,
|
||||
nextValue: unknown,
|
||||
) {
|
||||
const normalizedName = fileName.toLowerCase()
|
||||
if (normalizedName.endsWith('.jsonl')) {
|
||||
const lines = content.split('\n')
|
||||
if (sourceIndex < 0 || sourceIndex >= lines.length) throw new Error('目标样本不存在')
|
||||
lines[sourceIndex] = JSON.stringify(nextValue)
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
if (normalizedName.endsWith('.json')) {
|
||||
let root: unknown
|
||||
try {
|
||||
root = JSON.parse(content)
|
||||
} catch {
|
||||
if (sourceIndex !== 0) throw new Error('目标样本不存在')
|
||||
return JSON.stringify(nextValue, null, 2)
|
||||
}
|
||||
if (Array.isArray(root)) {
|
||||
if (sourceIndex < 0 || sourceIndex >= root.length) throw new Error('目标样本不存在')
|
||||
root[sourceIndex] = nextValue
|
||||
return JSON.stringify(root, null, 2)
|
||||
}
|
||||
if (sourceIndex !== 0) throw new Error('目标样本不存在')
|
||||
return JSON.stringify(nextValue, null, 2)
|
||||
}
|
||||
|
||||
throw new Error('当前文件不支持逐条编辑')
|
||||
}
|
||||
Reference in New Issue
Block a user