@9000ai/cli 0.6.3 → 0.6.5
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/dist/commands/feedback.js +4 -1
- package/dist/commands/init.js +14 -6
- package/dist/commands/monitor.js +7 -4
- package/dist/commands/search.js +2 -2
- package/dist/commands/task.js +5 -3
- package/dist/commands/transcribe.js +11 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/9000AI-hub/SKILL.md +8 -1
- package/skills/9000AI-hub/init/templates/agents/content-agent.md +15 -0
- package/skills/9000AI-hub/init/templates/benchmarks/README.md +70 -0
- package/skills/9000AI-hub/init/templates/benchmarks/index.json +1 -0
- package/skills/9000AI-hub/init/templates/guide.md +20 -8
|
@@ -38,11 +38,14 @@ export function registerFeedbackCommands(parent) {
|
|
|
38
38
|
.description("List my submitted feedback")
|
|
39
39
|
.option("--page <n>", "Page number", "1")
|
|
40
40
|
.option("--page-size <n>", "Items per page", "20")
|
|
41
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
42
|
+
.option("--fields <list>", "Comma-separated fields to extract")
|
|
43
|
+
.option("--compact", "One JSON object per line")
|
|
41
44
|
.action(async (opts) => {
|
|
42
45
|
const data = await request({
|
|
43
46
|
method: "GET",
|
|
44
47
|
path: `/api/v1/feedback?page=${opts.page}&page_size=${opts.pageSize}`,
|
|
45
48
|
});
|
|
46
|
-
printJson(data);
|
|
49
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
47
50
|
});
|
|
48
51
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, copyFileSync, readFileSync, readdirSync, statSyn
|
|
|
2
2
|
import { join, relative } from "path";
|
|
3
3
|
import { resolveSkillsPath } from "../config.js";
|
|
4
4
|
/** User data directories — never overwrite even with --force */
|
|
5
|
-
const USER_DATA_DIRS = ["profile", "claims", "inbox", "projects"];
|
|
5
|
+
const USER_DATA_DIRS = ["profile", "claims", "inbox", "projects", "benchmarks"];
|
|
6
6
|
function filesEqual(a, b) {
|
|
7
7
|
try {
|
|
8
8
|
return readFileSync(a).equals(readFileSync(b));
|
|
@@ -84,6 +84,8 @@ export function registerInitCommand(program) {
|
|
|
84
84
|
}
|
|
85
85
|
const { created, updated, skipped, outdated } = copyTemplates(templatesDir, dest, dest, !!opts.force);
|
|
86
86
|
// Output summary
|
|
87
|
+
const isFirstTime = created.length > 0 && updated.length === 0 && outdated.length === 0;
|
|
88
|
+
const isUpdate = updated.length > 0;
|
|
87
89
|
if (created.length > 0) {
|
|
88
90
|
console.log(`Created ${created.length} files:`);
|
|
89
91
|
created.forEach((f) => console.log(` + ${f}`));
|
|
@@ -102,11 +104,17 @@ export function registerInitCommand(program) {
|
|
|
102
104
|
return;
|
|
103
105
|
}
|
|
104
106
|
console.log(`\nWorkspace ready: ${dest}`);
|
|
105
|
-
if (
|
|
106
|
-
console.log(`\
|
|
107
|
-
console.log(`
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(`
|
|
107
|
+
if (isFirstTime) {
|
|
108
|
+
console.log(`\nThis is a content creator workspace powered by 9000AI.`);
|
|
109
|
+
console.log(`Capabilities: trending topics, keyword search, creator monitoring, video transcription.`);
|
|
110
|
+
console.log(`\nRead guide.md for full walkthrough, or get started now:`);
|
|
111
|
+
console.log(` 1. Load 9000AI hub: 9000ai skill load 9000AI-hub`);
|
|
112
|
+
console.log(` 2. Or tell your AI: /9000AI`);
|
|
113
|
+
console.log(` The AI will guide you through profile setup and available capabilities.`);
|
|
114
|
+
}
|
|
115
|
+
else if (isUpdate) {
|
|
116
|
+
console.log(`\nWhat's new: 9000ai skill load 9000AI-hub to see latest capabilities.`);
|
|
117
|
+
console.log(`Your data (profile/, claims/, inbox/, projects/) was not modified.`);
|
|
110
118
|
}
|
|
111
119
|
});
|
|
112
120
|
}
|
package/dist/commands/monitor.js
CHANGED
|
@@ -5,11 +5,12 @@ export function registerMonitorCommands(parent) {
|
|
|
5
5
|
cmd
|
|
6
6
|
.command("list-creators")
|
|
7
7
|
.description("List all monitoring targets")
|
|
8
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
8
9
|
.option("--fields <list>", "Comma-separated fields to extract")
|
|
9
10
|
.option("--compact", "One JSON object per line")
|
|
10
11
|
.action(async (opts) => {
|
|
11
12
|
const data = await request({ method: "GET", path: "/api/v1/douyin/monitor/creators" });
|
|
12
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
13
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
13
14
|
});
|
|
14
15
|
cmd
|
|
15
16
|
.command("create-creator")
|
|
@@ -85,6 +86,7 @@ export function registerMonitorCommands(parent) {
|
|
|
85
86
|
.option("--page <n>", "Page number", "1")
|
|
86
87
|
.option("--page-size <n>", "Items per page", "20")
|
|
87
88
|
.option("--status <status>", "Filter by status")
|
|
89
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
88
90
|
.option("--fields <list>", "Comma-separated fields to extract")
|
|
89
91
|
.option("--compact", "One JSON object per line")
|
|
90
92
|
.action(async (opts) => {
|
|
@@ -92,17 +94,18 @@ export function registerMonitorCommands(parent) {
|
|
|
92
94
|
if (opts.status)
|
|
93
95
|
params.set("status", opts.status);
|
|
94
96
|
const data = await request({ method: "GET", path: `/api/v1/douyin/monitor/runs?${params}` });
|
|
95
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
97
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
96
98
|
});
|
|
97
99
|
cmd
|
|
98
100
|
.command("run-detail")
|
|
99
101
|
.description("View single run details")
|
|
100
102
|
.requiredOption("--run-id <id>", "Run ID")
|
|
103
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
101
104
|
.option("--fields <list>", "Comma-separated fields to extract")
|
|
102
105
|
.option("--compact", "One JSON object per line")
|
|
103
106
|
.action(async (opts) => {
|
|
104
107
|
const data = await request({ method: "GET", path: `/api/v1/douyin/monitor/runs/${opts.runId}` });
|
|
105
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
108
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
106
109
|
});
|
|
107
110
|
cmd
|
|
108
111
|
.command("fetch")
|
|
@@ -110,7 +113,7 @@ export function registerMonitorCommands(parent) {
|
|
|
110
113
|
.requiredOption("--sec-user <id>", "User sec_user_id or homepage URL")
|
|
111
114
|
.option("--count <n>", "Number of videos to fetch", "20")
|
|
112
115
|
.option("--sort <n>", "Sort: 0=newest 1=hottest", "0")
|
|
113
|
-
.option("--format <fmt>", "Output format: csv|json", "
|
|
116
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
114
117
|
.option("--fields <list>", "Comma-separated fields to extract")
|
|
115
118
|
.option("--compact", "One JSON object per line")
|
|
116
119
|
.action(async (opts) => {
|
package/dist/commands/search.js
CHANGED
|
@@ -68,7 +68,7 @@ export function registerSearchCommands(parent) {
|
|
|
68
68
|
.option("--min-likes <n>", "Minimum likes", "0")
|
|
69
69
|
.option("--min-comments <n>", "Minimum comments", "0")
|
|
70
70
|
.option("--wait", "Poll until batch completes then print results")
|
|
71
|
-
.option("--format <fmt>", "Output format: csv|json", "
|
|
71
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
72
72
|
.option("--fields <list>", "Comma-separated fields to extract (used with --wait)")
|
|
73
73
|
.option("--compact", "One JSON object per line (used with --wait)")
|
|
74
74
|
.action(async (keywords, opts) => {
|
|
@@ -121,7 +121,7 @@ export function registerSearchCommands(parent) {
|
|
|
121
121
|
.command("batch-result")
|
|
122
122
|
.description("Query async search batch results")
|
|
123
123
|
.requiredOption("--batch-id <id>", "Batch ID")
|
|
124
|
-
.option("--format <fmt>", "Output format: csv|json", "
|
|
124
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
125
125
|
.option("--fields <list>", "Comma-separated fields to extract (e.g. desc,author_name,likes,video_url)")
|
|
126
126
|
.option("--compact", "One JSON object per line, no indentation")
|
|
127
127
|
.action(async (opts) => {
|
package/dist/commands/task.js
CHANGED
|
@@ -6,6 +6,7 @@ export function registerTaskCommands(parent) {
|
|
|
6
6
|
.description("Check task or batch status")
|
|
7
7
|
.option("--task-id <id>", "Task ID")
|
|
8
8
|
.option("--batch-id <id>", "Batch ID (shows batch progress + task list)")
|
|
9
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
9
10
|
.option("--fields <list>", "Comma-separated fields to extract (e.g. desc,video_url,likes)")
|
|
10
11
|
.option("--compact", "One JSON object per line, no indentation")
|
|
11
12
|
.action(async (opts) => {
|
|
@@ -15,20 +16,21 @@ export function registerTaskCommands(parent) {
|
|
|
15
16
|
}
|
|
16
17
|
if (opts.batchId) {
|
|
17
18
|
const data = await request({ method: "GET", path: `/api/v1/tasks/batch/${opts.batchId}` });
|
|
18
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
19
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
22
|
const data = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}` });
|
|
22
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
23
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
23
24
|
});
|
|
24
25
|
cmd
|
|
25
26
|
.command("results")
|
|
26
27
|
.description("Get task results")
|
|
27
28
|
.requiredOption("--task-id <id>", "Task ID")
|
|
29
|
+
.option("--format <fmt>", "Output format: csv|json", "csv")
|
|
28
30
|
.option("--fields <list>", "Comma-separated fields to extract (e.g. desc,video_url,likes)")
|
|
29
31
|
.option("--compact", "One JSON object per line, no indentation")
|
|
30
32
|
.action(async (opts) => {
|
|
31
33
|
const data = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}/results` });
|
|
32
|
-
printJson(data, { fields: opts.fields, compact: opts.compact });
|
|
34
|
+
printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
|
|
33
35
|
});
|
|
34
36
|
}
|
|
@@ -76,6 +76,8 @@ export function registerTranscribeCommands(parent) {
|
|
|
76
76
|
.command("text")
|
|
77
77
|
.description("Extract transcription text and save to local file")
|
|
78
78
|
.requiredOption("--task-id <id>", "Task ID")
|
|
79
|
+
.option("--name <name>", "Custom filename (without .txt), e.g. '一鸣财经_中国教育的三大魔幻现象'")
|
|
80
|
+
.option("--dir <dir>", "Sub-directory under output/transcripts/, e.g. 'AI+就业'")
|
|
79
81
|
.option("--no-save", "Print text to stdout instead of saving to file")
|
|
80
82
|
.action(async (opts) => {
|
|
81
83
|
const taskData = await request({ method: "GET", path: `/api/v1/tasks/${opts.taskId}` });
|
|
@@ -100,17 +102,20 @@ export function registerTranscribeCommands(parent) {
|
|
|
100
102
|
console.error("Transcript text is empty");
|
|
101
103
|
process.exit(1);
|
|
102
104
|
}
|
|
103
|
-
// 用 third_party_task_id (video_id) 或 task_id 做文件名
|
|
104
|
-
const videoId = (inner.third_party_task_id ?? opts.taskId);
|
|
105
105
|
if (!opts.save) {
|
|
106
|
-
// --no-save: 直接输出
|
|
107
106
|
console.log(text);
|
|
108
107
|
return;
|
|
109
108
|
}
|
|
110
|
-
//
|
|
111
|
-
const
|
|
109
|
+
// 文件名: --name > third_party_task_id (video_id) > task_id
|
|
110
|
+
const videoId = (inner.third_party_task_id ?? opts.taskId);
|
|
111
|
+
const filename = (opts.name ?? videoId).replace(/[<>:"/\\|?*]/g, "_");
|
|
112
|
+
// 目录: output/transcripts/[--dir]/
|
|
113
|
+
const dirParts = ["output", "transcripts"];
|
|
114
|
+
if (opts.dir)
|
|
115
|
+
dirParts.push(opts.dir);
|
|
116
|
+
const dir = resolve(...dirParts);
|
|
112
117
|
mkdirSync(dir, { recursive: true });
|
|
113
|
-
const filepath = join(dir, `${
|
|
118
|
+
const filepath = join(dir, `${filename}.txt`);
|
|
114
119
|
writeFileSync(filepath, text, "utf-8");
|
|
115
120
|
// 只返回摘要给 AI
|
|
116
121
|
const preview = text.length > 100 ? text.slice(0, 100) + "..." : text;
|
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.
|
|
17
|
+
.version("0.6.4");
|
|
18
18
|
registerConfigCommands(program);
|
|
19
19
|
registerAuthCommands(program);
|
|
20
20
|
registerSearchCommands(program);
|
package/package.json
CHANGED
|
@@ -114,7 +114,14 @@ output-format: routing-only
|
|
|
114
114
|
|
|
115
115
|
完成后:
|
|
116
116
|
|
|
117
|
-
>
|
|
117
|
+
> 画像建好了。你的工作空间包含:
|
|
118
|
+
> - `profile/` — 你的画像(刚填好的)
|
|
119
|
+
> - `claims/` — 主张库,所有内容围绕主张展开
|
|
120
|
+
> - `benchmarks/` — 对标文案库,转写和拆解的素材存这里,通过 index.json 索引
|
|
121
|
+
> - `inbox/` — 素材投喂入口
|
|
122
|
+
> - `projects/` — 选题项目
|
|
123
|
+
>
|
|
124
|
+
> 现在可以开始——比如"帮我做选题调研"、"看看最近热榜"、"转写这个视频"。
|
|
118
125
|
|
|
119
126
|
## 更新系统
|
|
120
127
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
| profile/ | 了解用户是谁——身份、风格、领域 | 只读(用户维护) |
|
|
14
14
|
| inbox/ | 接收用户投喂的语料——会议记录、视频链接、文章、随笔 | 读取 + 处理后归档 |
|
|
15
15
|
| claims/ | 主张库——核心资产,所有内容围绕主张展开 | 读写(提取、匹配、回写) |
|
|
16
|
+
| benchmarks/ | 对标文案库——转写、拆解的素材,通过 index.json 索引 | 读写(存素材 + 维护索引) |
|
|
16
17
|
| projects/ | 选题项目——一个选题一个项目 | 读写 |
|
|
17
18
|
|
|
18
19
|
## 3. 可用工具能力
|
|
@@ -24,6 +25,20 @@
|
|
|
24
25
|
| 对标账号监控 | 监控指定博主的内容更新 | `9000ai monitor` |
|
|
25
26
|
| 视频转文字 | 批量将视频转为文字稿 | `9000ai transcribe` |
|
|
26
27
|
|
|
28
|
+
## 3.1 benchmarks 对标文案库规则
|
|
29
|
+
|
|
30
|
+
`benchmarks/` 通过 `index.json` 索引。**必须遵守以下规则:**
|
|
31
|
+
|
|
32
|
+
**存入素材时:**
|
|
33
|
+
1. 按主题建子目录(如 `AI就业/`、`知识付费/`)
|
|
34
|
+
2. 文件名格式:`作者_标题.md`
|
|
35
|
+
3. **必须同步更新 `benchmarks/index.json`**,追加条目,id 递增
|
|
36
|
+
|
|
37
|
+
**检索素材时:**
|
|
38
|
+
1. 先读 `benchmarks/index.json`,按 tags 或 topic 匹配
|
|
39
|
+
2. 只读匹配到的具体文件,不全量扫描目录
|
|
40
|
+
3. 做选题前主动检查有没有相关对标素材
|
|
41
|
+
|
|
27
42
|
## 4. inbox 处理规则
|
|
28
43
|
|
|
29
44
|
当用户往 inbox/ 丢入新文件时:
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 对标文案库
|
|
2
|
+
|
|
3
|
+
这个目录存放从对标账号转写、拆解的文案素材。是你的内容弹药库,AI 做选题时会检索这里。
|
|
4
|
+
|
|
5
|
+
## 工作流
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
搜索/监控 → 发现好内容 → 转写 → 拆解分析 → 存到 benchmarks/主题/
|
|
9
|
+
↓
|
|
10
|
+
自动更新 index.json
|
|
11
|
+
↓
|
|
12
|
+
下次做选题时 AI 按标签检索
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 目录结构
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
benchmarks/
|
|
19
|
+
├── index.json ← AI 检索入口,存素材索引
|
|
20
|
+
├── AI就业/
|
|
21
|
+
│ ├── 一鸣财经_中国教育的三大魔幻现象.md
|
|
22
|
+
│ └── 张三说_AI替代了哪些工作.md
|
|
23
|
+
├── 知识付费/
|
|
24
|
+
│ └── 李四_如何做知识付费.md
|
|
25
|
+
└── README.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## index.json 格式
|
|
29
|
+
|
|
30
|
+
每次存入新素材时,AI 必须同步更新 index.json:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
[
|
|
34
|
+
{
|
|
35
|
+
"id": "bm001",
|
|
36
|
+
"topic": "AI就业",
|
|
37
|
+
"title": "一鸣财经讲中国教育的三大魔幻现象",
|
|
38
|
+
"type": "transcription",
|
|
39
|
+
"file": "AI就业/一鸣财经_中国教育的三大魔幻现象.md",
|
|
40
|
+
"tags": ["AI", "教育", "就业"],
|
|
41
|
+
"source_video_id": "7582142740935970054",
|
|
42
|
+
"author": "一鸣财经",
|
|
43
|
+
"created_at": "2026-04-03"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| 字段 | 说明 |
|
|
49
|
+
|------|------|
|
|
50
|
+
| id | 递增编号 bm001, bm002... |
|
|
51
|
+
| topic | 所属主题目录名 |
|
|
52
|
+
| title | 素材标题 |
|
|
53
|
+
| type | transcription(转写) / analysis(拆解) / collection(合集) |
|
|
54
|
+
| file | 相对路径 |
|
|
55
|
+
| tags | 关键词标签,用于检索匹配 |
|
|
56
|
+
| source_video_id | 来源视频 ID(可选) |
|
|
57
|
+
| author | 原作者(可选) |
|
|
58
|
+
| created_at | 入库日期 |
|
|
59
|
+
|
|
60
|
+
## AI 检索规则
|
|
61
|
+
|
|
62
|
+
1. 做选题时,先读 `index.json` 看有没有相关素材
|
|
63
|
+
2. 按 tags 或 topic 匹配,不要全量扫描目录
|
|
64
|
+
3. 只读匹配到的具体文件,不读整个目录
|
|
65
|
+
|
|
66
|
+
## 和 claims 的关系
|
|
67
|
+
|
|
68
|
+
- `claims/` 定义你的核心主张
|
|
69
|
+
- `benchmarks/` 存对标账号的表达方式
|
|
70
|
+
- AI 对比两者,找到差异化的内容角度
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
├── profile/ # 你的画像(身份、风格、领域、产品)
|
|
9
9
|
├── inbox/ # 素材投喂入口
|
|
10
10
|
├── claims/ # 主张库(你的核心资产)
|
|
11
|
+
├── benchmarks/ # 对标文案库(转写、拆解的素材)
|
|
11
12
|
├── projects/ # 选题项目
|
|
12
|
-
├── CLAUDE.md # Claude Code 自动载入文件
|
|
13
13
|
└── guide.md # 就是这份指南
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
## 全流程概览
|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
发现热点 → 匹配主张 → 找角度 → 补素材 → 转写视频 → 产出内容
|
|
22
|
-
↑ ↑ ↑ ↑ ↑
|
|
23
|
-
热榜/搜索 claims.json angles cases 视频转文字
|
|
21
|
+
发现热点 → 匹配主张 → 找角度 → 补素材 → 转写视频 → 存入文案库 → 产出内容
|
|
22
|
+
↑ ↑ ↑ ↑ ↑ ↑
|
|
23
|
+
热榜/搜索 claims.json angles cases 视频转文字 benchmarks/
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
1. **发现**:用热榜或搜索找到值得追的热点
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
3. **切角度**:从角度库找已有角度,或基于主张推新角度
|
|
29
29
|
4. **补素材**:从案例库拉历史素材,或搜索新素材
|
|
30
30
|
5. **转写**:对标视频转成文字稿,分析学习
|
|
31
|
-
6.
|
|
31
|
+
6. **入库**:转写和拆解的文案存到 `benchmarks/主题/`,自动更新索引
|
|
32
|
+
7. **产出**:录制/撰写内容,记录到 outputs.jsonl
|
|
32
33
|
|
|
33
34
|
---
|
|
34
35
|
|
|
@@ -75,6 +76,16 @@
|
|
|
75
76
|
|
|
76
77
|
---
|
|
77
78
|
|
|
79
|
+
## 第三步:积累对标文案
|
|
80
|
+
|
|
81
|
+
`benchmarks/` 是你的对标文案库。搜索或监控发现好内容后,转写 → 拆解 → 存到这里。
|
|
82
|
+
|
|
83
|
+
AI 通过 `benchmarks/index.json` 索引快速检索,不需要全量扫描。每次存入新素材时 AI 自动更新索引。
|
|
84
|
+
|
|
85
|
+
详见 `benchmarks/README.md`。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
78
89
|
## 各能力快速入门
|
|
79
90
|
|
|
80
91
|
### 热榜 — 看当前什么话题热
|
|
@@ -153,14 +164,15 @@
|
|
|
153
164
|
1. `9000ai search keyword "关键词"` 搜索目标内容
|
|
154
165
|
2. 结果落到 output 文件
|
|
155
166
|
3. 挑出值得学的视频 → `9000ai transcribe submit` 转文字稿
|
|
156
|
-
4.
|
|
157
|
-
5.
|
|
167
|
+
4. 转写结果存到 `benchmarks/主题/`,AI 自动更新索引
|
|
168
|
+
5. 分析文字稿 → 提取案例写入 cases.jsonl
|
|
169
|
+
6. 基于积累的案例和对标文案 → 规划一周选题
|
|
158
170
|
|
|
159
171
|
### 场景 D:对标监控 + 持续素材积累
|
|
160
172
|
|
|
161
173
|
1. `9000ai monitor create-creator` 添加对标账号
|
|
162
174
|
2. 定期监控,获取最新内容
|
|
163
|
-
3. 值得学的视频 → 转写 → 提取角度和案例
|
|
175
|
+
3. 值得学的视频 → 转写 → 存到 `benchmarks/` → 提取角度和案例
|
|
164
176
|
4. 找对标做了但你没做的角度 → 新选题
|
|
165
177
|
|
|
166
178
|
---
|