@bty/customer-service-cli 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +20 -0
- package/dist/bin.js +301 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.2 (2026-05-28)
|
|
4
|
+
|
|
5
|
+
**修复:`repair-record` 命令 404 问题**
|
|
6
|
+
|
|
7
|
+
- `repair-record-api` 三处请求从 `getCustomerAgentUrl()`(`customer-agent.bantouyan.com`)改为 `getCsAdminUrl()`(`customer-service-admin.betteryeah.com`)。服务端路由部署在 `apps/cs-admin`,之前打错了 host。
|
|
8
|
+
- 鉴权方式从 Cookie(`auth_token`)改为标准 Bearer token,与 cs-admin headless 调用规范一致。
|
|
9
|
+
|
|
10
|
+
Issue #65
|
|
11
|
+
|
|
12
|
+
## 0.5.1 (2026-05-28)
|
|
13
|
+
|
|
14
|
+
**新增:数据看板(`dashboard`)子命令**
|
|
15
|
+
|
|
16
|
+
- 对接后端 `/v1/dashboard` 看板接口,只产结构化数据,运营报告交由上层(LLM)按场景加工。
|
|
17
|
+
- `dashboard summary [--config-id]`:全局 / 单店 KPI 汇总 + 环比(接待客户数、转人工率、AI 独立承接率)。
|
|
18
|
+
- `dashboard trend [--config-id] [--granularity day/week/month]`:接待量 / 转人工趋势。
|
|
19
|
+
- `dashboard shops`:全部店铺统计列表(默认按转人工客户数降序),横向对比。
|
|
20
|
+
- `dashboard export --start --end [--config-id ...] [--out <path>]`:店铺维度每日明细。两段式(POST 拿 OSS `download_url` → 拉取 CSV),默认解析为 JSON 行(稳定英文 key + 计数转 number),`--out` 落盘原始 CSV。
|
|
21
|
+
- `dashboard intent --config-id`:单店各意图消息级转人工统计。
|
|
22
|
+
- `dashboard intent-conversations --config-id --event-one --event-two`:某意图下会话列表下钻。
|
|
23
|
+
- 复用现有 `request`(`Bearer` + `workspace-id`)/ `getCustomerServiceUrl` / 输出与退出码体系,无额外鉴权逻辑。
|
|
24
|
+
- 口径备注:`接待客户数(customers)` 按客户去重 ≈ 看板"会话/接待量";`AI回复消息数(ai_reply_messages)` 是真实回复条数;`对话轮次 ≈ ai_reply_messages / customers`。**数据 T+1**(`--end` ≤ 昨天),`--start`/`--end` 闭区间。
|
|
25
|
+
|
|
3
26
|
## 0.5.0 (2026-05-28)
|
|
4
27
|
|
|
5
28
|
**Breaking change**
|
package/README.md
CHANGED
|
@@ -582,6 +582,26 @@ cs-cli change-consumer delivery complete <delivery_id> --status completed \
|
|
|
582
582
|
|
|
583
583
|
**xlsx 二进制输出**:`export --output <path>` 必填路径,stdout 仅承载 JSON 报告 `{success:true, data:{path, bytes}}`,不支持 stdout pipe(避免与 JSON-by-default 冲突)。
|
|
584
584
|
|
|
585
|
+
### 数据看板 (`dashboard`)
|
|
586
|
+
|
|
587
|
+
转人工率 / 接待量 / AI 回复量等运营指标。**数据 T+1**(`--end` 不能晚于昨天,否则后端返回 400);`--start` / `--end` 为**闭区间**。渠道枚举:`qianniu`(千牛/淘宝)/ `jingdong` / `pinduoduo` / `douyin`。CLI 只产结构化数据,运营报告由上层(如 LLM)按场景加工。
|
|
588
|
+
|
|
589
|
+
| 命令 | 说明 |
|
|
590
|
+
| --- | --- |
|
|
591
|
+
| `dashboard summary [--config-id <id>] [--start <d>] [--end <d>] [--channel <c>]` | 全局或单店 KPI 汇总 + 环比(不传 `--config-id` 为全店铺聚合) |
|
|
592
|
+
| `dashboard trend [--config-id <id>] [--start <d>] [--end <d>] [--granularity day/week/month] [--channel <c>]` | 趋势(每日/周/月接待客户数、转人工数、转人工率),`--granularity` 默认 `day` |
|
|
593
|
+
| `dashboard shops [--start <d>] [--end <d>] [--channel <c>]` | 全部店铺统计列表(默认按转人工客户数降序),用于横向对比 |
|
|
594
|
+
| `dashboard export --start <d> --end <d> [--config-id <id> ...] [--channel <c>] [--out <path>]` | 店铺维度每日明细。默认解析为 JSON 行;`--out` 落盘原始 CSV。`--config-id` 可重复传,不传=全部店铺 |
|
|
595
|
+
| `dashboard intent --config-id <id> [--start <d>] [--end <d>]` | 单店各意图(一级/二级标签)消息级转人工统计,默认按转人工消息数降序 |
|
|
596
|
+
| `dashboard intent-conversations --config-id <id> --event-one <l> --event-two <l> [--start <d>] [--end <d>] [--page <n>] [--page-size <n>]` | 某意图下会话列表下钻 |
|
|
597
|
+
|
|
598
|
+
**口径要点**:
|
|
599
|
+
|
|
600
|
+
- `summary` / `trend` / `shops` / `intent` 直接透传后端 JSON(`total_customers` / `transfer_rate` / `avg_*` 等英文 key)。
|
|
601
|
+
- `export` 把 CSV 表头映射为稳定英文 key:`date / shop_name / channel / customers / ai_independent_customers / ai_independent_rate / transfer_customers / transfer_rate / ai_reply_messages`;计数字段转 number,比率字段保留原始字符串(如 `"46.0%"`)。
|
|
602
|
+
- **接待客户数(customers)** 按客户去重,是看板口径的"会话/接待量";**AI 回复消息数(ai_reply_messages)** 是真实 AI 回复条数;`对话轮次 ≈ ai_reply_messages / customers`。
|
|
603
|
+
- `dashboard export --out <path>` 落盘原始 CSV 时,stdout 仅返回 `{path, bytes, count}`。
|
|
604
|
+
|
|
585
605
|
## 输出格式
|
|
586
606
|
|
|
587
607
|
默认输出 JSON:
|
package/dist/bin.js
CHANGED
|
@@ -1164,6 +1164,293 @@ function registerConversationCommand(program2) {
|
|
|
1164
1164
|
});
|
|
1165
1165
|
}
|
|
1166
1166
|
|
|
1167
|
+
// src/client/dashboard-api.ts
|
|
1168
|
+
var DASHBOARD_PREFIX = "/v1/dashboard";
|
|
1169
|
+
async function getDashboardSummary(opts) {
|
|
1170
|
+
const request = createRequest();
|
|
1171
|
+
const path5 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/summary` : `${DASHBOARD_PREFIX}/summary`;
|
|
1172
|
+
const query = {};
|
|
1173
|
+
if (opts.startDate) query.start_date = opts.startDate;
|
|
1174
|
+
if (opts.endDate) query.end_date = opts.endDate;
|
|
1175
|
+
if (opts.channel) query.channel = opts.channel;
|
|
1176
|
+
return request(getCustomerServiceUrl(), path5, { method: "GET", query });
|
|
1177
|
+
}
|
|
1178
|
+
async function getDashboardTrend(opts) {
|
|
1179
|
+
const request = createRequest();
|
|
1180
|
+
const path5 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/trend` : `${DASHBOARD_PREFIX}/trend`;
|
|
1181
|
+
const query = {};
|
|
1182
|
+
if (opts.startDate) query.start_date = opts.startDate;
|
|
1183
|
+
if (opts.endDate) query.end_date = opts.endDate;
|
|
1184
|
+
if (opts.granularity) query.granularity = opts.granularity;
|
|
1185
|
+
if (opts.channel) query.channel = opts.channel;
|
|
1186
|
+
return request(getCustomerServiceUrl(), path5, { method: "GET", query });
|
|
1187
|
+
}
|
|
1188
|
+
async function listShopStatistics(opts) {
|
|
1189
|
+
const request = createRequest();
|
|
1190
|
+
const query = {};
|
|
1191
|
+
if (opts.startDate) query.start_date = opts.startDate;
|
|
1192
|
+
if (opts.endDate) query.end_date = opts.endDate;
|
|
1193
|
+
if (opts.channel) query.channel = opts.channel;
|
|
1194
|
+
return request(getCustomerServiceUrl(), `${DASHBOARD_PREFIX}/shop-statistics`, {
|
|
1195
|
+
method: "GET",
|
|
1196
|
+
query
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
async function getIntentStatistics(opts) {
|
|
1200
|
+
const request = createRequest();
|
|
1201
|
+
const query = {};
|
|
1202
|
+
if (opts.startDate) query.start_date = opts.startDate;
|
|
1203
|
+
if (opts.endDate) query.end_date = opts.endDate;
|
|
1204
|
+
return request(
|
|
1205
|
+
getCustomerServiceUrl(),
|
|
1206
|
+
`${DASHBOARD_PREFIX}/${opts.configId}/intent-statistics`,
|
|
1207
|
+
{ method: "GET", query }
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
async function listIntentConversations(opts) {
|
|
1211
|
+
const request = createRequest();
|
|
1212
|
+
const query = {
|
|
1213
|
+
event_one: opts.eventOne,
|
|
1214
|
+
event_two: opts.eventTwo
|
|
1215
|
+
};
|
|
1216
|
+
if (opts.startDate) query.start_date = opts.startDate;
|
|
1217
|
+
if (opts.endDate) query.end_date = opts.endDate;
|
|
1218
|
+
if (opts.page) query.page = opts.page;
|
|
1219
|
+
if (opts.pageSize) query.page_size = opts.pageSize;
|
|
1220
|
+
return request(
|
|
1221
|
+
getCustomerServiceUrl(),
|
|
1222
|
+
`${DASHBOARD_PREFIX}/${opts.configId}/intent-conversations`,
|
|
1223
|
+
{ method: "GET", query }
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
var EXPORT_HEADER_MAP = {
|
|
1227
|
+
\u65E5\u671F: "date",
|
|
1228
|
+
\u5E97\u94FA\u540D\u79F0: "shop_name",
|
|
1229
|
+
\u6E20\u9053: "channel",
|
|
1230
|
+
\u63A5\u5F85\u5BA2\u6237\u6570: "customers",
|
|
1231
|
+
AI\u72EC\u7ACB\u627F\u63A5\u5BA2\u6237\u6570: "ai_independent_customers",
|
|
1232
|
+
AI\u72EC\u7ACB\u627F\u63A5\u7387: "ai_independent_rate",
|
|
1233
|
+
\u8F6C\u4EBA\u5DE5\u5BA2\u6237\u6570: "transfer_customers",
|
|
1234
|
+
\u8F6C\u4EBA\u5DE5\u7387: "transfer_rate",
|
|
1235
|
+
AI\u56DE\u590D\u6D88\u606F\u6570: "ai_reply_messages"
|
|
1236
|
+
};
|
|
1237
|
+
var EXPORT_NUMERIC_KEYS = /* @__PURE__ */ new Set([
|
|
1238
|
+
"customers",
|
|
1239
|
+
"ai_independent_customers",
|
|
1240
|
+
"transfer_customers",
|
|
1241
|
+
"ai_reply_messages"
|
|
1242
|
+
]);
|
|
1243
|
+
function parseCsv(text) {
|
|
1244
|
+
const s = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
1245
|
+
const rows = [];
|
|
1246
|
+
let row = [];
|
|
1247
|
+
let field = "";
|
|
1248
|
+
let inQuotes = false;
|
|
1249
|
+
for (let i = 0; i < s.length; i++) {
|
|
1250
|
+
const c = s[i];
|
|
1251
|
+
if (inQuotes) {
|
|
1252
|
+
if (c === '"') {
|
|
1253
|
+
if (s[i + 1] === '"') {
|
|
1254
|
+
field += '"';
|
|
1255
|
+
i++;
|
|
1256
|
+
} else {
|
|
1257
|
+
inQuotes = false;
|
|
1258
|
+
}
|
|
1259
|
+
} else {
|
|
1260
|
+
field += c;
|
|
1261
|
+
}
|
|
1262
|
+
} else if (c === '"') {
|
|
1263
|
+
inQuotes = true;
|
|
1264
|
+
} else if (c === ",") {
|
|
1265
|
+
row.push(field);
|
|
1266
|
+
field = "";
|
|
1267
|
+
} else if (c === "\n") {
|
|
1268
|
+
row.push(field);
|
|
1269
|
+
rows.push(row);
|
|
1270
|
+
row = [];
|
|
1271
|
+
field = "";
|
|
1272
|
+
} else if (c !== "\r") {
|
|
1273
|
+
field += c;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
if (field.length > 0 || row.length > 0) {
|
|
1277
|
+
row.push(field);
|
|
1278
|
+
rows.push(row);
|
|
1279
|
+
}
|
|
1280
|
+
return rows;
|
|
1281
|
+
}
|
|
1282
|
+
function csvToRows(csv) {
|
|
1283
|
+
const table = parseCsv(csv).filter((r) => r.some((cell) => cell.trim() !== ""));
|
|
1284
|
+
if (table.length === 0) return [];
|
|
1285
|
+
const headers = table[0].map((h) => EXPORT_HEADER_MAP[h.trim()] ?? h.trim());
|
|
1286
|
+
return table.slice(1).map((cells) => {
|
|
1287
|
+
const obj = {};
|
|
1288
|
+
headers.forEach((key, idx) => {
|
|
1289
|
+
const raw = cells[idx] ?? "";
|
|
1290
|
+
if (EXPORT_NUMERIC_KEYS.has(key)) {
|
|
1291
|
+
const n = Number(raw);
|
|
1292
|
+
obj[key] = Number.isNaN(n) ? raw : n;
|
|
1293
|
+
} else {
|
|
1294
|
+
obj[key] = raw;
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
return obj;
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
async function exportShopData(opts) {
|
|
1301
|
+
const request = createRequest();
|
|
1302
|
+
const body = {
|
|
1303
|
+
start_date: opts.startDate,
|
|
1304
|
+
end_date: opts.endDate
|
|
1305
|
+
};
|
|
1306
|
+
if (opts.configIds && opts.configIds.length > 0) body.config_ids = opts.configIds;
|
|
1307
|
+
if (opts.channel) body.channel = opts.channel;
|
|
1308
|
+
const data = await request(
|
|
1309
|
+
getCustomerServiceUrl(),
|
|
1310
|
+
`${DASHBOARD_PREFIX}/export`,
|
|
1311
|
+
{ method: "POST", body }
|
|
1312
|
+
);
|
|
1313
|
+
const downloadUrl = data?.download_url;
|
|
1314
|
+
if (!downloadUrl) {
|
|
1315
|
+
throw new APIError(1, "\u5BFC\u51FA\u63A5\u53E3\u672A\u8FD4\u56DE download_url");
|
|
1316
|
+
}
|
|
1317
|
+
const timeoutMs = getRuntimeRequestTimeoutMs() ?? 6e4;
|
|
1318
|
+
const resp = await fetch(downloadUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
1319
|
+
if (!resp.ok) {
|
|
1320
|
+
throw new APIError(resp.status, `\u4E0B\u8F7D\u5BFC\u51FA CSV \u5931\u8D25 HTTP ${resp.status}`);
|
|
1321
|
+
}
|
|
1322
|
+
const csv = await resp.text();
|
|
1323
|
+
return { downloadUrl, csv, rows: csvToRows(csv) };
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// src/utils/file-output.ts
|
|
1327
|
+
import fs5 from "fs";
|
|
1328
|
+
import path4 from "path";
|
|
1329
|
+
async function writeBinaryToFile(filePath, buffer) {
|
|
1330
|
+
try {
|
|
1331
|
+
const dir = path4.dirname(filePath);
|
|
1332
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
1333
|
+
fs5.writeFileSync(filePath, buffer);
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1336
|
+
throw new APIError(1, `\u6587\u4EF6\u5199\u5165\u5931\u8D25: ${msg}`);
|
|
1337
|
+
}
|
|
1338
|
+
return { path: filePath, bytes: buffer.length };
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// src/commands/dashboard.ts
|
|
1342
|
+
function collect(value, previous) {
|
|
1343
|
+
return previous.concat([value]);
|
|
1344
|
+
}
|
|
1345
|
+
function registerDashboardCommand(program2) {
|
|
1346
|
+
const dashboard = program2.command("dashboard").description(
|
|
1347
|
+
"\u6570\u636E\u770B\u677F \u2014\u2014 \u8F6C\u4EBA\u5DE5\u7387/\u63A5\u5F85\u91CF/AI\u56DE\u590D\u91CF\u7B49\u8FD0\u8425\u6307\u6807\uFF08\u6570\u636E T+1\uFF0Cend \u2264 \u6628\u5929\uFF1Bstart/end \u4E3A\u95ED\u533A\u95F4\uFF09\u3002\u53EA\u4EA7\u7ED3\u6784\u5316\u6570\u636E\uFF0C\u62A5\u544A\u7531\u4E0A\u5C42\u6309\u573A\u666F\u52A0\u5DE5"
|
|
1348
|
+
);
|
|
1349
|
+
dashboard.command("summary").description(
|
|
1350
|
+
"\u5168\u5C40\u6216\u5355\u5E97\u94FA KPI \u6C47\u603B + \u73AF\u6BD4\uFF08\u63A5\u5F85\u5BA2\u6237\u6570\u3001\u8F6C\u4EBA\u5DE5\u7387\u3001AI\u72EC\u7ACB\u627F\u63A5\u7387\uFF09\u3002\u4F20 --config-id \u67E5\u5355\u5E97"
|
|
1351
|
+
).option("--config-id <id>", "\u5E97\u94FA\u914D\u7F6E ID\uFF08\u4E0D\u4F20=\u5168\u5E97\u94FA\u805A\u5408\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5").option("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5\uFF0C\u4E0D\u80FD\u665A\u4E8E\u6628\u5929").option("--channel <channel>", "\u6E20\u9053\u7B5B\u9009: qianniu | jingdong | pinduoduo | douyin").action(async (opts) => {
|
|
1352
|
+
try {
|
|
1353
|
+
const data = await getDashboardSummary({
|
|
1354
|
+
configId: opts.configId,
|
|
1355
|
+
startDate: opts.start,
|
|
1356
|
+
endDate: opts.end,
|
|
1357
|
+
channel: opts.channel
|
|
1358
|
+
});
|
|
1359
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
1360
|
+
} catch (err) {
|
|
1361
|
+
reportCaughtError(err);
|
|
1362
|
+
process.exit(toExitCode(err));
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
dashboard.command("trend").description(
|
|
1366
|
+
"\u5168\u5C40\u6216\u5355\u5E97\u94FA\u8D8B\u52BF\uFF08\u6BCF\u65E5/\u5468/\u6708\u63A5\u5F85\u5BA2\u6237\u6570\u3001\u8F6C\u4EBA\u5DE5\u6570\u3001\u8F6C\u4EBA\u5DE5\u7387\uFF09\u3002\u4F20 --config-id \u67E5\u5355\u5E97"
|
|
1367
|
+
).option("--config-id <id>", "\u5E97\u94FA\u914D\u7F6E ID\uFF08\u4E0D\u4F20=\u5168\u5E97\u94FA\u805A\u5408\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5").option("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5\uFF0C\u4E0D\u80FD\u665A\u4E8E\u6628\u5929").option("--granularity <g>", "\u7C92\u5EA6: day | week | month", "day").option("--channel <channel>", "\u6E20\u9053\u7B5B\u9009: qianniu | jingdong | pinduoduo | douyin").action(async (opts) => {
|
|
1368
|
+
try {
|
|
1369
|
+
const data = await getDashboardTrend({
|
|
1370
|
+
configId: opts.configId,
|
|
1371
|
+
startDate: opts.start,
|
|
1372
|
+
endDate: opts.end,
|
|
1373
|
+
granularity: opts.granularity,
|
|
1374
|
+
channel: opts.channel
|
|
1375
|
+
});
|
|
1376
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
1377
|
+
} catch (err) {
|
|
1378
|
+
reportCaughtError(err);
|
|
1379
|
+
process.exit(toExitCode(err));
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
dashboard.command("shops").description("\u5168\u90E8\u5E97\u94FA\u7EDF\u8BA1\u5217\u8868\uFF08\u9ED8\u8BA4\u6309\u8F6C\u4EBA\u5DE5\u5BA2\u6237\u6570\u964D\u5E8F\uFF09\uFF0C\u7528\u4E8E\u6A2A\u5411\u5BF9\u6BD4").option("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5").option("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5\uFF0C\u4E0D\u80FD\u665A\u4E8E\u6628\u5929").option("--channel <channel>", "\u6E20\u9053\u7B5B\u9009: qianniu | jingdong | pinduoduo | douyin").action(async (opts) => {
|
|
1383
|
+
try {
|
|
1384
|
+
const data = await listShopStatistics({
|
|
1385
|
+
startDate: opts.start,
|
|
1386
|
+
endDate: opts.end,
|
|
1387
|
+
channel: opts.channel
|
|
1388
|
+
});
|
|
1389
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
1390
|
+
} catch (err) {
|
|
1391
|
+
reportCaughtError(err);
|
|
1392
|
+
process.exit(toExitCode(err));
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
dashboard.command("export").description(
|
|
1396
|
+
"\u5BFC\u51FA\u5E97\u94FA\u7EF4\u5EA6\u6BCF\u65E5\u660E\u7EC6\uFF08\u63A5\u5F85\u5BA2\u6237\u6570/AI\u72EC\u7ACB\u627F\u63A5/\u8F6C\u4EBA\u5DE5/AI\u56DE\u590D\u6D88\u606F\u6570\uFF09\u3002\u9ED8\u8BA4\u89E3\u6790\u4E3A JSON \u884C\uFF1B--out \u843D\u76D8\u539F\u59CB CSV\u3002\u53EF\u91CD\u590D --config-id \u9650\u5B9A\u5E97\u94FA"
|
|
1397
|
+
).requiredOption("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u5FC5\u586B").requiredOption("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u5FC5\u586B\uFF0C\u4E0D\u80FD\u665A\u4E8E\u6628\u5929").option("--config-id <id>", "\u5E97\u94FA\u914D\u7F6E ID\uFF08\u53EF\u91CD\u590D\u4F20\uFF1B\u4E0D\u4F20=\u5168\u90E8\u5E97\u94FA\uFF09", collect, []).option("--channel <channel>", "\u6E20\u9053\u7B5B\u9009: qianniu | jingdong | pinduoduo | douyin").option("--out <path>", "\u843D\u76D8\u539F\u59CB CSV \u8DEF\u5F84\uFF08\u7236\u76EE\u5F55\u81EA\u52A8 mkdir -p\uFF09").action(async (opts) => {
|
|
1398
|
+
try {
|
|
1399
|
+
const result = await exportShopData({
|
|
1400
|
+
startDate: opts.start,
|
|
1401
|
+
endDate: opts.end,
|
|
1402
|
+
configIds: opts.configId,
|
|
1403
|
+
channel: opts.channel
|
|
1404
|
+
});
|
|
1405
|
+
if (opts.out) {
|
|
1406
|
+
const { path: path5, bytes } = await writeBinaryToFile(
|
|
1407
|
+
opts.out,
|
|
1408
|
+
Buffer.from(result.csv, "utf-8")
|
|
1409
|
+
);
|
|
1410
|
+
formatOutput(
|
|
1411
|
+
{ success: true, data: { path: path5, bytes, count: result.rows.length } },
|
|
1412
|
+
program2.opts().table
|
|
1413
|
+
);
|
|
1414
|
+
} else {
|
|
1415
|
+
formatOutput({ success: true, data: result.rows }, program2.opts().table);
|
|
1416
|
+
}
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
reportCaughtError(err);
|
|
1419
|
+
process.exit(toExitCode(err));
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
dashboard.command("intent").description("\u5355\u5E97\u94FA\u5404\u610F\u56FE\uFF08\u4E00\u7EA7/\u4E8C\u7EA7\u6807\u7B7E\uFF09\u7684\u6D88\u606F\u7EA7\u8F6C\u4EBA\u5DE5\u7EDF\u8BA1\uFF0C\u9ED8\u8BA4\u6309\u8F6C\u4EBA\u5DE5\u6D88\u606F\u6570\u964D\u5E8F").requiredOption("--config-id <id>", "\u5E97\u94FA\u914D\u7F6E ID\uFF08\u5FC5\u586B\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5").option("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u6628\u65E5\uFF0C\u4E0D\u80FD\u665A\u4E8E\u6628\u5929").action(async (opts) => {
|
|
1423
|
+
try {
|
|
1424
|
+
const data = await getIntentStatistics({
|
|
1425
|
+
configId: opts.configId,
|
|
1426
|
+
startDate: opts.start,
|
|
1427
|
+
endDate: opts.end
|
|
1428
|
+
});
|
|
1429
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
1430
|
+
} catch (err) {
|
|
1431
|
+
reportCaughtError(err);
|
|
1432
|
+
process.exit(toExitCode(err));
|
|
1433
|
+
}
|
|
1434
|
+
});
|
|
1435
|
+
dashboard.command("intent-conversations").description("\u67D0\u610F\u56FE\u4E0B\u7684\u4F1A\u8BDD\u5217\u8868\u4E0B\u94BB\uFF08\u542B\u8BE5\u610F\u56FE\u5728\u4F1A\u8BDD\u4E2D\u7684\u8F6C\u4EBA\u5DE5\u6B21\u6570\uFF09").requiredOption("--config-id <id>", "\u5E97\u94FA\u914D\u7F6E ID\uFF08\u5FC5\u586B\uFF09").requiredOption("--event-one <label>", "\u4E00\u7EA7\u610F\u56FE\uFF08\u5FC5\u586B\uFF09").requiredOption("--event-two <label>", "\u4E8C\u7EA7\u610F\u56FE\uFF08\u5FC5\u586B\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)").option("--end <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)").option("--page <number>", "\u9875\u7801", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF\uFF08\u6700\u5927 100\uFF09", "20").action(async (opts) => {
|
|
1436
|
+
try {
|
|
1437
|
+
const data = await listIntentConversations({
|
|
1438
|
+
configId: opts.configId,
|
|
1439
|
+
eventOne: opts.eventOne,
|
|
1440
|
+
eventTwo: opts.eventTwo,
|
|
1441
|
+
startDate: opts.start,
|
|
1442
|
+
endDate: opts.end,
|
|
1443
|
+
page: Number(opts.page),
|
|
1444
|
+
pageSize: Number(opts.pageSize)
|
|
1445
|
+
});
|
|
1446
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
1447
|
+
} catch (err) {
|
|
1448
|
+
reportCaughtError(err);
|
|
1449
|
+
process.exit(toExitCode(err));
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1167
1454
|
// src/client/debug-api.ts
|
|
1168
1455
|
var DEFAULT_FLOW_WORKSPACE_ID = "531c14d1ece047cbaec22914e1f1364d";
|
|
1169
1456
|
async function createDebugConversation(opts) {
|
|
@@ -1801,7 +2088,7 @@ async function batchReassignOwner(params) {
|
|
|
1801
2088
|
}
|
|
1802
2089
|
|
|
1803
2090
|
// src/utils/batch-input.ts
|
|
1804
|
-
import
|
|
2091
|
+
import fs6 from "fs";
|
|
1805
2092
|
function parseIdsInput(opts) {
|
|
1806
2093
|
const hasIds = opts.ids !== void 0 && opts.ids.trim() !== "";
|
|
1807
2094
|
const hasFile = opts.idsFile !== void 0 && opts.idsFile.trim() !== "";
|
|
@@ -1818,7 +2105,7 @@ function parseIdsInput(opts) {
|
|
|
1818
2105
|
const filePath = opts.idsFile;
|
|
1819
2106
|
let content;
|
|
1820
2107
|
try {
|
|
1821
|
-
content =
|
|
2108
|
+
content = fs6.readFileSync(filePath, "utf8");
|
|
1822
2109
|
} catch (err) {
|
|
1823
2110
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1824
2111
|
throw new Error(`\u8BFB\u53D6 --ids-file \u5931\u8D25: ${msg}`);
|
|
@@ -1840,7 +2127,7 @@ function parseIdsInput(opts) {
|
|
|
1840
2127
|
}
|
|
1841
2128
|
|
|
1842
2129
|
// src/utils/issue-batch-input.ts
|
|
1843
|
-
import
|
|
2130
|
+
import fs7 from "fs";
|
|
1844
2131
|
var PRIORITY_VALUES = ["critical", "high", "medium", "low"];
|
|
1845
2132
|
function readSource(opts) {
|
|
1846
2133
|
const hasFile = typeof opts.file === "string" && opts.file.trim() !== "";
|
|
@@ -1853,7 +2140,7 @@ function readSource(opts) {
|
|
|
1853
2140
|
}
|
|
1854
2141
|
if (hasFile) {
|
|
1855
2142
|
try {
|
|
1856
|
-
return
|
|
2143
|
+
return fs7.readFileSync(opts.file, "utf8");
|
|
1857
2144
|
} catch (err) {
|
|
1858
2145
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1859
2146
|
throw new Error(`\u8BFB\u53D6 --file \u5931\u8D25: ${msg}`);
|
|
@@ -2485,7 +2772,7 @@ async function resolveSessionsForIssues(issues, workspaceId) {
|
|
|
2485
2772
|
}
|
|
2486
2773
|
|
|
2487
2774
|
// src/commands/knowledge.ts
|
|
2488
|
-
import
|
|
2775
|
+
import fs8 from "fs";
|
|
2489
2776
|
|
|
2490
2777
|
// src/client/knowledge-api.ts
|
|
2491
2778
|
async function listExternalKnowledge(opts) {
|
|
@@ -2591,7 +2878,7 @@ async function deleteKnowledgeContent(opts) {
|
|
|
2591
2878
|
// src/commands/knowledge.ts
|
|
2592
2879
|
function readContentArg(value) {
|
|
2593
2880
|
if (value.startsWith("@")) {
|
|
2594
|
-
return
|
|
2881
|
+
return fs8.readFileSync(value.slice(1), "utf-8");
|
|
2595
2882
|
}
|
|
2596
2883
|
return value;
|
|
2597
2884
|
}
|
|
@@ -3720,29 +4007,23 @@ async function listRepairRecords(opts) {
|
|
|
3720
4007
|
if (opts.workspaceId) query.workspace_id = opts.workspaceId;
|
|
3721
4008
|
if (opts.page) query.page = opts.page;
|
|
3722
4009
|
if (opts.pageSize) query.page_size = opts.pageSize;
|
|
3723
|
-
return request(
|
|
4010
|
+
return request(getCsAdminUrl(), PATH_PREFIX2, {
|
|
3724
4011
|
method: "GET",
|
|
3725
|
-
query
|
|
3726
|
-
headers: buildCookieHeaders(),
|
|
3727
|
-
skipAuth: true
|
|
4012
|
+
query
|
|
3728
4013
|
});
|
|
3729
4014
|
}
|
|
3730
4015
|
async function createRepairRecord(data) {
|
|
3731
4016
|
const request = createRequest();
|
|
3732
|
-
return request(
|
|
4017
|
+
return request(getCsAdminUrl(), PATH_PREFIX2, {
|
|
3733
4018
|
method: "POST",
|
|
3734
|
-
body: data
|
|
3735
|
-
headers: buildCookieHeaders(),
|
|
3736
|
-
skipAuth: true
|
|
4019
|
+
body: data
|
|
3737
4020
|
});
|
|
3738
4021
|
}
|
|
3739
4022
|
async function updateRepairRecord(recordId, data) {
|
|
3740
4023
|
const request = createRequest();
|
|
3741
|
-
return request(
|
|
4024
|
+
return request(getCsAdminUrl(), `${PATH_PREFIX2}/${recordId}`, {
|
|
3742
4025
|
method: "PUT",
|
|
3743
|
-
body: data
|
|
3744
|
-
headers: buildCookieHeaders(),
|
|
3745
|
-
skipAuth: true
|
|
4026
|
+
body: data
|
|
3746
4027
|
});
|
|
3747
4028
|
}
|
|
3748
4029
|
|
|
@@ -4014,21 +4295,6 @@ function registerSACommand(program2) {
|
|
|
4014
4295
|
// src/commands/testset.ts
|
|
4015
4296
|
import fs9 from "fs";
|
|
4016
4297
|
|
|
4017
|
-
// src/utils/file-output.ts
|
|
4018
|
-
import fs8 from "fs";
|
|
4019
|
-
import path4 from "path";
|
|
4020
|
-
async function writeBinaryToFile(filePath, buffer) {
|
|
4021
|
-
try {
|
|
4022
|
-
const dir = path4.dirname(filePath);
|
|
4023
|
-
fs8.mkdirSync(dir, { recursive: true });
|
|
4024
|
-
fs8.writeFileSync(filePath, buffer);
|
|
4025
|
-
} catch (err) {
|
|
4026
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
4027
|
-
throw new APIError(1, `\u6587\u4EF6\u5199\u5165\u5931\u8D25: ${msg}`);
|
|
4028
|
-
}
|
|
4029
|
-
return { path: filePath, bytes: buffer.length };
|
|
4030
|
-
}
|
|
4031
|
-
|
|
4032
4298
|
// src/client/testset-api.ts
|
|
4033
4299
|
function unwrapPaginated(raw, fallbackPageSize) {
|
|
4034
4300
|
return {
|
|
@@ -4698,7 +4964,7 @@ var require2 = createRequire(import.meta.url);
|
|
|
4698
4964
|
var { version } = require2("../package.json");
|
|
4699
4965
|
var program = new Command();
|
|
4700
4966
|
program.name("cs-cli").description(
|
|
4701
|
-
"BetterYeah AI \u5BA2\u670D\u5E73\u53F0 CLI\u3002\u6838\u5FC3\u6982\u5FF5\uFF1Aworkspace\uFF08\u5DE5\u4F5C\u7A7A\u95F4\uFF09\u2192 agent\uFF08AI \u5BA2\u670D\u673A\u5668\u4EBA\uFF09\u2192 SA/product/FAQ\uFF08\u77E5\u8BC6\u914D\u7F6E\uFF09\u2192 issue\uFF08\u5DE5\u5355\uFF09\u2192 debug\uFF08\u8C03\u8BD5\u9A8C\u8BC1\uFF09\u2192 monitor\uFF08\u8FD0\u8425\u76D1\u63A7\uFF09\u2192 repair-record\uFF08\u4FEE\u590D\u5BA1\u8BA1\uFF09\u2192 change-consumer\uFF08\u5546\u54C1\u53D8\u66F4\u4E8B\u4EF6\u6D88\u8D39\uFF09\u3002\u6240\u6709\u547D\u4EE4\u9ED8\u8BA4\u8F93\u51FA JSON\uFF0C\u8FFD\u52A0 --table \u53EF\u5207\u6362\u4E3A\u4EBA\u7C7B\u53EF\u8BFB\u8868\u683C"
|
|
4967
|
+
"BetterYeah AI \u5BA2\u670D\u5E73\u53F0 CLI\u3002\u6838\u5FC3\u6982\u5FF5\uFF1Aworkspace\uFF08\u5DE5\u4F5C\u7A7A\u95F4\uFF09\u2192 agent\uFF08AI \u5BA2\u670D\u673A\u5668\u4EBA\uFF09\u2192 SA/product/FAQ\uFF08\u77E5\u8BC6\u914D\u7F6E\uFF09\u2192 issue\uFF08\u5DE5\u5355\uFF09\u2192 debug\uFF08\u8C03\u8BD5\u9A8C\u8BC1\uFF09\u2192 monitor\uFF08\u8FD0\u8425\u76D1\u63A7\uFF09\u2192 dashboard\uFF08\u6570\u636E\u770B\u677F\uFF09\u2192 repair-record\uFF08\u4FEE\u590D\u5BA1\u8BA1\uFF09\u2192 change-consumer\uFF08\u5546\u54C1\u53D8\u66F4\u4E8B\u4EF6\u6D88\u8D39\uFF09\u3002\u6240\u6709\u547D\u4EE4\u9ED8\u8BA4\u8F93\u51FA JSON\uFF0C\u8FFD\u52A0 --table \u53EF\u5207\u6362\u4E3A\u4EBA\u7C7B\u53EF\u8BFB\u8868\u683C"
|
|
4702
4968
|
).version(version).option("--table", "\u4EE5\u8868\u683C\u5F62\u5F0F\u8F93\u51FA\uFF08\u9ED8\u8BA4 JSON\uFF09\u3002\u4EBA\u5DE5\u67E5\u770B\u65F6\u4F7F\u7528", false).option("--workspace <id>", "\u4E34\u65F6\u8986\u76D6\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4 ID\uFF0C\u4E0D\u4FEE\u6539\u6301\u4E45\u5316\u914D\u7F6E").option(
|
|
4703
4969
|
"--request-timeout <ms>",
|
|
4704
4970
|
"\u5355\u4E2A HTTP \u8BF7\u6C42\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09\uFF0C\u590D\u6742 Agent \u56DE\u590D\u5EFA\u8BAE\u8C03\u9AD8\u3002\u4E0D\u8981\u5199 --timeout\uFF0C\u90A3\u662F\u5B50\u547D\u4EE4\u7684\u8F6E\u8BE2\u7A97\u53E3\uFF08\u79D2\uFF09",
|
|
@@ -4733,6 +4999,7 @@ registerFaqCommand(program);
|
|
|
4733
4999
|
registerConversationCommand(program);
|
|
4734
5000
|
registerDebugCommand(program);
|
|
4735
5001
|
registerMonitorCommand(program);
|
|
5002
|
+
registerDashboardCommand(program);
|
|
4736
5003
|
registerRepairRecordCommand(program);
|
|
4737
5004
|
registerOperationsRecordCommand(program);
|
|
4738
5005
|
registerChangeConsumerCommand(program);
|