Skip to content

Commit 14fc293

Browse files
committed
feat: opt json output & reduce Chinese table name
1 parent 3f29f93 commit 14fc293

9 files changed

Lines changed: 227 additions & 165 deletions

File tree

packages/cli/src/commands/quota/check.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ function formatRatio(usage: number, limit: number): string {
6464
function getStatus(usage: number, limit: number): string {
6565
if (limit <= 0) return "-";
6666
const pct = (usage / limit) * 100;
67-
if (pct >= 100) return "已限流";
68-
if (pct >= 80) return "接近限流";
69-
return "正常";
67+
if (pct >= 100) return "Throttled";
68+
if (pct >= 80) return "Near Limit";
69+
return "Normal";
7070
}
7171

7272
function getNestedRecord(
@@ -193,7 +193,6 @@ function printTable(rows: CheckRow[], noColor: boolean): void {
193193
const yellow = noColor ? (t: string) => t : (t: string) => `\x1b[33m${t}\x1b[0m`;
194194
const red = noColor ? (t: string) => t : (t: string) => `\x1b[31m${t}\x1b[0m`;
195195

196-
const headersCn = ["模型", "RPM 用量/限额", "TPM 用量/限额", "状态"];
197196
const headersEn = ["Model", "RPM Usage/Limit", "TPM Usage/Limit", "Status"];
198197

199198
const tableRows = rows.map((r) => {
@@ -215,36 +214,30 @@ function printTable(rows: CheckRow[], noColor: boolean): void {
215214
return;
216215
}
217216

218-
const widths = headersCn.map((label, col) =>
219-
Math.max(
220-
displayWidth(label),
221-
displayWidth(headersEn[col]),
222-
...tableRows.map((r) => displayWidth(r.cells[col])),
223-
),
217+
const widths = headersEn.map((label, col) =>
218+
Math.max(displayWidth(label), ...tableRows.map((r) => displayWidth(r.cells[col]))),
224219
);
225220

226-
const cnLine = headersCn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
227-
const enLine = headersEn.map((label, col) => dim(padEnd(label, widths[col]))).join(" ");
221+
const headerLine = headersEn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
228222
const separator = widths.map((w) => dim("─".repeat(w))).join("──");
229223

230-
process.stdout.write(cnLine + "\n");
231-
process.stdout.write(enLine + "\n");
224+
process.stdout.write(headerLine + "\n");
232225
process.stdout.write(separator + "\n");
233226

234227
const statusCol = 3;
235228
for (const r of tableRows) {
236229
const cells = r.cells.map((cell, col) => {
237230
if (col === statusCol) {
238-
if (cell === "已限流") return red(padEnd(cell, widths[col]));
239-
if (cell === "接近限流") return yellow(padEnd(cell, widths[col]));
240-
if (cell === "正常") return green(padEnd(cell, widths[col]));
231+
if (cell === "Throttled") return red(padEnd(cell, widths[col]));
232+
if (cell === "Near Limit") return yellow(padEnd(cell, widths[col]));
233+
if (cell === "Normal") return green(padEnd(cell, widths[col]));
241234
}
242235
return padEnd(cell, widths[col]);
243236
});
244237
process.stdout.write(cells.join(" ") + "\n");
245238
}
246239

247-
process.stdout.write(dim(`\n共 ${rows.length} 个模型 (Total: ${rows.length})`) + "\n");
240+
process.stdout.write(dim(`\nTotal: ${rows.length} models`) + "\n");
248241
}
249242

250243
export default defineCommand({

packages/cli/src/commands/quota/history.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ function printTable(records: LimitApplicationItem[], noColor: boolean, total: nu
6565
const bold = noColor ? (t: string) => t : (t: string) => `\x1b[1m${t}\x1b[0m`;
6666
const dim = noColor ? (t: string) => t : (t: string) => `\x1b[2m${t}\x1b[0m`;
6767

68-
const headersCn = ["模型", "Token 账号限流", "申请时间"];
6968
const headersEn = ["Model", "Token Limit", "Applied At"];
7069

7170
const rows = records.map((r) => [
@@ -74,27 +73,21 @@ function printTable(records: LimitApplicationItem[], noColor: boolean, total: nu
7473
formatDateTime(r.gmtCreate),
7574
]);
7675

77-
const widths = headersCn.map((label, col) =>
78-
Math.max(
79-
displayWidth(label),
80-
displayWidth(headersEn[col]),
81-
...rows.map((row) => displayWidth(row[col])),
82-
),
76+
const widths = headersEn.map((label, col) =>
77+
Math.max(displayWidth(label), ...rows.map((row) => displayWidth(row[col]))),
8378
);
8479

85-
const cnLine = headersCn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
86-
const enLine = headersEn.map((label, col) => dim(padEnd(label, widths[col]))).join(" ");
80+
const headerLine = headersEn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
8781
const separator = widths.map((w) => dim("─".repeat(w))).join("──");
8882

89-
process.stdout.write(cnLine + "\n");
90-
process.stdout.write(enLine + "\n");
83+
process.stdout.write(headerLine + "\n");
9184
process.stdout.write(separator + "\n");
9285

9386
for (const row of rows) {
9487
process.stdout.write(row.map((cell, col) => padEnd(cell, widths[col])).join(" ") + "\n");
9588
}
9689

97-
process.stdout.write(dim(`\n共 ${total} 条记录 (Total: ${total})`) + "\n");
90+
process.stdout.write(dim(`\nTotal: ${total} records`) + "\n");
9891
}
9992

10093
export default defineCommand({
@@ -161,11 +154,6 @@ export default defineCommand({
161154
throw err;
162155
}
163156

164-
if (format === "json") {
165-
emitResult(result, format);
166-
return;
167-
}
168-
169157
const resp = extractResponseData(result as Record<string, unknown>);
170158
let records = (resp.records as LimitApplicationItem[]) ?? [];
171159
const total = (resp.items as number) ?? records.length;
@@ -174,6 +162,16 @@ export default defineCommand({
174162
records = records.filter((r) => r.deployedModel === modelFilter);
175163
}
176164

165+
if (format === "json") {
166+
const items = records.map((r) => ({
167+
model: r.deployedModel,
168+
tokenLimit: r.usageLimit,
169+
appliedAt: formatDateTime(r.gmtCreate),
170+
}));
171+
emitResult({ records: items, total: modelFilter ? records.length : total }, format);
172+
return;
173+
}
174+
177175
if (records.length === 0) {
178176
process.stdout.write("No quota change history found.\n");
179177
return;

packages/cli/src/commands/quota/list.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ function printTable(models: ModelWithQpm[], noColor: boolean): void {
108108
const bold = noColor ? (t: string) => t : (t: string) => `\x1b[1m${t}\x1b[0m`;
109109
const dim = noColor ? (t: string) => t : (t: string) => `\x1b[2m${t}\x1b[0m`;
110110

111-
const headersCn = ["模型", "RPM", "TPM", "可设上限 TPM"];
112111
const headersEn = ["Model", "Req/min", "Token/min", "Max TPM"];
113112

114113
const rows = models.map((m) => {
@@ -135,27 +134,21 @@ function printTable(models: ModelWithQpm[], noColor: boolean): void {
135134
return;
136135
}
137136

138-
const widths = headersCn.map((label, col) =>
139-
Math.max(
140-
displayWidth(label),
141-
displayWidth(headersEn[col]),
142-
...rows.map((row) => displayWidth(row[col])),
143-
),
137+
const widths = headersEn.map((label, col) =>
138+
Math.max(displayWidth(label), ...rows.map((row) => displayWidth(row[col]))),
144139
);
145140

146-
const cnLine = headersCn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
147-
const enLine = headersEn.map((label, col) => dim(padEnd(label, widths[col]))).join(" ");
141+
const headerLine = headersEn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
148142
const separator = widths.map((w) => dim("─".repeat(w))).join("──");
149143

150-
process.stdout.write(cnLine + "\n");
151-
process.stdout.write(enLine + "\n");
144+
process.stdout.write(headerLine + "\n");
152145
process.stdout.write(separator + "\n");
153146

154147
for (const row of rows) {
155148
process.stdout.write(row.map((cell, col) => padEnd(cell, widths[col])).join(" ") + "\n");
156149
}
157150

158-
process.stdout.write(dim(`\n共 ${models.length} 个模型 (Total: ${models.length})`) + "\n");
151+
process.stdout.write(dim(`\nTotal: ${models.length} models`) + "\n");
159152
}
160153

161154
export default defineCommand({
@@ -221,7 +214,25 @@ export default defineCommand({
221214
}
222215

223216
if (format === "json") {
224-
emitResult(models, format);
217+
const items = models.map((m) => {
218+
const qpm = m.qpmInfo;
219+
const modelDefault = qpm?.["model-default"];
220+
const userSpec = qpm?.["user-spec"];
221+
222+
const defaultRPM = calculateRPM(modelDefault);
223+
const defaultTPM = calculateTPM(modelDefault);
224+
const currentRPM = calculateRPM(userSpec, modelDefault?.count_limit_period) || defaultRPM;
225+
const currentTPM = calculateTPM(userSpec, modelDefault?.usage_limit_period) || defaultTPM;
226+
const maxTPM = defaultTPM * 2;
227+
228+
return {
229+
model: m.model,
230+
rpm: currentRPM > 0 ? currentRPM : null,
231+
tpm: currentTPM > 0 ? currentTPM : null,
232+
maxTPM: maxTPM > 0 ? maxTPM : null,
233+
};
234+
});
235+
emitResult(items, format);
225236
return;
226237
}
227238

packages/cli/src/commands/usage/free.ts

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ function printTable(
7878
typeMap: Map<string, string>,
7979
noColor: boolean,
8080
): void {
81-
const headersCn = ["模型", "类型", "剩余/总量", "使用率", "过期时间", "用完即停"];
8281
const headersEn = ["Model", "Type", "Remaining/Total", "Usage", "Expires", "Auto-Stop"];
8382

8483
const rows = quotas.map((quota) => {
@@ -102,25 +101,19 @@ function printTable(
102101
];
103102
});
104103

105-
const widths = headersCn.map((label, col) =>
106-
Math.max(
107-
displayWidth(label),
108-
displayWidth(headersEn[col]),
109-
...rows.map((row) => displayWidth(row[col])),
110-
),
104+
const widths = headersEn.map((label, col) =>
105+
Math.max(displayWidth(label), ...rows.map((row) => displayWidth(row[col]))),
111106
);
112107

113108
const dim = noColor ? (text: string) => text : (text: string) => `\x1b[2m${text}\x1b[0m`;
114109
const bold = noColor ? (text: string) => text : (text: string) => `\x1b[1m${text}\x1b[0m`;
115110
const green = noColor ? (text: string) => text : (text: string) => `\x1b[32m${text}\x1b[0m`;
116111
const yellow = noColor ? (text: string) => text : (text: string) => `\x1b[33m${text}\x1b[0m`;
117112

118-
const autoStopCol = headersCn.length - 1;
119-
const cnLine = headersCn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
120-
const enLine = headersEn.map((label, col) => dim(padEnd(label, widths[col]))).join(" ");
113+
const autoStopCol = headersEn.length - 1;
114+
const enLine = headersEn.map((label, col) => bold(padEnd(label, widths[col]))).join(" ");
121115
const separator = widths.map((width) => dim("─".repeat(width))).join("──");
122116

123-
process.stdout.write(cnLine + "\n");
124117
process.stdout.write(enLine + "\n");
125118
process.stdout.write(separator + "\n");
126119

@@ -296,11 +289,6 @@ export default defineCommand({
296289
}),
297290
]);
298291

299-
if (format === "json") {
300-
emitResult(quotaResult, format);
301-
return;
302-
}
303-
304292
const allQuotas = extractQuotas(quotaResult);
305293
let quotas = modelFlag
306294
? allQuotas
@@ -321,14 +309,44 @@ export default defineCommand({
321309
quotas.sort((a, b) => (a.quotaValidityPeriod ?? 0) - (b.quotaValidityPeriod ?? 0));
322310
}
323311

312+
const stopStatuses = extractFreeTierOnlyStatuses(stopResult);
313+
const stopMap = new Map(stopStatuses.map((status) => [status.model, status.freeTierOnly]));
314+
315+
if (format === "json") {
316+
const items = quotas.map((quota) => {
317+
const hasQuota = quota.quotaInitTotal != null && quota.quotaTotal != null;
318+
const used = hasQuota ? quota.quotaInitTotal - quota.quotaTotal : 0;
319+
const stopStatus = stopMap.get(quota.model);
320+
const autoStop =
321+
quota.quotaStatus === "UNKNOWN"
322+
? "unsupported"
323+
: stopStatus === true
324+
? true
325+
: stopStatus === false
326+
? false
327+
: null;
328+
return {
329+
model: quota.model,
330+
type: typeMap.get(quota.model) || null,
331+
remaining: hasQuota ? quota.quotaTotal : null,
332+
total: hasQuota ? quota.quotaInitTotal : null,
333+
usagePercent:
334+
hasQuota && quota.quotaInitTotal > 0
335+
? Math.round((used / quota.quotaInitTotal) * 1000) / 10
336+
: null,
337+
expires: quota.quotaValidityPeriod ? formatDate(quota.quotaValidityPeriod) : null,
338+
autoStop,
339+
};
340+
});
341+
emitResult(items, format);
342+
return;
343+
}
344+
324345
if (quotas.length === 0) {
325346
process.stdout.write("No free-tier quota found.\n");
326347
return;
327348
}
328349

329-
const stopStatuses = extractFreeTierOnlyStatuses(stopResult);
330-
const stopMap = new Map(stopStatuses.map((status) => [status.model, status.freeTierOnly]));
331-
332350
printTable(quotas, stopMap, typeMap, config.noColor);
333351
},
334352
});

0 commit comments

Comments
 (0)