@9000ai/cli 0.6.1 → 0.6.3

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.
@@ -3,11 +3,21 @@ export function registerTaskCommands(parent) {
3
3
  const cmd = parent.command("task").description("Query task status and results");
4
4
  cmd
5
5
  .command("status")
6
- .description("Check task status")
7
- .requiredOption("--task-id <id>", "Task ID")
6
+ .description("Check task or batch status")
7
+ .option("--task-id <id>", "Task ID")
8
+ .option("--batch-id <id>", "Batch ID (shows batch progress + task list)")
8
9
  .option("--fields <list>", "Comma-separated fields to extract (e.g. desc,video_url,likes)")
9
10
  .option("--compact", "One JSON object per line, no indentation")
10
11
  .action(async (opts) => {
12
+ if (!opts.taskId && !opts.batchId) {
13
+ console.error("Error: must provide --task-id or --batch-id");
14
+ process.exit(1);
15
+ }
16
+ if (opts.batchId) {
17
+ const data = await request({ method: "GET", path: `/api/v1/tasks/batch/${opts.batchId}` });
18
+ printJson(data, { fields: opts.fields, compact: opts.compact });
19
+ return;
20
+ }
11
21
  const data = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}` });
12
22
  printJson(data, { fields: opts.fields, compact: opts.compact });
13
23
  });
@@ -1,5 +1,7 @@
1
1
  import { request, printJson, pollUntilDone } from "../client.js";
2
2
  import { loadJsonFile } from "../utils/format.js";
3
+ import { mkdirSync, writeFileSync } from "node:fs";
4
+ import { join, resolve } from "node:path";
3
5
  /** Extract unique video_ids from monitor task output */
4
6
  function extractVideoIdsFromMonitorOutput(output) {
5
7
  const data = (output.data ?? output);
@@ -72,39 +74,52 @@ export function registerTranscribeCommands(parent) {
72
74
  });
73
75
  cmd
74
76
  .command("text")
75
- .description("Extract transcription text from completed task")
77
+ .description("Extract transcription text and save to local file")
76
78
  .requiredOption("--task-id <id>", "Task ID")
79
+ .option("--no-save", "Print text to stdout instead of saving to file")
77
80
  .action(async (opts) => {
78
81
  const taskData = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}` });
79
82
  const inner = taskData.data;
80
- if (!inner || inner.status !== "SUCCESS") {
81
- console.log(`Task status: ${inner?.status ?? "unknown"}`);
82
- if (inner?.status !== "SUCCESS") {
83
- printJson(inner);
84
- return;
85
- }
83
+ if (!inner || String(inner.status).toUpperCase() !== "SUCCESS") {
84
+ console.error(`Task status: ${inner?.status ?? "unknown"}`);
85
+ process.exit(1);
86
86
  }
87
87
  const output = (typeof inner.output === "string" ? JSON.parse(inner.output) : inner.output);
88
88
  const jsonUrl = output?.json_url;
89
89
  if (!jsonUrl) {
90
90
  console.error("No json_url in task output");
91
- printJson(inner);
92
- return;
91
+ process.exit(1);
93
92
  }
94
93
  const controller = new AbortController();
95
94
  const timer = setTimeout(() => controller.abort(), 60_000);
96
95
  try {
97
96
  const res = await fetch(jsonUrl, { signal: controller.signal });
98
97
  const transcript = await res.json();
99
- const text = transcript.text ?? "";
100
- const sentences = (transcript.timecodes?.sentences ?? []);
98
+ const text = String(transcript.text ?? "");
99
+ if (!text) {
100
+ console.error("Transcript text is empty");
101
+ process.exit(1);
102
+ }
103
+ // 用 third_party_task_id (video_id) 或 task_id 做文件名
104
+ const videoId = (inner.third_party_task_id ?? opts.taskId);
105
+ if (!opts.save) {
106
+ // --no-save: 直接输出
107
+ console.log(text);
108
+ return;
109
+ }
110
+ // 落盘到 output/transcripts/{video_id}.txt
111
+ const dir = resolve("output", "transcripts");
112
+ mkdirSync(dir, { recursive: true });
113
+ const filepath = join(dir, `${videoId}.txt`);
114
+ writeFileSync(filepath, text, "utf-8");
115
+ // 只返回摘要给 AI
116
+ const preview = text.length > 100 ? text.slice(0, 100) + "..." : text;
101
117
  printJson({
102
118
  task_id: opts.taskId,
103
- text_field: "text",
104
- sentence_field: "timecodes.sentences[*].text",
105
- text,
106
- sentence_count: sentences.length,
107
- duration_ms: transcript.duration_ms,
119
+ video_id: videoId,
120
+ file: filepath,
121
+ char_count: text.length,
122
+ preview,
108
123
  });
109
124
  }
110
125
  finally {
@@ -133,7 +148,7 @@ export function registerTranscribeCommands(parent) {
133
148
  if (opts.taskId) {
134
149
  const taskResp = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}` });
135
150
  const taskData = (taskResp.data ?? taskResp);
136
- if (taskData.status !== "SUCCESS") {
151
+ if (String(taskData.status).toUpperCase() !== "SUCCESS") {
137
152
  console.error(`Task status: ${taskData.status ?? "unknown"} (need SUCCESS)`);
138
153
  process.exit(1);
139
154
  }
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ const program = new Command();
14
14
  program
15
15
  .name("9000ai")
16
16
  .description("9000AI Toolbox CLI — unified interface for 9000AI platform")
17
- .version("0.6.1");
17
+ .version("0.6.3");
18
18
  registerConfigCommands(program);
19
19
  registerAuthCommands(program);
20
20
  registerSearchCommands(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@9000ai/cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "9000AI Toolbox CLI — unified command-line interface for 9000AI platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,6 +46,8 @@ agent 在对话中确认标题和内容后,直接组装参数调 CLI 就行。
46
46
  | `--type` | 否 | 可选分类:workflow / bug / feature / other |
47
47
  | `--context-json` | 否 | 附加上下文,比如涉及的 skill 名、task_id 等,JSON 格式 |
48
48
 
49
+ **必须带版本号**:提交反馈前先执行 `9000ai --version` 获取当前版本,在 content 末尾附上 `[CLI v0.x.x]`,方便定位问题。
50
+
49
51
  ## 命令
50
52
 
51
53
  查看帮助:
@@ -67,13 +67,18 @@ output-format: task-oriented
67
67
 
68
68
  不要把整份转写 JSON 原样塞进上下文。
69
69
 
70
- 如果只需要原文文案:
70
+ 提取原文文案:
71
71
 
72
72
  ```bash
73
73
  9000ai transcribe text --task-id <task_id>
74
74
  ```
75
75
 
76
- 返回 `text` 字段即可,不要读全量 JSON。
76
+ 这个命令会:
77
+ 1. 下载转写结果,提取纯文本
78
+ 2. 保存到 `output/transcripts/{video_id}.txt`
79
+ 3. 返回文件路径 + 前 100 字预览
80
+
81
+ AI 拿到路径后按需读取,不要一次性把所有文案塞进上下文。如果只需要输出到终端不落盘,加 `--no-save`。
77
82
 
78
83
  ## 命令
79
84
 
@@ -117,7 +122,7 @@ output-format: task-oriented
117
122
  # 正确 — 只取需要的字段
118
123
  9000ai task results --task-id <id> --fields status,output,video_url
119
124
 
120
- # 只要原文 — 用专用命令
125
+ # 只要原文 — 落盘后按需读取
121
126
  9000ai transcribe text --task-id <task_id>
122
127
  ```
123
128