unsloth/studio/frontend/src/features/training/api/datasets-api.ts
Roland Tannous 5d97f42af4 feat: add AI Assist button for user-triggered column classification
Move LLM-assisted column mapping from silent /check-format automation
to an explicit "AI Assist" button in the dataset mapping dialog. This
makes the feature transparent and user-controlled.

- Remove llm_classify_columns() from check_dataset_format() (heuristic-only)
- Remove auto-save suggested_mapping from use-training-actions.ts
- Add POST /api/datasets/ai-assist-mapping endpoint (receives preview
  samples from frontend, no dataset re-loading needed)
- Add AiAssistMappingRequest/Response models
- Add aiAssistMapping() frontend API function
- Add Sparkles AI Assist button to DatasetMappingCard with loading state
- Wire up handleAiAssist handler in dataset-preview-dialog.tsx
2026-03-10 11:09:01 +00:00

109 lines
2.8 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-only - See /studio/LICENSE.AGPL-3.0
// Copyright © 2025 Unsloth AI
import type {
CheckFormatResponse,
LocalDatasetsResponse,
UploadDatasetResponse,
} from "../types/datasets";
import { authFetch } from "@/features/auth";
type CheckDatasetFormatArgs = {
datasetName: string;
hfToken: string | null;
subset?: string | null;
split?: string | null;
isVlm?: boolean;
};
export async function checkDatasetFormat({
datasetName,
hfToken,
subset,
split,
isVlm,
}: CheckDatasetFormatArgs): Promise<CheckFormatResponse> {
const res = await authFetch("/api/datasets/check-format", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
dataset_name: datasetName,
hf_token: hfToken || undefined,
subset: subset || undefined,
split: split || "train",
is_vlm: !!isVlm,
}),
});
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.detail || `Request failed (${res.status})`);
}
return res.json();
}
export async function uploadTrainingDataset(
file: File,
): Promise<UploadDatasetResponse> {
const form = new FormData();
form.append("file", file);
const res = await authFetch("/api/datasets/upload", {
method: "POST",
body: form,
});
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.detail || `Upload failed (${res.status})`);
}
return res.json();
}
// ── AI Assist ────────────────────────────────────────────────────────
type AiAssistMappingArgs = {
columns: string[];
samples: Record<string, unknown>[];
datasetName?: string | null;
};
export type AiAssistMappingResponse = {
success: boolean;
suggested_mapping?: Record<string, string> | null;
warning?: string | null;
};
export async function aiAssistMapping({
columns,
samples,
datasetName,
}: AiAssistMappingArgs): Promise<AiAssistMappingResponse> {
const res = await authFetch("/api/datasets/ai-assist-mapping", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
columns,
samples: samples.slice(0, 5),
dataset_name: datasetName || undefined,
}),
});
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.detail || `AI assist failed (${res.status})`);
}
return res.json();
}
export async function listLocalDatasets(): Promise<LocalDatasetsResponse> {
const res = await authFetch("/api/datasets/local");
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.detail || `Request failed (${res.status})`);
}
return res.json();
}