Skip to content

Commit eb6c2b8

Browse files
committed
Merge branch 'feat/model-finetune-opt' into feat/cli-skill-sync
2 parents ebd6226 + 3c64461 commit eb6c2b8

51 files changed

Lines changed: 1632 additions & 842 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ bl auth login --console
130130

131131
# Fine-tune & deploy — a one-shot train-to-serve workflow
132132
bl dataset upload --file ./train.jsonl # Upload a .jsonl dataset (validated first)
133-
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
133+
bl finetune text create --base-model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
134134
bl finetune watch --job-id ft-xxx --output json # Non-blocking probe (running/succeeded return 0; failed/canceled report an error)
135-
bl finetune capability --model qwen3-8b # Which training types a model supports
136-
bl deploy text create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint
135+
bl finetune capability --base-model qwen3-8b # Which training types a model supports
136+
bl deploy text create --model-name qwen3-8b --display-name my-svc --plan mu # Deploy the trained model as an endpoint
137137

138138
# Browse models / apps / free-tier quota / usage statistics / workspaces
139139
bl model list # Browse model families and pricing

README.zh.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ bl auth login --console
128128

129129
# 微调与部署 — 从训练到服务的一站式流程
130130
bl dataset upload --file ./train.jsonl # 上传 .jsonl 数据集(先校验)
131-
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
131+
bl finetune text create --base-model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
132132
bl finetune watch --job-id ft-xxx --output json # 非阻塞探测(运行中/成功返回 0;失败/取消报错)
133-
bl finetune capability --model qwen3-8b # 查询模型支持哪些训练方式
134-
bl deploy text create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务
133+
bl finetune capability --base-model qwen3-8b # 查询模型支持哪些训练方式
134+
bl deploy text create --model-name qwen3-8b --display-name my-svc --plan mu # 把训练好的模型部署为推理服务
135135

136136
# 浏览模型 / 应用 / 免费额度 / 用量统计 / 业务空间
137137
bl model list # 浏览模型系列与价格信息

packages/cli/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ bl auth login --console
130130

131131
# Fine-tune & deploy — a one-shot train-to-serve workflow
132132
bl dataset upload --file ./train.jsonl # Upload a .jsonl dataset (validated first)
133-
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
133+
bl finetune text create --base-model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
134134
bl finetune watch --job-id ft-xxx --output json # Non-blocking probe (running/succeeded return 0; failed/canceled report an error)
135-
bl finetune capability --model qwen3-8b # Which training types a model supports
136-
bl deploy text create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint
135+
bl finetune capability --base-model qwen3-8b # Which training types a model supports
136+
bl deploy text create --model-name qwen3-8b --display-name my-svc --plan mu # Deploy the trained model as an endpoint
137137

138138
# Browse models / apps / free-tier quota / usage statistics / workspaces
139139
bl model list # Browse model families and pricing

packages/cli/README.zh.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ bl auth login --console
128128

129129
# 微调与部署 — 从训练到服务的一站式流程
130130
bl dataset upload --file ./train.jsonl # 上传 .jsonl 数据集(先校验)
131-
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
131+
bl finetune text create --base-model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
132132
bl finetune watch --job-id ft-xxx --output json # 非阻塞探测(运行中/成功返回 0;失败/取消报错)
133-
bl finetune capability --model qwen3-8b # 查询模型支持哪些训练方式
134-
bl deploy text create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务
133+
bl finetune capability --base-model qwen3-8b # 查询模型支持哪些训练方式
134+
bl deploy text create --model-name qwen3-8b --display-name my-svc --plan mu # 把训练好的模型部署为推理服务
135135

136136
# 浏览模型 / 应用 / 免费额度 / 用量统计 / 业务空间
137137
bl model list # 浏览模型系列与价格信息

