skillfree 0.1.39 → 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/SKILL.md +91 -93
- package/bin/skillfree.js +30 -8
- package/install.sh +7 -3
- package/package.json +1 -1
- package/scripts/commands/auth.js +2 -7
- package/scripts/commands/pilot.js +8 -1
- package/scripts/commands/presentation.js +100 -0
package/SKILL.md
CHANGED
|
@@ -1,163 +1,161 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skillfree
|
|
3
|
-
description: SkillFree — 模型与技能严选平台。只保留每个任务类型最强的模型,按实际用量精确计费。写代码用Claude,文档分析用GPT,多模态用Gemini,生图用nano banana,生视频用Veo,文档OCR用合合,网页搜索用Tavily
|
|
3
|
+
description: SkillFree — 模型与技能严选平台。只保留每个任务类型最强的模型,按实际用量精确计费。写代码用Claude,文档分析用GPT,多模态用Gemini,生图用nano banana,生视频用Veo,文档OCR用合合,网页搜索用Tavily,做PPT用AI演示文稿。
|
|
4
4
|
metadata: {"openclaw": {"primaryEnv": "SKILLFREE_API_KEY", "emoji": "🦞", "homepage": "https://skillfree.tech", "requires": {"bins": ["skillfree"], "env": ["SKILLFREE_API_KEY"]}}}
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# SkillFree — 模型与技能严选平台 🦞
|
|
8
8
|
|
|
9
|
-
>
|
|
9
|
+
> 不堆模型数量,只选每个场景最好用的那一个。按实际用量精确计费,用多少扣多少。
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## 🧭 任务 →
|
|
13
|
+
## 🧭 任务 → 严选工具 一览
|
|
14
14
|
|
|
15
|
-
|
|
|
16
|
-
|
|
17
|
-
| ✍️ 写代码 /
|
|
18
|
-
| 📄 文档分析 / 报告生成
|
|
19
|
-
| 🖼️
|
|
20
|
-
| 🎨 图像生成 | nano banana 2 /
|
|
21
|
-
| 🎬 视频生成 | Veo 3.1 Fast / Veo 3.1 |
|
|
22
|
-
| 📑 扫描文档 OCR
|
|
23
|
-
| 🌐 实时网页搜索 | Tavily
|
|
15
|
+
| 任务类型 | 严选工具 | 计费方式 |
|
|
16
|
+
|---------|---------|---------|
|
|
17
|
+
| ✍️ 写代码 / 重构 / 技术文档 | Claude Sonnet 4.6 | 按 token |
|
|
18
|
+
| 📄 文档分析 / 报告生成 | GPT-5.4 | 按 token |
|
|
19
|
+
| 🖼️ 图文多模态理解 | Gemini 3.1 Pro | 按 token |
|
|
20
|
+
| 🎨 图像生成 | nano banana 2 / pro | 按次 |
|
|
21
|
+
| 🎬 视频生成 | Veo 3.1 Fast / Veo 3.1 | 按秒 |
|
|
22
|
+
| 📑 扫描文档 OCR | 合合 图文混排 | 按量 |
|
|
23
|
+
| 🌐 实时网页搜索 | Tavily | 按次 |
|
|
24
|
+
| 📊 演示文稿 / PPT 生成 | **AI 演示文稿生成** ✨ | **按实际页数** |
|
|
24
25
|
|
|
25
26
|
---
|
|
26
27
|
|
|
27
|
-
## 💬
|
|
28
|
-
|
|
29
|
-
计费方式:按实际消耗 token 精确结算(¥/百万 tokens)
|
|
28
|
+
## 💬 模型严选(chat / image / video / ocr)
|
|
30
29
|
|
|
31
30
|
### ✍️ 写代码 — Claude
|
|
32
31
|
|
|
33
|
-
Claude 对代码的理解深度在所有模型中最强:能追踪跨文件上下文、精准定位 bug、给出可直接运行的重构方案。技术写作也是强项。
|
|
34
|
-
|
|
35
32
|
| 模型ID | 名称 | 输入 | 输出 |
|
|
36
33
|
|--------|------|------|------|
|
|
37
|
-
| `claude-sonnet-4-6` | Claude Sonnet 4.6 ⭐ | ¥
|
|
38
|
-
| `claude-sonnet-4-6-cc` | Claude Sonnet 4.6 CC | ¥
|
|
39
|
-
| `claude-opus-4-6` | Claude Opus 4.6 | ¥
|
|
40
|
-
| `claude-opus-4-6-cc` | Claude Opus 4.6 CC | ¥140/1M | ¥700/1M |
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
skillfree pilot --type chat --model claude-sonnet-4-6 \
|
|
44
|
-
--prompt "重构这段代码,提升可读性并添加类型注解"
|
|
45
|
-
```
|
|
34
|
+
| `claude-sonnet-4-6` | Claude Sonnet 4.6 ⭐ | ¥30/1M | ¥150/1M |
|
|
35
|
+
| `claude-sonnet-4-6-cc` | Claude Sonnet 4.6 CC | ¥30/1M | ¥150/1M |
|
|
36
|
+
| `claude-opus-4-6` | Claude Opus 4.6 | ¥150/1M | ¥750/1M |
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
**Claude 不适合:** 实时联网信息、图片理解
|
|
38
|
+
**适合:** 代码生成、bug 定位、重构、架构设计、技术文档
|
|
49
39
|
|
|
50
40
|
---
|
|
51
41
|
|
|
52
42
|
### 📄 文档分析 — GPT
|
|
53
43
|
|
|
54
|
-
GPT 擅长结构化文档处理:读懂复杂格式后输出层次清晰的分析,在商业报告、合同条款提炼、数据表格解读上表现最稳。
|
|
55
|
-
|
|
56
44
|
| 模型ID | 名称 | 输入 | 输出 |
|
|
57
45
|
|--------|------|------|------|
|
|
58
|
-
| `gpt-5.4` | GPT-5.4 ⭐ | ¥
|
|
59
|
-
| `gpt-5.4-mini` | GPT-5.4 Mini | ¥
|
|
46
|
+
| `gpt-5.4` | GPT-5.4 ⭐ | ¥33/1M | ¥200/1M |
|
|
47
|
+
| `gpt-5.4-mini` | GPT-5.4 Mini | ¥10/1M | ¥60/1M |
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
skillfree pilot --type chat --model gpt-5.4 \
|
|
63
|
-
--prompt "提取这份投资协议中的核心条款和风险点"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**GPT 适合:** 商业文档、合同分析、结构化摘要、数据提炼、报告生成
|
|
67
|
-
**GPT-mini 适合:** 大批量简单文档处理,成本敏感场景
|
|
49
|
+
**适合:** 商业文档、合同分析、结构化摘要、数据提炼、报告生成
|
|
68
50
|
|
|
69
51
|
---
|
|
70
52
|
|
|
71
53
|
### 🖼️ 多模态理解 — Gemini
|
|
72
54
|
|
|
73
|
-
Gemini 原生多模态架构,图片、PDF、表格、文字混合输入时理解最准。超长上下文窗口,适合需要"同时看多份材料"的复杂分析场景。
|
|
74
|
-
|
|
75
55
|
| 模型ID | 名称 | 输入 | 输出 |
|
|
76
56
|
|--------|------|------|------|
|
|
77
|
-
| `gemini-3.1-pro-preview` | Gemini 3.1 Pro ⭐ | ¥
|
|
78
|
-
| `gemini-3.1-flash-lite-preview` | Gemini 3.1 Flash Lite | ¥1/1M | ¥4/1M |
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
skillfree pilot --type chat --model gemini-3.1-pro-preview \
|
|
82
|
-
--prompt "分析这张财务图表的关键趋势" --file chart.png
|
|
83
|
-
```
|
|
57
|
+
| `gemini-3.1-pro-preview` | Gemini 3.1 Pro ⭐ | ¥33/1M | ¥134/1M |
|
|
58
|
+
| `gemini-3.1-flash-lite-preview` | Gemini 3.1 Flash Lite | ¥1.1/1M | ¥4.3/1M |
|
|
84
59
|
|
|
85
|
-
|
|
86
|
-
**Gemini Flash Lite 适合:** 大批量简单图文识别,极低成本
|
|
60
|
+
**适合:** 图文混合分析、多模态推理、超长文档
|
|
87
61
|
|
|
88
62
|
---
|
|
89
63
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
基于 Google Gemini 图像模型。对自然语言描述理解准确,风格多样,中英文 prompt 均可,生成速度快。
|
|
64
|
+
### 🎨 图像生成 — nano banana
|
|
93
65
|
|
|
94
66
|
| 模型ID | 展示名 | 价格 |
|
|
95
67
|
|--------|--------|------|
|
|
96
68
|
| `gemini-3.1-flash-image-preview` | **nano banana 2** ⭐ | ¥0.40/次 |
|
|
97
69
|
| `gemini-3-pro-image-preview` | **nano banana pro** | ¥1.40/次 |
|
|
98
70
|
|
|
99
|
-
```bash
|
|
100
|
-
# 快速生成(推荐日常使用)
|
|
101
|
-
skillfree pilot --type image --model gemini-3.1-flash-image-preview \
|
|
102
|
-
--prompt "赛博朋克上海夜景,霓虹灯反射在雨后街道" --output ./image.png
|
|
103
|
-
|
|
104
|
-
# 旗舰品质(商业级创作)
|
|
105
|
-
skillfree pilot --type image --model gemini-3-pro-image-preview \
|
|
106
|
-
--prompt "产品包装图,极简风格,白底" --output ./image.png
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**nano banana 2:** 日常创作、概念图、插画,速度快性价比高
|
|
110
|
-
**nano banana pro:** 复杂场景构图、艺术风格精控、商业级输出
|
|
111
|
-
|
|
112
71
|
---
|
|
113
72
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
Google Veo 系列,物理运动自然,画质细腻。文字描述直接生成视频,异步生成自动轮询返回结果,支持三档分辨率,**成功生成后才扣费**。
|
|
73
|
+
### 🎬 视频生成 — Google Veo
|
|
117
74
|
|
|
118
75
|
| 模型ID | 名称 | 720p | 1080p | 4K |
|
|
119
76
|
|--------|------|------|-------|-----|
|
|
120
77
|
| `veo-3.1-fast-generate-preview` | **Veo 3.1 Fast** ⭐ | ¥1.5/s | ¥1.5/s | ¥3.5/s |
|
|
121
78
|
| `veo-3.1-generate-preview` | **Veo 3.1** | ¥3.5/s | ¥3.5/s | ¥5.5/s |
|
|
122
79
|
|
|
123
|
-
|
|
124
|
-
# 快速版(推荐)
|
|
125
|
-
skillfree pilot --type video --model veo-3.1-fast-generate-preview \
|
|
126
|
-
--prompt "樱花花瓣在微风中缓缓飘落,日式庭院,电影感" \
|
|
127
|
-
--seconds 8 --size 1920x1080 --output ./video.mp4
|
|
128
|
-
|
|
129
|
-
# 旗舰版(商业级)
|
|
130
|
-
skillfree pilot --type video --model veo-3.1-generate-preview \
|
|
131
|
-
--prompt "产品展示视频,极简白色空间" \
|
|
132
|
-
--seconds 6 --size 3840x2160 --output ./video.mp4
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
**分辨率:** `1280x720`(720p)· `1920x1080`(1080p)· `3840x2160`(4K)
|
|
136
|
-
**时长:** `--seconds 4 / 6 / 8`(默认 8 秒)
|
|
80
|
+
异步生成,成功后才扣费,支持 4~8 秒时长。
|
|
137
81
|
|
|
138
82
|
---
|
|
139
83
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
合合(hehe)专注文档智能解析,扫描版 PDF、图片文字、复杂排版(表格、公式、图文混排)识别率业界顶级,输出标准 Markdown,是纸质文档数字化的最优选择。
|
|
84
|
+
### 📑 OCR 解析 — 合合信息
|
|
143
85
|
|
|
144
86
|
| 模型ID | 名称 | 计费 |
|
|
145
87
|
|--------|------|------|
|
|
146
88
|
| `hehe-tywd` | **合合 图文混排解析** | 按量计费 |
|
|
147
89
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
90
|
+
**适合:** 扫描版合同、学术论文、含表格财务文档
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 🌐 实时搜索 — Tavily
|
|
95
|
+
|
|
96
|
+
作为独立技能安装,可与对话模型组合构建搜索增强工作流。
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## ✨ 技能严选
|
|
151
101
|
|
|
152
|
-
|
|
102
|
+
> 技能 = 多步骤自动化工作流,比单一模型调用更强大。按任务结果计费,不按 token。
|
|
153
103
|
|
|
154
104
|
---
|
|
155
105
|
|
|
156
|
-
|
|
106
|
+
### 📊 AI 演示文稿生成
|
|
107
|
+
|
|
108
|
+
输入主题或大纲,自动生成 **8-12 页专业演示文稿**,返回在线预览 + PDF 导出,无需任何设计功底。
|
|
109
|
+
|
|
110
|
+
**✅ 适合场景**
|
|
111
|
+
- 投资路演 BP、融资材料
|
|
112
|
+
- 产品发布 / 项目汇报 / 周会材料
|
|
113
|
+
- 提案文档、课件、培训材料
|
|
114
|
+
|
|
115
|
+
**💰 定价策略**
|
|
116
|
+
|
|
117
|
+
| 页数规模 | 预估费用 | 说明 |
|
|
118
|
+
|---------|---------|------|
|
|
119
|
+
| 标准(8-10页)| **约 ¥2.6~3.5** | 普通主题描述 |
|
|
120
|
+
| 丰富(10-12页)| **约 ¥3.5~4.5** | 详细大纲输入 |
|
|
121
|
+
|
|
122
|
+
> **按实际生成量计费**,不是固定价格。生成页数越多、内容越丰富,费用越高。
|
|
123
|
+
> 生成失败自动退款,不收任何费用。
|
|
124
|
+
|
|
125
|
+
**⏱ 生成时长:** 约 30~60 秒(异步任务,提交后轮询结果)
|
|
126
|
+
|
|
127
|
+
**🔌 API 调用**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# 第一步:提交任务(立即返回,< 2 秒)
|
|
131
|
+
curl -X POST https://skillfree.tech/v1/presentations \
|
|
132
|
+
-H "Authorization: Bearer YOUR_API_KEY" \
|
|
133
|
+
-H "Content-Type: application/json" \
|
|
134
|
+
-d '{
|
|
135
|
+
"model": "ai-presentation",
|
|
136
|
+
"inputs": {
|
|
137
|
+
"text": "百图生科融资路演BP,AI驱动蛋白质大模型药物发现平台,xTrimoPGLM千亿参数,已融资2亿美元",
|
|
138
|
+
"language": "zh-cn"
|
|
139
|
+
}
|
|
140
|
+
}'
|
|
141
|
+
# 返回:{ "task_id": "xxx", "status": "processing", "estimated_credits": 300 }
|
|
142
|
+
|
|
143
|
+
# 第二步:轮询结果(每隔 8~10 秒查一次)
|
|
144
|
+
curl https://skillfree.tech/v1/tasks/{task_id} \
|
|
145
|
+
-H "Authorization: Bearer YOUR_API_KEY"
|
|
146
|
+
# 完成:{ "status": "completed", "result_url": "https://...", "credits_used": 273 }
|
|
147
|
+
# 失败:{ "status": "failed", "error": "...", "credits_used": 0 }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**📋 参数说明**
|
|
157
151
|
|
|
158
|
-
|
|
152
|
+
| 参数 | 必填 | 说明 |
|
|
153
|
+
|------|------|------|
|
|
154
|
+
| `inputs.text` | ✅ | 主题描述或大纲,越详细生成质量越高 |
|
|
155
|
+
| `inputs.language` | 否 | 语言代码,默认 `zh-cn`;英文用 `en` |
|
|
156
|
+
| `inputs.format` | 否 | 固定为 `presentation`(演示文稿)|
|
|
159
157
|
|
|
160
|
-
|
|
158
|
+
**🌍 支持语言:** `zh-cn`(简体中文)· `zh-tw`(繁体)· `en`(英文)· `ja`(日文)· `ko`(韩文)及 50+ 语言
|
|
161
159
|
|
|
162
160
|
---
|
|
163
161
|
|
package/bin/skillfree.js
CHANGED
|
@@ -36,14 +36,15 @@ auth
|
|
|
36
36
|
// ── pilot ─────────────────────────────────────────────────────────────────────
|
|
37
37
|
program
|
|
38
38
|
.command('pilot')
|
|
39
|
-
.description('AI 智能调度:chat | image | video | ocr')
|
|
40
|
-
.option('--type <type>',
|
|
41
|
-
.option('--prompt <text>',
|
|
42
|
-
.option('--file <path>',
|
|
43
|
-
.option('--output <path>',
|
|
44
|
-
.option('--model <model>',
|
|
45
|
-
.option('--size <size>',
|
|
46
|
-
.option('--seconds <sec>',
|
|
39
|
+
.description('AI 智能调度:chat | image | video | ocr | presentation')
|
|
40
|
+
.option('--type <type>', '调用类型: chat | image | video | ocr | presentation', 'chat')
|
|
41
|
+
.option('--prompt <text>', '输入提示词')
|
|
42
|
+
.option('--file <path>', '输入文件路径(ocr 用)')
|
|
43
|
+
.option('--output <path>', '输出文件路径')
|
|
44
|
+
.option('--model <model>', '指定模型(可选,不填自动选最优)')
|
|
45
|
+
.option('--size <size>', '图像尺寸 或 视频分辨率(默认 1024x1024 / 1920x1080)')
|
|
46
|
+
.option('--seconds <sec>', '视频时长:4 | 6 | 8(默认 8)', '8')
|
|
47
|
+
.option('--language <lang>', '演示文稿语言(默认 zh-cn)', 'zh-cn')
|
|
47
48
|
.action(async (flags) => {
|
|
48
49
|
const { pilot } = require('../scripts/commands/pilot')
|
|
49
50
|
await pilot(flags).catch(e => { console.error('❌', e.message); process.exit(1) })
|
|
@@ -59,6 +60,27 @@ program
|
|
|
59
60
|
await pilot({ type: 'chat', prompt, ...flags }).catch(e => { console.error('❌', e.message); process.exit(1) })
|
|
60
61
|
})
|
|
61
62
|
|
|
63
|
+
// ── ppt(演示文稿快捷方式)──────────────────────────────────────────────────
|
|
64
|
+
program
|
|
65
|
+
.command('ppt <prompt>')
|
|
66
|
+
.description('AI 演示文稿生成(约 30-60 秒,按实际页数计费)')
|
|
67
|
+
.option('--language <lang>', '语言代码(默认 zh-cn;英文用 en)', 'zh-cn')
|
|
68
|
+
.action(async (prompt, flags) => {
|
|
69
|
+
const { createPresentation } = require('../scripts/commands/presentation')
|
|
70
|
+
await createPresentation({ prompt, language: flags.language })
|
|
71
|
+
.catch(e => { console.error('❌', e.message); process.exit(1) })
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// ── tasks ─────────────────────────────────────────────────────────────────────
|
|
75
|
+
const tasks = program.command('tasks').description('任务管理')
|
|
76
|
+
tasks
|
|
77
|
+
.command('get <taskId>')
|
|
78
|
+
.description('查询异步任务状态(视频、演示文稿等)')
|
|
79
|
+
.action(async (taskId) => {
|
|
80
|
+
const { getTask } = require('../scripts/commands/presentation')
|
|
81
|
+
await getTask(taskId).catch(e => { console.error('❌', e.message); process.exit(1) })
|
|
82
|
+
})
|
|
83
|
+
|
|
62
84
|
// ── models ────────────────────────────────────────────────────────────────────
|
|
63
85
|
program
|
|
64
86
|
.command('models')
|
package/install.sh
CHANGED
|
@@ -33,7 +33,7 @@ cat << 'EOF'
|
|
|
33
33
|
EOF
|
|
34
34
|
echo -e "${NC}"
|
|
35
35
|
echo -e " ${DIM}🦞 模型与技能严选平台 — 只选每个场景最好用的那一个${NC}"
|
|
36
|
-
echo -e " ${DIM} Claude · GPT · Gemini · nano banana · Veo · 合合 OCR
|
|
36
|
+
echo -e " ${DIM} Claude · GPT · Gemini · nano banana · Veo · 合合 OCR · AI演示文稿${NC}"
|
|
37
37
|
echo ""
|
|
38
38
|
echo -e " ${DIM}────────────────────────────────────────────────────${NC}"
|
|
39
39
|
echo ""
|
|
@@ -62,13 +62,13 @@ echo -e " ${DIM}正在从 npm 安装 skillfree...${NC}"
|
|
|
62
62
|
echo ""
|
|
63
63
|
|
|
64
64
|
INSTALL_OK=false
|
|
65
|
-
if npm install -g skillfree 2>&1 | sed 's/^/ /'; then
|
|
65
|
+
if npm install -g skillfree@latest 2>&1 | sed 's/^/ /'; then
|
|
66
66
|
INSTALL_OK=true
|
|
67
67
|
else
|
|
68
68
|
echo ""
|
|
69
69
|
warn "权限不足,尝试 sudo..."
|
|
70
70
|
echo ""
|
|
71
|
-
if sudo npm install -g skillfree 2>&1 | sed 's/^/ /'; then
|
|
71
|
+
if sudo npm install -g skillfree@latest 2>&1 | sed 's/^/ /'; then
|
|
72
72
|
INSTALL_OK=true
|
|
73
73
|
fi
|
|
74
74
|
fi
|
|
@@ -146,6 +146,10 @@ echo -e " ${CYAN}做一个视频:${NC}"
|
|
|
146
146
|
echo -e " ${DIM} $ skillfree pilot --type video --prompt \"一只未来感龙虾在霓虹都市中行走,电影感运镜\" --seconds 8 --size 1920x1080 --output ./video.mp4${NC}"
|
|
147
147
|
echo ""
|
|
148
148
|
|
|
149
|
+
echo -e " ${CYAN}生成一份演示文稿(30-60秒):${NC}"
|
|
150
|
+
echo -e " ${DIM} $ skillfree ppt \"百图生科融资路演BP,AI蛋白质大模型药物发现平台,已融资2亿美元\"${NC}"
|
|
151
|
+
echo ""
|
|
152
|
+
|
|
149
153
|
echo -e " ${CYAN}解析一份合同/文档:${NC}"
|
|
150
154
|
echo -e " ${DIM} $ skillfree pilot --type ocr --file ./contract.pdf --output ./result.md${NC}"
|
|
151
155
|
echo ""
|
package/package.json
CHANGED
package/scripts/commands/auth.js
CHANGED
|
@@ -12,14 +12,9 @@ function injectToOpenclaw(apiKey) {
|
|
|
12
12
|
// 1. 写入 openclaw.json
|
|
13
13
|
const openclawDir = path.join(os.homedir(), '.openclaw')
|
|
14
14
|
const cfgPath = path.join(openclawDir, 'openclaw.json')
|
|
15
|
-
if (fs.existsSync(openclawDir)
|
|
15
|
+
if (fs.existsSync(openclawDir)) {
|
|
16
16
|
let cfg = {}
|
|
17
|
-
try {
|
|
18
|
-
cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'))
|
|
19
|
-
} catch (e) {
|
|
20
|
-
console.warn('⚠️ openclaw.json 解析失败,跳过自动配置')
|
|
21
|
-
return
|
|
22
|
-
}
|
|
17
|
+
try { cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8')) } catch {}
|
|
23
18
|
cfg.skills = cfg.skills || {}
|
|
24
19
|
cfg.skills.entries = cfg.skills.entries || {}
|
|
25
20
|
cfg.skills.entries['skillfree'] = {
|
|
@@ -156,7 +156,14 @@ async function pilot(flags) {
|
|
|
156
156
|
return
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
// ── PRESENTATION(AI 演示文稿,异步轮询)────────────────────────────────────
|
|
160
|
+
if (type === 'presentation') {
|
|
161
|
+
const { createPresentation } = require('./presentation')
|
|
162
|
+
await createPresentation({ prompt, language: flags.language, format: flags.format })
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error(`不支持的类型: ${type}\n可选: chat | image | video | ocr | presentation`)
|
|
160
167
|
}
|
|
161
168
|
|
|
162
169
|
module.exports = { pilot }
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI 演示文稿生成(异步任务 + 轮询)
|
|
3
|
+
* 底层走 /v1/presentations → 拿 task_id → 轮询 /v1/tasks/:taskId
|
|
4
|
+
*/
|
|
5
|
+
const { getApiKey, BASE_URL, checkCredits } = require('../lib/client')
|
|
6
|
+
|
|
7
|
+
const POLL_INTERVAL_MS = 5000 // 每 5 秒轮询一次
|
|
8
|
+
const MAX_WAIT_MS = 120000 // 最多等 2 分钟
|
|
9
|
+
|
|
10
|
+
async function createPresentation(params) {
|
|
11
|
+
const apiKey = getApiKey()
|
|
12
|
+
|
|
13
|
+
if (!params.prompt && !params.text) {
|
|
14
|
+
throw new Error('--prompt 是必需的(主题描述或大纲)')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const inputText = params.prompt || params.text
|
|
18
|
+
const language = params.language || 'zh-cn'
|
|
19
|
+
const format = params.format || 'presentation'
|
|
20
|
+
|
|
21
|
+
await checkCredits()
|
|
22
|
+
|
|
23
|
+
// Step 1: 提交任务
|
|
24
|
+
console.log('📊 提交演示文稿生成任务...')
|
|
25
|
+
const submitRes = await fetch(`${BASE_URL}/v1/presentations`, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: {
|
|
28
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
model: 'ai-presentation',
|
|
33
|
+
inputs: { text: inputText, language, format },
|
|
34
|
+
}),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const submitData = await submitRes.json()
|
|
38
|
+
if (!submitRes.ok || !submitData.task_id) {
|
|
39
|
+
throw new Error(submitData.error || submitData.message || `提交失败:HTTP ${submitRes.status}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const taskId = submitData.task_id
|
|
43
|
+
const estimated = submitData.estimated_credits || 300
|
|
44
|
+
console.log(`⏳ 生成中(预计约 30-60 秒)...`)
|
|
45
|
+
console.log(` task_id: ${taskId}`)
|
|
46
|
+
console.log(` 预计消耗: ${estimated} 积分(¥${(estimated / 100).toFixed(2)})\n`)
|
|
47
|
+
|
|
48
|
+
// Step 2: 轮询结果
|
|
49
|
+
const deadline = Date.now() + MAX_WAIT_MS
|
|
50
|
+
while (Date.now() < deadline) {
|
|
51
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL_MS))
|
|
52
|
+
|
|
53
|
+
const pollRes = await fetch(`${BASE_URL}/v1/tasks/${taskId}`, {
|
|
54
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
55
|
+
})
|
|
56
|
+
const task = await pollRes.json()
|
|
57
|
+
|
|
58
|
+
if (task.status === 'completed') {
|
|
59
|
+
const credits = task.credits_used ?? estimated
|
|
60
|
+
console.log(`✅ 生成完成!(实际消耗 ${credits} 积分,¥${(credits / 100).toFixed(2)})\n`)
|
|
61
|
+
console.log(`🔗 在线预览:${task.result_url}`)
|
|
62
|
+
if (task.upstream_id && task.upstream_id.startsWith('http')) {
|
|
63
|
+
console.log(`📄 PDF 导出:${task.upstream_id}`)
|
|
64
|
+
}
|
|
65
|
+
return task
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (task.status === 'failed') {
|
|
69
|
+
throw new Error(`生成失败:${task.error || '未知错误'}(积分已自动退还)`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// processing → 继续等待
|
|
73
|
+
process.stdout.write('.')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
throw new Error('生成超时(超过 2 分钟),请稍后用以下命令查询进度:\n skillfree tasks get ' + taskId)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function getTask(taskId) {
|
|
80
|
+
const apiKey = getApiKey()
|
|
81
|
+
const res = await fetch(`${BASE_URL}/v1/tasks/${taskId}`, {
|
|
82
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
83
|
+
})
|
|
84
|
+
const task = await res.json()
|
|
85
|
+
|
|
86
|
+
if (!res.ok) throw new Error(task.error || `HTTP ${res.status}`)
|
|
87
|
+
|
|
88
|
+
const statusIcon = { completed: '✅', failed: '❌', processing: '⏳' }[task.status] || '❓'
|
|
89
|
+
console.log(`\n${statusIcon} 任务 ${task.task_id}`)
|
|
90
|
+
console.log(` 状态:${task.status}`)
|
|
91
|
+
console.log(` 模型:${task.model}`)
|
|
92
|
+
if (task.result_url) console.log(` 在线预览:${task.result_url}`)
|
|
93
|
+
if (task.upstream_id?.startsWith('http')) console.log(` PDF 导出:${task.upstream_id}`)
|
|
94
|
+
if (task.error) console.log(` 错误:${task.error}`)
|
|
95
|
+
console.log(` 创建:${task.created_at}`)
|
|
96
|
+
console.log(` 更新:${task.updated_at}`)
|
|
97
|
+
return task
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = { createPresentation, getTask }
|