@aiyiran/myclaw 1.0.201 → 1.0.202

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.
Files changed (37) hide show
  1. package/index.js +113 -25
  2. package/{inject-clear-models.js → injects/inject-clear-models.js} +1 -1
  3. package/{inject-image.js → injects/inject-image.js} +1 -1
  4. package/{inject-minimax.js → injects/inject-minimax.js} +1 -1
  5. package/{inject-search.js → injects/inject-search.js} +1 -1
  6. package/{inject-token.js → injects/inject-token.js} +1 -1
  7. package/injects/inject-tooldeny.js +50 -0
  8. package/{inject-zai.js → injects/inject-zai.js} +1 -1
  9. package/package.json +1 -1
  10. package/{patch-manifest.json → patches/patch-manifest.json} +15 -5
  11. package/{patch-reset.js → patches/patch-reset.js} +1 -1
  12. package/{patch-skill.js → patches/patch-skill.js} +6 -1
  13. package/pull.js +1 -1
  14. package/skills/vapi-image-gen-1.0.1/README.md +92 -0
  15. package/skills/vapi-image-gen-1.0.1/SKILL.md +75 -0
  16. package/skills/vapi-image-gen-1.0.1/_meta.json +6 -0
  17. package/skills/vapi-image-gen-1.0.1/scripts/gen.py +259 -0
  18. package/skills/yiran-skill-media/SKILL.md +74 -0
  19. package/skills/yiran-skill-media/config.json +26 -0
  20. package/skills/yiran-skill-media/references/image-api.md +88 -0
  21. package/skills/yiran-skill-media/references/music-api.md +120 -0
  22. package/skills/yiran-skill-media/scripts/generate.py +165 -0
  23. package/skills/yiran-skill-media/scripts/generation_log.json +20 -0
  24. package/skills/yiran-skill-media/scripts/image.sh +43 -0
  25. package/skills/yiran-skill-media/scripts/music.sh +46 -0
  26. package/skills/yiran-skill-media/scripts/providers/__init__.py +15 -0
  27. package/skills/yiran-skill-media/scripts/providers/__pycache__/__init__.cpython-311.pyc +0 -0
  28. package/skills/yiran-skill-media/scripts/providers/__pycache__/minimax_image.cpython-311.pyc +0 -0
  29. package/skills/yiran-skill-media/scripts/providers/__pycache__/minimax_music.cpython-311.pyc +0 -0
  30. package/skills/yiran-skill-media/scripts/providers/__pycache__/vapi_image.cpython-311.pyc +0 -0
  31. package/skills/yiran-skill-media/scripts/providers/minimax_image.py +75 -0
  32. package/skills/yiran-skill-media/scripts/providers/minimax_music.py +61 -0
  33. package/skills/yiran-skill-media/scripts/providers/vapi_image.py +63 -0
  34. package/skills/yiran-skill-media/scripts/registry.py +133 -0
  35. /package/{inject-workspaceAndSoul.js → injects/inject-workspaceAndSoul.js} +0 -0
  36. /package/{patch-agent.js → patches/patch-agent.js} +0 -0
  37. /package/{patch.js → patches/patch.js} +0 -0
