Сохранять каждый запуск датасета в отдельную папку и показывать прогресс генерации.
Файлы пишутся в sonar_dataset/дата-время-модель без удаления прошлых запусков; кнопка «Генерация…» заполняется по мере записи сцен через NDJSON-стрим. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -289,7 +289,7 @@ export const api = {
|
||||
});
|
||||
triggerDownload(blob, safeName || suggested);
|
||||
},
|
||||
datasetGenerate: ({
|
||||
datasetGenerate: async ({
|
||||
count = 5,
|
||||
seed = 42,
|
||||
outputDir = "sonar_dataset",
|
||||
@@ -298,6 +298,7 @@ export const api = {
|
||||
beamCount = 45,
|
||||
lengthCount = 45,
|
||||
modelFile,
|
||||
onProgress,
|
||||
} = {}) => {
|
||||
if (!modelFile) {
|
||||
return Promise.reject(new Error("Выберите файл модели .obj"));
|
||||
@@ -311,10 +312,74 @@ export const api = {
|
||||
formData.append("beamCount", String(beamCount ?? 45));
|
||||
formData.append("lengthCount", String(lengthCount ?? 45));
|
||||
formData.append("model", modelFile, modelFile.name || "model.obj");
|
||||
return request("/api/dataset/generate", {
|
||||
|
||||
const response = await fetch("/api/dataset/generate", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
throw new Error(formatApiError(payload.detail, `Request failed: /api/dataset/generate`));
|
||||
}
|
||||
if (!response.body) {
|
||||
throw new Error("Пустой ответ генерации датасета");
|
||||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
let result = null;
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split("\n");
|
||||
buffer = lines.pop() || "";
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
let event;
|
||||
try {
|
||||
event = JSON.parse(trimmed);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (event.type === "error") {
|
||||
throw new Error(event.detail || "Ошибка генерации датасета");
|
||||
}
|
||||
if (event.type === "start" || event.type === "progress") {
|
||||
if (typeof onProgress === "function") onProgress(event);
|
||||
}
|
||||
if (event.type === "done") {
|
||||
result = event.result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.trim()) {
|
||||
try {
|
||||
const event = JSON.parse(buffer.trim());
|
||||
if (event.type === "error") {
|
||||
throw new Error(event.detail || "Ошибка генерации датасета");
|
||||
}
|
||||
if (event.type === "done") result = event.result;
|
||||
if ((event.type === "start" || event.type === "progress") && typeof onProgress === "function") {
|
||||
onProgress(event);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof SyntaxError) {
|
||||
/* ignore trailing junk */
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
throw new Error("Генерация завершилась без результата");
|
||||
}
|
||||
return result;
|
||||
},
|
||||
datasetPreview: ({ stem, outputDir = "sonar_dataset", maxPoints = 25000 } = {}) =>
|
||||
request("/api/dataset/preview", {
|
||||
|
||||
Reference in New Issue
Block a user