Fix LoRA training Error 500 - remove Radio serialization issue
The @gradio/client was wrapping Radio component values as
{"value": "replace", "__type__": "update"} instead of plain strings,
causing the update_settings Gradio call to fail and crash the server.
- /update-settings: removed Gradio call, settings are applied at save time
- /save-dataset: migrated to REST API (/v1/dataset/save) which accepts
tag_position and other settings directly as strings
- Frontend: pass dataset settings (tag, position, etc.) when saving
This commit is contained in:
@@ -474,6 +474,10 @@ export const TrainingPanel: React.FC = () => {
|
|||||||
const result = await trainingApi.saveDataset({
|
const result = await trainingApi.saveDataset({
|
||||||
savePath: savePath || `./datasets/${datasetSettings.datasetName}.json`,
|
savePath: savePath || `./datasets/${datasetSettings.datasetName}.json`,
|
||||||
datasetName: datasetSettings.datasetName,
|
datasetName: datasetSettings.datasetName,
|
||||||
|
customTag: datasetSettings.customTag,
|
||||||
|
tagPosition: datasetSettings.tagPosition,
|
||||||
|
allInstrumental: datasetSettings.allInstrumental,
|
||||||
|
genreRatio: datasetSettings.genreRatio,
|
||||||
}, token);
|
}, token);
|
||||||
setSaveStatus(result.status as string);
|
setSaveStatus(result.status as string);
|
||||||
if (result.path) setSavePath(result.path);
|
if (result.path) setSavePath(result.path);
|
||||||
|
|||||||
@@ -717,41 +717,45 @@ router.post('/save-sample', authMiddleware, async (req: AuthenticatedRequest, re
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/training/update-settings — Update dataset global settings
|
// POST /api/training/update-settings — Update dataset global settings
|
||||||
router.post('/update-settings', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
|
// Settings are applied directly when saving (via REST API), so no Gradio call needed here.
|
||||||
try {
|
router.post('/update-settings', authMiddleware, (_req: AuthenticatedRequest, res: Response) => {
|
||||||
const { customTag, tagPosition, allInstrumental, genreRatio } = req.body;
|
res.json({ success: true });
|
||||||
|
|
||||||
const client = await getGradioClient();
|
|
||||||
await client.predict('/update_settings', [
|
|
||||||
customTag ?? '',
|
|
||||||
tagPosition ?? 'replace',
|
|
||||||
allInstrumental ?? true,
|
|
||||||
genreRatio ?? 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[Training] Update settings error:', error);
|
|
||||||
res.status(500).json({ error: error instanceof Error ? error.message : 'Failed to update settings' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/training/save-dataset — Save the dataset to a JSON file
|
// POST /api/training/save-dataset — Save the dataset to a JSON file
|
||||||
router.post('/save-dataset', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
|
router.post('/save-dataset', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { savePath, datasetName } = req.body;
|
const { savePath, datasetName, customTag, tagPosition, allInstrumental, genreRatio } = req.body;
|
||||||
|
|
||||||
const client = await getGradioClient();
|
const resolvedPath = (savePath ?? `./datasets/${datasetName ?? 'my_lora_dataset'}.json`).trim();
|
||||||
const result = await client.predict('/save_dataset', [
|
|
||||||
savePath ?? './datasets/my_lora_dataset.json',
|
|
||||||
datasetName ?? 'my_lora_dataset',
|
|
||||||
]);
|
|
||||||
const data = result.data as unknown[];
|
|
||||||
|
|
||||||
// Returns: [saveStatus, savePath]
|
// Use REST API to avoid @gradio/client Radio serialization issues
|
||||||
|
const apiUrl = config.acestep.apiUrl;
|
||||||
|
const body: Record<string, unknown> = {
|
||||||
|
save_path: resolvedPath,
|
||||||
|
dataset_name: datasetName ?? 'my_lora_dataset',
|
||||||
|
};
|
||||||
|
if (customTag !== undefined) body.custom_tag = customTag;
|
||||||
|
if (tagPosition !== undefined) body.tag_position = tagPosition;
|
||||||
|
if (allInstrumental !== undefined) body.all_instrumental = allInstrumental;
|
||||||
|
if (genreRatio !== undefined) body.genre_ratio = genreRatio;
|
||||||
|
|
||||||
|
const apiRes = await fetch(`${apiUrl}/v1/dataset/save`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
signal: AbortSignal.timeout(30_000),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!apiRes.ok) {
|
||||||
|
const err = await apiRes.json().catch(() => ({})) as any;
|
||||||
|
throw new Error(err?.detail || err?.error || `Save failed: ${apiRes.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await apiRes.json() as any;
|
||||||
res.json({
|
res.json({
|
||||||
status: data[0],
|
status: data.status ?? 'Saved',
|
||||||
path: data[1],
|
path: data.save_path ?? resolvedPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Training] Save dataset error:', error);
|
console.error('[Training] Save dataset error:', error);
|
||||||
|
|||||||
@@ -768,6 +768,10 @@ export const trainingApi = {
|
|||||||
saveDataset: (params: {
|
saveDataset: (params: {
|
||||||
savePath?: string;
|
savePath?: string;
|
||||||
datasetName?: string;
|
datasetName?: string;
|
||||||
|
customTag?: string;
|
||||||
|
tagPosition?: string;
|
||||||
|
allInstrumental?: boolean;
|
||||||
|
genreRatio?: number;
|
||||||
}, token: string): Promise<{ status: string; path: string }> =>
|
}, token: string): Promise<{ status: string; path: string }> =>
|
||||||
api('/api/training/save-dataset', { method: 'POST', body: params, token }),
|
api('/api/training/save-dataset', { method: 'POST', body: params, token }),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user