完善韩泰 EOT 标注编辑器并更新标注规范与项目资料
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
type Transcript,
|
||||
} from "@/lib/annotations";
|
||||
import { isSameOriginRequest } from "@/lib/request-origin";
|
||||
import type { CallReference } from "@/lib/call-reference";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -20,7 +19,7 @@ const dataRoot = path.join(projectRoot, "data");
|
||||
const labelsRoot = path.join(projectRoot, "labels", "EOT标注");
|
||||
const savedRoot = path.join(labelsRoot, "工作数据");
|
||||
const exampleRoot = path.join(labelsRoot, "示例");
|
||||
const callReferencesPath = path.join(process.cwd(), "data", "hantai-reference.json");
|
||||
const draftRoot = path.join(labelsRoot, "韩泰初稿");
|
||||
const lockPath = path.join(savedRoot, ".workspace.lock");
|
||||
const extensions = new Set([".mp3", ".wav", ".m4a", ".ogg", ".flac", ".webm"]);
|
||||
const maxPayloadBytes = 20 * 1024 * 1024;
|
||||
@@ -119,39 +118,6 @@ async function discoverRecordings(): Promise<Recording[]> {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function readCallReferences(): Promise<CallReference[]> {
|
||||
let source: string;
|
||||
try {
|
||||
source = await fs.readFile(callReferencesPath, "utf8");
|
||||
} catch (error) {
|
||||
if (hasCode(error, "ENOENT")) return [];
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const references: unknown = JSON.parse(source);
|
||||
if (!Array.isArray(references)) throw new Error("顶层必须为数组。");
|
||||
return references.map((value, index) => {
|
||||
const message = `第 ${index + 1} 条原表记录格式无效。`;
|
||||
if (!value || typeof value !== "object") throw new Error(message);
|
||||
const row = value as Partial<CallReference>;
|
||||
if (typeof row.call_id !== "string" || !row.call_id.trim()
|
||||
|| !row.source || typeof row.source.file !== "string" || typeof row.source.sheet !== "string"
|
||||
|| !Number.isSafeInteger(row.source.row) || row.source.row < 1
|
||||
|| !Array.isArray(row.fields)
|
||||
|| row.fields.some((field) => !field || typeof field.label !== "string" || typeof field.value !== "string")) {
|
||||
throw new Error(message);
|
||||
}
|
||||
return {
|
||||
call_id: row.call_id,
|
||||
source: { file: row.source.file, sheet: row.source.sheet, row: row.source.row },
|
||||
fields: row.fields.map((field) => ({ label: field.label, value: field.value })),
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
throw new WorkspaceError(`原表参考数据格式有误:${error instanceof Error ? error.message : "JSON 格式错误。"}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function readCsvPair(directory: string): Promise<{ transcripts: Transcript[]; annotations: Annotation[] }> {
|
||||
const [transcriptsCsv, annotationsCsv] = await Promise.all([
|
||||
fs.readFile(path.join(directory, "asr_history.csv"), "utf8"),
|
||||
@@ -179,22 +145,24 @@ export async function GET(): Promise<Response> {
|
||||
if (await exists(lockPath)) {
|
||||
throw new WorkspaceError("工作数据正在保存,请稍后重试。", 409);
|
||||
}
|
||||
const [hasTranscripts, hasAnnotations, recordings, callReferences] = await Promise.all([
|
||||
const [hasTranscripts, hasAnnotations, recordings] = await Promise.all([
|
||||
exists(path.join(savedRoot, "asr_history.csv")),
|
||||
exists(path.join(savedRoot, "eot_labels.csv")),
|
||||
discoverRecordings(),
|
||||
readCallReferences(),
|
||||
]);
|
||||
if (hasTranscripts && hasAnnotations) {
|
||||
return await withDiskLock(async () => json({
|
||||
...await readCsvPair(savedRoot),
|
||||
recordings,
|
||||
callReferences,
|
||||
source: "saved",
|
||||
savedAt: await savedAt(),
|
||||
}));
|
||||
}
|
||||
return json({ ...await readCsvPair(exampleRoot), recordings, callReferences, source: "example" });
|
||||
if (await exists(path.join(draftRoot, "asr_history.csv")) && await exists(path.join(draftRoot, "eot_labels.csv"))) {
|
||||
const stats = await Promise.all([fs.stat(path.join(draftRoot, "asr_history.csv")), fs.stat(path.join(draftRoot, "eot_labels.csv"))]);
|
||||
return json({ ...await readCsvPair(draftRoot), recordings, source: "draft", savedAt: new Date(Math.max(...stats.map(stat => stat.mtimeMs))).toISOString() });
|
||||
}
|
||||
return json({ ...await readCsvPair(exampleRoot), recordings, source: "example" });
|
||||
});
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
|
||||
Reference in New Issue
Block a user