yuanflow-cli 0.1.37 → 0.1.40
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/README.md +50 -1
- package/package.json +1 -1
- package/skills/yuanflow-skill/IP/350/277/220/350/220/245/SKILL.md +1 -0
- package/skills/yuanflow-skill/README.md +12 -2
- package/skills/yuanflow-skill/SKILL.md +12 -4
- package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/SKILL.md +1 -1
- package/skills/yuanflow-skill//345/210/233/344/275/234/346/200/273/347/233/221/SKILL.md +94 -0
- package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/{344/270/216/345/217/221/345/270/203/SKILL.md → SKILL.md} +14 -6
- package/skills/yuanflow-skill//345/270/220/345/217/267/345/256/232/344/275/215/SKILL.md +1 -0
- package/skills/yuanflow-skill//346/226/207/346/241/210/345/210/233/344/275/234/SKILL.md +1 -0
- package/skills/yuanflow-skill//347/203/255/351/227/250/345/206/205/345/256/271/346/225/264/347/220/206/SKILL.md +83 -0
- package/skills/yuanflow-skill//347/233/264/346/222/255/346/212/225/346/265/201/347/255/226/347/225/245/SKILL.md +1 -0
- package/skills/yuanflow-skill//347/233/264/346/222/255/350/257/235/346/234/257/347/224/237/346/210/220/SKILL.md +1 -0
- package/skills/yuanflow-skill//350/207/252/345/252/222/344/275/223/346/265/217/350/247/210/345/231/250/350/207/252/345/212/250/345/214/226/SKILL.md +23 -3
- package/skills/yuanflow-skill//350/207/252/345/252/222/344/275/223/347/237/245/350/257/206/345/272/223/SKILL.md +4 -0
- package/skills/yuanflow-skill//350/247/206/351/242/221/346/212/225/346/265/201/347/255/226/347/225/245/SKILL.md +1 -0
- package/skills/yuanflow-skill//350/247/206/351/242/221/346/231/272/350/203/275/345/211/252/350/276/221/SKILL.md +374 -0
- package/skills/yuanflow-skill//351/200/211/351/242/230/347/255/226/345/210/222/SKILL.md +1 -0
- package/skills/yuanflow-skill//351/243/236/344/271/246/345/256/230/346/226/271/346/212/200/350/203/275/SKILL.md +93 -0
- package/src/agent-protocol.js +6 -0
- package/src/cli.js +43 -0
- package/src/trending-tools.js +117 -0
- package/src/video-tools.js +969 -0
- /package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/{344/270/216/345/217/221/345/270/203/references → references}/commands.md" +0 -0
- /package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/{344/270/216/345/217/221/345/270/203/references → references}/interaction-policy.md" +0 -0
- /package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/{344/270/216/345/217/221/345/270/203/references → references}/publishing-policy.md" +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { callEndpoint } from './request.js';
|
|
2
|
+
|
|
3
|
+
const VIDEO_HOT_LIST_PATH = '/douyin/billboard/fetch_hot_total_video_list';
|
|
4
|
+
|
|
5
|
+
const VIDEO_HOT_BOARD_TYPES = [
|
|
6
|
+
{ subType: 1001, label: '视频总榜' },
|
|
7
|
+
{ subType: 1002, label: '低粉爆款' },
|
|
8
|
+
{ subType: 1003, label: '高完播率' },
|
|
9
|
+
{ subType: 1004, label: '高涨粉率' },
|
|
10
|
+
{ subType: 1005, label: '高点赞率' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export function listTrendingCommands() {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
key: 'trending.video-hot-list',
|
|
17
|
+
command: 'trending video-hot-list',
|
|
18
|
+
kind: 'trending',
|
|
19
|
+
description: '一次性查询抖音视频热榜五类榜单:视频总榜、低粉爆款、高完播率、高涨粉率、高点赞率。',
|
|
20
|
+
method: 'POST',
|
|
21
|
+
socialPath: VIDEO_HOT_LIST_PATH,
|
|
22
|
+
positionals: [],
|
|
23
|
+
options: [
|
|
24
|
+
{ flag: '--page', name: 'page', required: false, label: '页码,默认 1' },
|
|
25
|
+
{ flag: '--page-size', name: 'page_size', required: false, label: '每页数量,默认 10' },
|
|
26
|
+
{ flag: '--date-window', name: 'date_window', required: false, label: '时间窗口,默认 2 按天' },
|
|
27
|
+
{ flag: '--tags-json', name: 'tags', required: false, label: '垂类标签 JSON 数组,空则全部垂类' },
|
|
28
|
+
],
|
|
29
|
+
returns: '返回五类视频热榜的统一 JSON,字段结构以上游实际响应为准。',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function fetchVideoHotList({ options }) {
|
|
35
|
+
const query = buildVideoHotListQuery(options);
|
|
36
|
+
const boards = [];
|
|
37
|
+
|
|
38
|
+
for (const board of VIDEO_HOT_BOARD_TYPES) {
|
|
39
|
+
const requestBody = {
|
|
40
|
+
page: query.page,
|
|
41
|
+
page_size: query.page_size,
|
|
42
|
+
date_window: query.date_window,
|
|
43
|
+
sub_type: board.subType,
|
|
44
|
+
...(query.tags !== undefined ? { tags: query.tags } : {}),
|
|
45
|
+
};
|
|
46
|
+
const response = await callEndpoint(VIDEO_HOT_LIST_PATH, {
|
|
47
|
+
...options,
|
|
48
|
+
method: 'POST',
|
|
49
|
+
body: requestBody,
|
|
50
|
+
});
|
|
51
|
+
boards.push({
|
|
52
|
+
sub_type: board.subType,
|
|
53
|
+
label: board.label,
|
|
54
|
+
request: requestBody,
|
|
55
|
+
response,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
platform: 'douyin',
|
|
61
|
+
endpoint: {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
path: VIDEO_HOT_LIST_PATH,
|
|
64
|
+
kind: 'video-hot-list',
|
|
65
|
+
},
|
|
66
|
+
query,
|
|
67
|
+
boards,
|
|
68
|
+
guidance: [
|
|
69
|
+
'结合用户个人创作信息、个人创作库历史记录、历史任务或对话记录输出建议。',
|
|
70
|
+
'不要只罗列榜单,必须区分五类榜单来源并提炼可执行选题和内容结构。',
|
|
71
|
+
'重点比较总榜、低粉爆款、高完播率、高涨粉率、高点赞率之间的差异。',
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildVideoHotListQuery(options = {}) {
|
|
77
|
+
return {
|
|
78
|
+
page: parsePositiveInteger(options.named?.page, 1, 'page'),
|
|
79
|
+
page_size: parsePositiveInteger(options.named?.['page-size'] ?? options.named?.page_size, 10, 'page_size'),
|
|
80
|
+
date_window: parsePositiveInteger(options.named?.['date-window'] ?? options.named?.date_window, 2, 'date_window'),
|
|
81
|
+
...(parseTags(options.named?.['tags-json'] ?? options.named?.tags) !== undefined
|
|
82
|
+
? { tags: parseTags(options.named?.['tags-json'] ?? options.named?.tags) }
|
|
83
|
+
: {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parsePositiveInteger(value, fallback, name) {
|
|
88
|
+
if (value === undefined || value === null || value === '') {
|
|
89
|
+
return fallback;
|
|
90
|
+
}
|
|
91
|
+
const number = Number(value);
|
|
92
|
+
if (!Number.isInteger(number) || number <= 0) {
|
|
93
|
+
throw new Error(`${name} 必须是正整数。`);
|
|
94
|
+
}
|
|
95
|
+
return number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function parseTags(value) {
|
|
99
|
+
if (value === undefined || value === null || value === '') {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(String(value));
|
|
107
|
+
if (!Array.isArray(parsed)) {
|
|
108
|
+
throw new Error('tags-json 必须是数组。');
|
|
109
|
+
}
|
|
110
|
+
return parsed;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (error?.message === 'tags-json 必须是数组。') {
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
throw new Error('tags-json 必须是合法 JSON 数组。');
|
|
116
|
+
}
|
|
117
|
+
}
|