packages/cli/src/commands.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import {
6262
finetuneTextCreate,
6363
finetuneAudioCreate,
6464
finetuneImageCreate,
65+
finetuneVideoCreate,
6566
finetuneList,
6667
finetuneGet,
6768
finetuneCancel,
@@ -71,6 +72,7 @@ import {
7172
finetuneExport,
7273
finetuneWatch,
7374
finetuneCapability,
75+
finetunePrice,
7476
deployTextCreate,
7577
deployAudioCreate,
7678
deployImageCreate,
@@ -80,6 +82,8 @@ import {
8082
deployScale,
8183
deployUpdate,
8284
deployDelete,
85+
deployPause,
86+
deployResume,
8387
tokenPlanListSeats,
8488
tokenPlanCreateKey,
8589
tokenPlanAssignSeats,
@@ -180,6 +184,7 @@ export const commands: Record<string, AnyCommand> = {
180184
"finetune text create": finetuneTextCreate,
181185
"finetune audio create": finetuneAudioCreate,
182186
"finetune image create": finetuneImageCreate,
187+
"finetune video create": finetuneVideoCreate,
183188
"finetune list": finetuneList,
184189
"finetune get": finetuneGet,
185190
"finetune cancel": finetuneCancel,
@@ -189,6 +194,7 @@ export const commands: Record<string, AnyCommand> = {
189194
"finetune export": finetuneExport,
190195
"finetune watch": finetuneWatch,
191196
"finetune capability": finetuneCapability,
197+
"finetune price": finetunePrice,
192198
"deploy text create": deployTextCreate,
193199
"deploy audio create": deployAudioCreate,
194200
"deploy image create": deployImageCreate,
@@ -198,6 +204,8 @@ export const commands: Record<string, AnyCommand> = {
198204
"deploy scale": deployScale,
199205
"deploy update": deployUpdate,
200206
"deploy delete": deployDelete,
207+
"deploy pause": deployPause,
208+
"deploy resume": deployResume,
201209
"token-plan list-seats": tokenPlanListSeats,
202210
"token-plan create-key": tokenPlanCreateKey,
203211
"token-plan assign-seats": tokenPlanAssignSeats,

packages/commands/src/commands/dataset/delete.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, deleteDataset, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
1+
import { defineCommand, deleteDataset, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const DELETE_FLAGS = {
55
fileId: {
@@ -19,20 +19,18 @@ export default defineCommand({
1919
async run(ctx) {
2020
const { settings, flags } = ctx;
2121
const fileId = flags.fileId;
22-
const format = detectOutputFormat(settings.output);
2322

2423
if (settings.dryRun) {
25-
emitResult({ action: "dataset.delete", file_id: fileId }, format);
24+
emitResult({ action: "dataset.delete", file_id: fileId }, "json");
2625
return;
2726
}
2827

2928
const response = await deleteDataset(ctx.client, fileId);
3029

31-
if (settings.quiet || format === "text") {
32-
emitBare(`Deleted ${fileId}.`);
33-
emitRequestId(response.request_id, settings.quiet);
30+
if (settings.quiet) {
31+
emitBare(fileId);
3432
} else {
35-
emitResult(response, format);
33+
emitResult(response, "json");
3634
}
3735
},
3836
});

packages/commands/src/commands/dataset/get.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, getDataset, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
1+
import { defineCommand, getDataset, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const GET_FLAGS = {
55
fileId: {
@@ -19,10 +19,9 @@ export default defineCommand({
1919
async run(ctx) {
2020
const { settings, flags } = ctx;
2121
const fileId = flags.fileId;
22-
const format = detectOutputFormat(settings.output);
2322

2423
if (settings.dryRun) {
25-
emitResult({ action: "dataset.get", file_id: fileId }, format);
24+
emitResult({ action: "dataset.get", file_id: fileId }, "json");
2625
return;
2726
}
2827

@@ -45,19 +44,10 @@ export default defineCommand({
4544
description: file.description ?? "",
4645
};
4746

48-
if (format === "json") {
49-
emitResult({ ...item, request_id: response.request_id }, format);
50-
return;
47+
if (settings.quiet) {
48+
emitBare(item.file_id);
49+
} else {
50+
emitResult({ ...item, request_id: response.request_id }, "json");
5151
}
52-
53-
// text / quiet
54-
emitBare(`file_id: ${item.file_id}`);
55-
emitBare(`name: ${item.name}`);
56-
emitBare(`size: ${item.size}`);
57-
if (item.md5) emitBare(`md5: ${item.md5}`);
58-
if (item.purpose) emitBare(`purpose: ${item.purpose}`);
59-
if (item.created_at) emitBare(`created_at: ${item.created_at}`);
60-
if (item.description) emitBare(`description: ${item.description}`);
61-
emitRequestId(response.request_id, settings.quiet);
6252
},
6353
});

packages/commands/src/commands/dataset/list.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, listDatasets, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId, formatTable } from "bailian-cli-runtime";
1+
import { defineCommand, listDatasets, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const LIST_FLAGS = {
55
page: { type: "number", valueHint: "<n>", description: "Page number (default: 1)" },
@@ -23,7 +23,6 @@ export default defineCommand({
2323
exampleArgs: ["", "--purpose fine-tune", "--purpose evaluation --page-size 20", "--output json"],
2424
async run(ctx) {
2525
const { settings, flags } = ctx;
26-
const format = detectOutputFormat(settings.output);
2726

2827
if (settings.dryRun) {
2928
emitResult(
@@ -33,7 +32,7 @@ export default defineCommand({
3332
page_size: flags.pageSize,
3433
purpose: flags.purpose,
3534
},
36-
format,
35+
"json",
3736
);
3837
return;
3938
}
@@ -46,28 +45,17 @@ export default defineCommand({
4645
const files = response.data?.files ?? [];
4746
const total = response.data?.total;
4847

49-
// Normalize to consistent structure for both text/json output.
5048
const items = files.map((item) => ({
5149
file_id: item.file_id ?? "",
5250
name: item.name ?? "",
5351
size: item.size !== undefined ? `${(item.size / 1024).toFixed(1)} KB` : "?",
5452
purpose: item.purpose ?? "",
5553
}));
5654

57-
if (format === "json") {
58-
emitResult({ items, total, request_id: response.request_id }, format);
59-
return;
60-
}
61-
62-
// text / quiet
63-
if (items.length === 0) {
64-
emitBare("No dataset files found.");
65-
return;
55+
if (settings.quiet) {
56+
for (const item of items) emitBare(item.file_id);
57+
} else {
58+
emitResult({ items, total, request_id: response.request_id }, "json");
6659
}
67-
const headers = ["FILE_ID", "NAME", "SIZE", "PURPOSE"];
68-
const rows = items.map((i) => [i.file_id, i.name, i.size, i.purpose]);
69-
for (const line of formatTable(headers, rows)) emitBare(line);
70-
if (total !== undefined) emitBare(`\nTotal: ${total}`);
71-
emitRequestId(response.request_id, settings.quiet);
7260
},
7361
});

packages/commands/src/commands/dataset/upload.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
uploadDataset,
54
validateDataset,
65
parseDatasetSchemaFlag,
@@ -11,7 +10,7 @@ import {
1110
ExitCode,
1211
type FlagsDef,
1312
} from "bailian-cli-core";
14-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
13+
import { emitResult, emitBare } from "bailian-cli-runtime";
1514

1615
const UPLOAD_FLAGS = {
1716
file: {
@@ -80,7 +79,6 @@ export default defineCommand({
8079
`Supported schemas: chatml, dpo, cpt, tts, image.`,
8180
);
8281
}
83-
const format = detectOutputFormat(settings.output);
8482
// Image schema allows larger ZIPs (1 GB vs 300 MB for text).
8583
const isMediaSchema = schema === "image";
8684

@@ -129,7 +127,7 @@ export default defineCommand({
129127
validate: !flags.noValidate,
130128
schema: schema ?? "auto",
131129
},
132-
format,
130+
"json",
133131
);
134132
return;
135133
}
@@ -142,11 +140,8 @@ export default defineCommand({
142140

143141
if (settings.quiet) {
144142
emitBare(file.file_id);
145-
} else if (format === "text") {
146-
emitBare(`Uploaded ${file.name} → file_id=${file.file_id}`);
147-
emitRequestId(request_id, settings.quiet);
148143
} else {
149-
emitResult({ ...file, request_id }, format);
144+
emitResult({ ...file, request_id }, "json");
150145
}
151146
},
152147
});

packages/commands/src/commands/dataset/validate.ts

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
validateDataset,
54
parseDatasetSchemaFlag,
6-
formatIssue,
75
BailianError,
86
ExitCode,
9-
type ValidationResult,
107
type FlagsDef,
118
} from "bailian-cli-core";
129
import { emitResult, emitBare } from "bailian-cli-runtime";
1310

14-
function formatStats(result: ValidationResult): string[] {
15-
const out: string[] = [];
16-
if (result.stats.totalRecords !== undefined) out.push(`records: ${result.stats.totalRecords}`);
17-
if (result.stats.sampledRecords !== undefined)
18-
out.push(`sampled: ${result.stats.sampledRecords}`);
19-
if (result.stats.bytes !== undefined) out.push(`bytes: ${result.stats.bytes}`);
20-
if (result.stats.durationMs !== undefined) out.push(`took: ${result.stats.durationMs}ms`);
21-
return out;
22-
}
23-
2411
const VALIDATE_FLAGS = {
2512
file: {
2613
type: "string",
@@ -79,8 +66,6 @@ export default defineCommand({
7966
`Supported schemas: chatml, dpo, cpt, tts, image.`,
8067
);
8168
}
82-
const format = detectOutputFormat(settings.output);
83-
8469
if (settings.dryRun) {
8570
emitResult(
8671
{
@@ -89,38 +74,17 @@ export default defineCommand({
8974
full: flags.fullValidate,
9075
schema: schema ?? "auto",
9176
},
92-
format,
77+
"json",
9378
);
9479
return;
9580
}
9681

9782
const result = await validateDataset(filePath, { fullValidate: flags.fullValidate, schema });
9883

99-
if (format === "json") {
100-
// For json output we always emit the structured result, exit code conveys validity.
101-
emitResult(result, format);
102-
} else if (settings.quiet) {
84+
if (settings.quiet) {
10385
emitBare(result.valid ? "ok" : "fail");
10486
} else {
105-
const status = result.valid ? "PASSED" : "FAILED";
106-
emitBare(`Dataset validation ${status} for ${result.filePath}`);
107-
const stats = formatStats(result);
108-
if (stats.length) emitBare(` ${stats.join(" · ")}`);
109-
110-
if (result.errors.length) {
111-
emitBare(`Errors (${result.errors.length}):`);
112-
for (const error of result.errors.slice(0, 20)) emitBare(formatIssue(error));
113-
if (result.errors.length > 20) {
114-
emitBare(` … and ${result.errors.length - 20} more.`);
115-
}
116-
}
117-
if (result.warnings.length) {
118-
emitBare(`Warnings (${result.warnings.length}):`);
119-
for (const warning of result.warnings.slice(0, 10)) emitBare(formatIssue(warning));
120-
if (result.warnings.length > 10) {
121-
emitBare(` … and ${result.warnings.length - 10} more.`);
122-
}
123-
}
87+
emitResult(result, "json");
12488
}
12589

12690
if (!result.valid) {

0 commit comments

Comments
 (0)