package/index.js CHANGED
@@ -682,8 +682,8 @@ function runOpen() {
682
682
  // ============================================================================
683
683
 
684
684
  function runPatch() {
685
- const { patch, status: patchStatus } = require('./patch');
686
- const { patchSkills } = require('./patch-skill');
685
+ const { patch, status: patchStatus } = require('./patches/patch');
686
+ const { patchSkills } = require('./patches/patch-skill');
687
687
  const { patchConfig } = require('./find-config');
688
688
  const bar = '----------------------------------------';
689
689
 
@@ -701,13 +701,13 @@ function runPatch() {
701
701
 
702
702
  // 3. 智能体上传(从 agent-list/ 复制到 ~/.openclaw/)
703
703
  console.log('');
704
- const { patchAgents } = require('./patch-agent');
704
+ const { patchAgents } = require('./patches/patch-agent');
705
705
  const agentResult = patchAgents();
706
706
 
707
707
  // 4. Config 补丁(从 manifest 读取,修改 openclaw.json)
708
708
  console.log('');
709
709
  try {
710
- const { loadManifest } = require('./patch-agent');
710
+ const { loadManifest } = require('./patches/patch-agent');
711
711
  const manifest = loadManifest();
712
712
  if (manifest && manifest.config && manifest.config.patches) {
713
713
  const configStrategy = manifest.config.strategy || 'on';
@@ -757,7 +757,7 @@ function runPatch() {
757
757
  // 通过修改 manifest 即可控制额外脚本(如 inject-image, inject-search)是否跟随 patch 自动执行,
758
758
  // 从而避免硬编码具体要注入哪些模块。
759
759
  try {
760
- const { loadManifest } = require('./patch-agent');
760
+ const { loadManifest } = require('./patches/patch-agent');
761
761
  const m = loadManifest();
762
762
  if (m && Array.isArray(m.run) && m.run.length > 0) {
763
763
  console.log('');
@@ -791,7 +791,7 @@ function runPatch() {
791
791
  }
792
792
 
793
793
  function runUnpatch() {
794
- const { unpatch } = require('./patch');
794
+ const { unpatch } = require('./patches/patch');
795
795
  const bar = '----------------------------------------';
796
796
 
797
797
  console.log('');
@@ -959,7 +959,7 @@ function runUpdate() {
959
959
  // ============================================================================
960
960
 
961
961
  function runList() {
962
- const { loadManifest } = require('./patch-agent');
962
+ const { loadManifest } = require('./patches/patch-agent');
963
963
  const bar = '----------------------------------------';
964
964
 
965
965
  console.log('');
@@ -1166,6 +1166,84 @@ function runInteractiveMenu() {
1166
1166
  // 帮助信息
1167
1167
  // ============================================================================
1168
1168
 
1169
+ // ============================================================================
1170
+ // inject 交互菜单
1171
+ // ============================================================================
1172
+
1173
+ const INJECT_MENU = [
1174
+ { key: '1', cmd: 'inject-minimax', desc: '注入 MiniMax 模型配置' },
1175
+ { key: '2', cmd: 'inject-zai', desc: '注入智谱 GLM 模型配置' },
1176
+ { key: '3', cmd: 'inject-image', desc: '注入图像生成模型配置 (vveai)' },
1177
+ { key: '4', cmd: 'inject-search', desc: '注入 Tavily 搜索插件配置' },
1178
+ { key: '5', cmd: 'inject-token', desc: '设置 Gateway Token 为 aiyiran' },
1179
+ { key: '6', cmd: 'inject-workspaceAndSoul', desc: '替换默认 workspace 的 SOUL.md' },
1180
+ { key: '7', cmd: 'inject-tooldeny', desc: 'deny image_generate + music_generate 内置工具' },
1181
+ { key: 'a', cmd: 'all', desc: '执行以上全部注入' },
1182
+ ];
1183
+
1184
+ function runInjectCommand(cmd, extraArgs) {
1185
+ const modules = {
1186
+ 'inject-minimax': './inject-minimax',
1187
+ 'inject-zai': './inject-zai',
1188
+ 'inject-image': './inject-image',
1189
+ 'inject-search': './inject-search',
1190
+ 'inject-token': './inject-token',
1191
+ 'inject-workspaceAndSoul': './inject-workspaceAndSoul',
1192
+ 'inject-tooldeny': './inject-tooldeny',
1193
+ };
1194
+ const mod = require(modules[cmd]);
1195
+ mod.run(extraArgs || []);
1196
+ console.log('🔄 正在重启 Gateway 使配置生效...');
1197
+ console.log('');
1198
+ }
1199
+
1200
+ function showInjectMenu() {
1201
+ console.log('');
1202
+ console.log(colors.blue + '📦 注入脚本选择' + colors.nc);
1203
+ console.log('----------------------------------------');
1204
+ console.log('');
1205
+ for (const item of INJECT_MENU) {
1206
+ console.log(' ' + colors.cyan + item.key + colors.nc + ') ' + item.desc);
1207
+ }
1208
+ console.log(' ' + colors.cyan + '0' + colors.nc + ') 返回');
1209
+ console.log('');
1210
+
1211
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1212
+ rl.question('请选择 [0-' + INJECT_MENU.length + '/a]: ', function (answer) {
1213
+ rl.close();
1214
+ const choice = answer.trim().toLowerCase();
1215
+
1216
+ if (choice === '0' || choice === '') {
1217
+ return;
1218
+ }
1219
+
1220
+ if (choice === 'a') {
1221
+ for (const item of INJECT_MENU) {
1222
+ if (item.cmd !== 'all') {
1223
+ try {
1224
+ console.log('');
1225
+ console.log('→ ' + item.desc + '...');
1226
+ runInjectCommand(item.cmd);
1227
+ } catch (err) {
1228
+ console.log(' ❌ 失败: ' + err.message);
1229
+ }
1230
+ }
1231
+ }
1232
+ runRestart();
1233
+ return;
1234
+ }
1235
+
1236
+ const found = INJECT_MENU.find(m => m.key === choice);
1237
+ if (!found) {
1238
+ console.log('[' + colors.red + '错误' + colors.nc + '] 无效选择: ' + choice);
1239
+ return;
1240
+ }
1241
+
1242
+ runInjectCommand(found.cmd, args.slice(1));
1243
+ runRestart();
1244
+ });
1245
+ }
1246
+
1169
1247
  function showHelp() {
1170
1248
  console.log('');
1171
1249
  console.log('MyClaw - 学生友好的 OpenClaw 工具');
@@ -1197,12 +1275,14 @@ function showHelp() {
1197
1275
  console.log(' pull 从 ~/.openclaw 拉取最新资源到源目录(开发用)');
1198
1276
  console.log(' patch 注入 MyClaw UI + 技能 + 智能体 + 配置');
1199
1277
  console.log(' unpatch 回滚 UI 注入(恢复原版)');
1200
- console.log(' minimax 注入 MiniMax 模型配置 (可选: --key sk-xxx, -f 强制清理其他模型)');
1201
- console.log(' zai 注入智谱 GLM 模型配置 (可选: --key xxx, -f 强制清理其他模型)');
1202
- console.log(' image 注入图像生成模型配置 (基于 vveai)');
1203
- console.log(' token 设置 Gateway Token 为 aiyiran');
1204
- console.log(' websearch 注入 Tavily 搜索插件配置');
1205
- console.log(' soul 替换默认 workspace 的 SOUL.md 提示词');
1278
+ console.log(' inject 交互选择要执行的注入脚本');
1279
+ console.log(' inject-minimax 注入 MiniMax 模型配置 (可选: --key sk-xxx, -f 强制清理其他模型)');
1280
+ console.log(' inject-zai 注入智谱 GLM 模型配置 (可选: --key xxx, -f 强制清理其他模型)');
1281
+ console.log(' inject-image 注入图像生成模型配置 (基于 vveai)');
1282
+ console.log(' inject-token 设置 Gateway Token 为 aiyiran');
1283
+ console.log(' inject-search 注入 Tavily 搜索插件配置');
1284
+ console.log(' inject-workspaceAndSoul 替换默认 workspace 的 SOUL.md 提示词');
1285
+ console.log(' inject-tooldeny deny image_generate + music_generate 内置工具');
1206
1286
  console.log(' restart 重启 OpenClaw Gateway');
1207
1287
  console.log(' help 显示帮助信息');
1208
1288
  console.log('');
@@ -1286,43 +1366,51 @@ if (!command) {
1286
1366
  runUninstall();
1287
1367
  } else if (command === 'restart') {
1288
1368
  runRestart();
1289
- } else if (command === 'minimax') {
1290
- const minimax = require('./inject-minimax');
1369
+ } else if (command === 'inject') {
1370
+ showInjectMenu();
1371
+ } else if (command === 'inject-minimax') {
1372
+ const minimax = require('./injects/inject-minimax');
1291
1373
  minimax.run(args.slice(1));
1292
1374
  // 注入完成后自动重启 Gateway
1293
1375
  console.log('🔄 正在重启 Gateway 使配置生效...');
1294
1376
  console.log('');
1295
1377
  runRestart();
1296
- } else if (command === 'zai') {
1297
- const zai = require('./inject-zai');
1378
+ } else if (command === 'inject-zai') {
1379
+ const zai = require('./injects/inject-zai');
1298
1380
  zai.run(args.slice(1));
1299
1381
  console.log('🔄 正在重启 Gateway 使配置生效...');
1300
1382
  console.log('');
1301
1383
  runRestart();
1302
- } else if (command === 'image') {
1303
- const image = require('./inject-image');
1384
+ } else if (command === 'inject-image') {
1385
+ const image = require('./injects/inject-image');
1304
1386
  image.run(args.slice(1));
1305
1387
  console.log('🔄 正在重启 Gateway 使配置生效...');
1306
1388
  console.log('');
1307
1389
  runRestart();
1308
- } else if (command === 'token') {
1309
- const token = require('./inject-token');
1390
+ } else if (command === 'inject-token') {
1391
+ const token = require('./injects/inject-token');
1310
1392
  token.run(args.slice(1));
1311
1393
  console.log('🔄 正在重启 Gateway 使配置生效...');
1312
1394
  console.log('');
1313
1395
  runRestart();
1314
- } else if (command === 'websearch') {
1315
- const search = require('./inject-search');
1396
+ } else if (command === 'inject-search') {
1397
+ const search = require('./injects/inject-search');
1316
1398
  search.run(args.slice(1));
1317
1399
  console.log('🔄 正在重启 Gateway 使配置生效...');
1318
1400
  console.log('');
1319
1401
  runRestart();
1320
- } else if (command === 'soul') {
1321
- const soul = require('./inject-workspaceAndSoul');
1402
+ } else if (command === 'inject-workspaceAndSoul') {
1403
+ const soul = require('./injects/inject-workspaceAndSoul');
1322
1404
  soul.run();
1323
1405
  console.log('🔄 正在重启 Gateway 使配置生效...');
1324
1406
  console.log('');
1325
1407
  runRestart();
1408
+ } else if (command === 'inject-tooldeny') {
1409
+ const tooldeny = require('./injects/inject-tooldeny');
1410
+ media.run(args.slice(1));
1411
+ console.log('🔄 正在重启 Gateway 使配置生效...');
1412
+ console.log('');
1413
+ runRestart();
1326
1414
  } else {
1327
1415
  console.error('[' + colors.red + '错误' + colors.nc + '] 未知命令: ' + command);
1328
1416
  showHelp();
@@ -7,7 +7,7 @@
7
7
  * 保留图片模型和搜索配置
8
8
  */
9
9
 
10
- const { readConfig, writeConfig } = require('./find-config');
10
+ const { readConfig, writeConfig } = require('../find-config');
11
11
 
12
12
  function run() {
13
13
  let configPath;
@@ -7,7 +7,7 @@
7
7
  * 这样就可以通过 `myclaw image` 直接覆盖图像模型。
8
8
  */
9
9
 
10
- const { readConfig, writeConfig } = require('./find-config');
10
+ const { readConfig, writeConfig } = require('../find-config');
11
11
 
12
12
  function run(cliArgs) {
13
13
  let configPath;
@@ -14,7 +14,7 @@
14
14
  * 入口: myclaw minimax [--key sk-xxx]
15
15
  */
16
16
 
17
- const { readConfig, writeConfig } = require('./find-config');
17
+ const { readConfig, writeConfig } = require('../find-config');
18
18
 
19
19
  // ============================================================
20
20
  // 请在这里填写默认的 MiniMax API Key
@@ -8,7 +8,7 @@
8
8
  * 入口: myclaw plus search
9
9
  */
10
10
 
11
- const { readConfig, writeConfig } = require('./find-config');
11
+ const { readConfig, writeConfig } = require('../find-config');
12
12
 
13
13
  function run(cliArgs) {
14
14
  let configPath;
@@ -8,7 +8,7 @@
8
8
  * 入口: myclaw token
9
9
  */
10
10
 
11
- const { readConfig, writeConfig } = require('./find-config');
11
+ const { readConfig, writeConfig } = require('../find-config');
12
12
 
13
13
  function run(cliArgs) {
14
14
  let configPath;
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * inject-rewriteMedia.js
5
+ *
6
+ * deny image_generate 工具,使智能体优先使用 yiran-skill-media skill。
7
+ */
8
+
9
+ const { readConfig, writeConfig } = require('../find-config');
10
+
11
+ function run() {
12
+ let configPath;
13
+ try {
14
+ ({ configPath } = readConfig());
15
+ } catch (err) {
16
+ console.error('❌ ' + err.message);
17
+ process.exit(1);
18
+ }
19
+
20
+ console.log('📍 找到配置: ' + configPath);
21
+ console.log('');
22
+
23
+ const { config } = readConfig();
24
+
25
+ // ── deny image_generate 工具 ──
26
+ if (!config.tools) config.tools = {};
27
+ if (!config.tools.deny) config.tools.deny = [];
28
+ for (const tool of ['image_generate', 'music_generate']) {
29
+ if (!config.tools.deny.includes(tool)) {
30
+ config.tools.deny.push(tool);
31
+ console.log(' ✓ 已添加 tools.deny["' + tool + '"]');
32
+ } else {
33
+ console.log(' ○ tools.deny 已包含 ' + tool + ',跳过');
34
+ }
35
+ }
36
+
37
+ writeConfig(config, configPath);
38
+
39
+ // ── 验证 ──
40
+ const verify = readConfig();
41
+ const deniedTools = verify.config.tools?.deny || [];
42
+
43
+ console.log('');
44
+ console.log('✅ rewriteMedia 注入完成');
45
+ console.log(' [验证] tools.deny image_generate: ' + deniedTools.includes('image_generate'));
46
+ console.log(' [验证] tools.deny music_generate: ' + deniedTools.includes('music_generate'));
47
+ console.log('');
48
+ }
49
+
50
+ module.exports = { run };
@@ -13,7 +13,7 @@
13
13
  * 入口: myclaw zai [--key xxx]
14
14
  */
15
15
 
16
- const { readConfig, writeConfig } = require('./find-config');
16
+ const { readConfig, writeConfig } = require('../find-config');
17
17
  const fs = require('fs');
18
18
  const path = require('path');
19
19
  const os = require('os');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.201",
3
+ "version": "1.0.202",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -12,6 +12,11 @@
12
12
  "name": "tavily-search",
13
13
  "strategy": "off",
14
14
  "description": "tavily-search (Tavily 搜索技能包)"
15
+ },
16
+ {
17
+ "name": "yiran-skill-media",
18
+ "strategy": "on",
19
+ "description": "统一多媒体生成 skill(图片+音乐,主备切换)"
15
20
  }
16
21
  ],
17
22
  "_doc_agents": "Step 3: 将 agent-list/ 下的智能体分发到 ~/.openclaw/ 并注册到 openclaw.json",
@@ -43,29 +48,34 @@
43
48
  "_doc_run": "Step 5: 按顺序 require(module).run([]) 执行自定义脚本,不触发 Gateway 重启",
44
49
  "run": [
45
50
  {
46
- "module": "./inject-search",
51
+ "module": "./injects/inject-search",
47
52
  "strategy": "auto",
48
53
  "description": "搜索配置注入 (Tavily)"
49
54
  },
50
55
  {
51
- "module": "./inject-minimax",
56
+ "module": "./injects/inject-minimax",
52
57
  "strategy": "auto",
53
58
  "description": "MiniMax 模型注入"
54
59
  },
55
60
  {
56
- "module": "./inject-image",
61
+ "module": "./injects/inject-image",
57
62
  "strategy": "auto",
58
63
  "description": "图片模型注入 (vveai)"
59
64
  },
60
65
  {
61
- "module": "./inject-workspaceAndSoul",
66
+ "module": "./injects/inject-workspaceAndSoul",
62
67
  "strategy": "on",
63
68
  "description": "替换默认 workspace 的 SOUL.md 提示词"
64
69
  },
65
70
  {
66
- "module": "./inject-token",
71
+ "module": "./injects/inject-token",
67
72
  "strategy": "auto",
68
73
  "description": "Gateway Token 设置为 aiyiran"
74
+ },
75
+ {
76
+ "module": "./injects/inject-tooldeny",
77
+ "strategy": "on",
78
+ "description": "deny image_generate + music_generate 内置工具"
69
79
  }
70
80
  ]
71
81
  }
@@ -6,7 +6,7 @@
6
6
  * 入口: myclaw reset-idle [--minutes N]
7
7
  */
8
8
 
9
- const { patchConfig, readConfig } = require('./find-config');
9
+ const { patchConfig, readConfig } = require('../find-config');
10
10
 
11
11
  /**
12
12
  * 将 session.reset 设为 idle 模式,默认 90720 分钟(≈63 天)
@@ -120,7 +120,12 @@ function patchSkills() {
120
120
  for (const skillDir of skillDirs) {
121
121
  const srcDir = path.join(myclawSkillsDir, skillDir.name);
122
122
  const destDir = path.join(skillsDir, skillDir.name);
123
- const strategy = skillStrategyMap[skillDir.name] || 'auto';
123
+ const strategy = skillStrategyMap[skillDir.name];
124
+
125
+ if (!strategy) {
126
+ console.log('[myclaw-skill] ⊘ 跳过: ' + skillDir.name + ' [未配置,跳过]');
127
+ continue;
128
+ }
124
129
 
125
130
  if (strategy === 'off') {
126
131
  console.log('[myclaw-skill] ⊘ 跳过: ' + skillDir.name + ' [off]');
package/pull.js CHANGED
@@ -21,7 +21,7 @@ const os = require('os');
21
21
  const OPENCLAW_DIR = path.join(os.homedir(), '.openclaw');
22
22
  const AGENT_LIST_DIR = path.join(__dirname, 'agent-list');
23
23
  const SKILLS_DIR = path.join(__dirname, 'skills');
24
- const MANIFEST_PATH = path.join(__dirname, 'patch-manifest.json');
24
+ const MANIFEST_PATH = path.join(__dirname, 'patches/patch-manifest.json');
25
25
 
26
26
  // 不应拉取的 workspace(排除列表)
27
27
  const WORKSPACE_IGNORE = new Set([
@@ -0,0 +1,92 @@
1
+ # 🎨 vapi-image-gen
2
+
3
+ Generate images with AI via VAPI's OpenAI-compatible Images API.
4
+ 通过 VAPI 的 OpenAI 兼容图像 API,让你的 AI 助手学会画画。
5
+
6
+ Supports **nano-banana** and **gpt-image** model series. Fast, flexible, works out of the box once configured.
7
+
8
+ ---
9
+
10
+ ## ✅ Requirements / 前置条件
11
+
12
+ - Python 3
13
+ - A [VAPI API Key](https://api.v3.cm) (`VAPI_API_KEY`)
14
+
15
+ ---
16
+
17
+ ## ⚙️ Configuration / 配置
18
+
19
+ Set in `.env` or `~/.openclaw/openclaw.json`:
20
+ - `VAPI_API_KEY` — your VAPI API key **(required)**
21
+ - `VAPI_BASE_URL` — base URL with /v1 suffix **(required)**; defaults to `https://api.v3.cm/v1` if not set
22
+
23
+ ---
24
+
25
+ ## 💬 Example Prompts / 示例提示词
26
+
27
+ Once configured, just tell your AI assistant what you want:
28
+
29
+ 配置好后,直接用自然语言告诉 AI 你想要什么:
30
+
31
+ ### 🖼️ Basic Generation / 基础生图
32
+
33
+ | English | 中文 |
34
+ |---|---|
35
+ | Draw a sunset over the ocean | 画一张海上日落的风景 |
36
+ | Generate a cyberpunk city at night | 生成一张赛博朋克风格的城市夜景 |
37
+ | Create a cute cartoon cat illustration | 画一只可爱的卡通猫咪插画 |
38
+
39
+ ### 📐 With Aspect Ratio / 指定比例
40
+
41
+ | English | 中文 |
42
+ |---|---|
43
+ | Generate a 16:9 wallpaper of a starry sky | 生成一张 16:9 的星空壁纸 |
44
+ | Draw a 2:3 portrait of a fantasy warrior | 画一张 2:3 竖版奇幻战士肖像 |
45
+ | Create a 1:1 square avatar of a fox in a suit | 画一个穿西装的狐狸头像,1:1 方形 |
46
+
47
+ ### 💾 Save to Local / 保存到本地
48
+
49
+ | English | 中文 |
50
+ |---|---|
51
+ | Generate a forest scene and save it | 生成一张森林场景的图片,保存到本地 |
52
+ | Draw 3 variations of a mountain landscape and save | 画 3 张山景图,保存到本地 |
53
+
54
+ ### 🔍 High Resolution / 高清生图
55
+
56
+ | English | 中文 |
57
+ |---|---|
58
+ | Generate a high-res 4K illustration of a dragon | 用高清 4K 模型画一条龙的插画 |
59
+ | Create a 2K detailed city map illustration | 生成一张 2K 高清城市地图插画 |
60
+
61
+ ---
62
+
63
+ ## 🤖 Supported Models / 支持的模型
64
+
65
+ | Model | Quality | Output |
66
+ |---|---|---|
67
+ | `nano-banana` | Standard | URL |
68
+ | `nano-banana-pro` ⭐ | Better — **Default** | URL |
69
+ | `nano-banana-2` | Gen 2 | URL |
70
+ | `nano-banana-pro-2k` | High-res 2K | URL |
71
+ | `nano-banana-pro-4k` | Ultra 4K | URL |
72
+ | `gpt-image-1` | High quality | Saved file |
73
+ | `gpt-image-1.5` | Higher quality | Saved file |
74
+
75
+ ---
76
+
77
+ ## 📁 Save Behavior / 图片保存说明
78
+
79
+ | Flag | Behavior |
80
+ |---|---|
81
+ | *(default)* | Returns image URL only, no local file |
82
+ | `--save` | Saves to `~/.openclaw/media/` |
83
+ | `--oss` | Saves to `~/.openclaw/oss/` |
84
+ | `gpt-image` models | Always saved (API returns base64 only) |
85
+
86
+ ---
87
+
88
+ ## 🔗 Links
89
+
90
+ - VAPI API: [api.v3.cm](https://api.v3.cm)
91
+ - OpenClaw: [openclaw.ai](https://openclaw.ai)
92
+ - ClawHub: [clawhub.ai](https://clawhub.ai)
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: vapi-image-gen
3
+ description: Generate images via VAPI's OpenAI-compatible Images API. Supports nano-banana and gpt-image model series. Default model is nano-banana-pro. Images are NOT saved locally by default (URL only). Use --save flag when the user wants to keep the image.
4
+ homepage: https://api.v3.cm
5
+ license: MIT
6
+ metadata:
7
+ {
8
+ "openclaw":
9
+ {
10
+ "emoji": "🎨",
11
+ "requires": { "bins": ["python3"], "env": ["VAPI_API_KEY", "VAPI_BASE_URL"] },
12
+ "primaryEnv": "VAPI_API_KEY",
13
+ },
14
+ }
15
+ ---
16
+
17
+ # VAPI Image Gen
18
+
19
+ Generate images via VAPI's OpenAI-compatible Images API (`/images/generations`).
20
+
21
+ ## Basic Usage
22
+
23
+ ```bash
24
+ python3 {baseDir}/scripts/gen.py --prompt "your prompt here"
25
+ ```
26
+
27
+ ## Options
28
+
29
+ ```bash
30
+ # Specify model (default: nano-banana-pro)
31
+ python3 {baseDir}/scripts/gen.py --prompt "..." --model nano-banana-pro
32
+
33
+ # Higher resolution (append -2k or -4k to model name)
34
+ python3 {baseDir}/scripts/gen.py --prompt "..." --model nano-banana-pro-2k
35
+
36
+ # Save image locally (default: NO save, URL only)
37
+ python3 {baseDir}/scripts/gen.py --prompt "..." --save
38
+
39
+ # Save to OSS directory (~/.openclaw/oss/)
40
+ python3 {baseDir}/scripts/gen.py --prompt "..." --oss
41
+
42
+ # Save to custom directory
43
+ python3 {baseDir}/scripts/gen.py --prompt "..." --save --out-dir /path/to/dir
44
+
45
+ # Aspect ratio
46
+ python3 {baseDir}/scripts/gen.py --prompt "..." --aspect-ratio 16:9
47
+
48
+ # Image count
49
+ python3 {baseDir}/scripts/gen.py --prompt "..." --count 2
50
+ ```
51
+
52
+ ## Supported Models
53
+
54
+ nano-banana series (returns URL, fast):
55
+ - nano-banana
56
+ - nano-banana-pro ← default
57
+ - nano-banana-2
58
+ - nano-banana-pro-2k / nano-banana-pro-4k (high res)
59
+
60
+ gpt-image series (returns base64, always saved):
61
+ - gpt-image-1
62
+ - gpt-image-1.5
63
+
64
+ ## Config
65
+
66
+ Set in `.env` or `~/.openclaw/openclaw.json`:
67
+ - `VAPI_API_KEY` — your VAPI API key **(required)**
68
+ - `VAPI_BASE_URL` — base URL with /v1 suffix **(required)**; defaults to `https://api.v3.cm/v1` if not set
69
+
70
+ ## Save Behavior
71
+
72
+ - Default: no local file, output `MEDIA:<url>` directly
73
+ - `--save`: save to `~/.openclaw/media/`
74
+ - `--oss`: save to `~/.openclaw/oss/`
75
+ - gpt-image models always save to media/ (API returns base64 only)
@@ -0,0 +1,6 @@
1
+ {
2
+ "ownerId": "kn7bawj4pyzcexc34av7715mmd82a9d9",
3
+ "slug": "vapi-image-gen",
4
+ "version": "1.0.1",
5
+ "publishedAt": 1773200855499
6
+ }