skillfree 0.1.4 → 0.1.6
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 +1 -1
- package/package.json +1 -1
- package/scripts/commands/pilot.js +77 -10
package/SKILL.md
CHANGED
package/package.json
CHANGED
|
@@ -75,8 +75,30 @@ async function pilot(flags) {
|
|
|
75
75
|
|
|
76
76
|
// ── IMAGE ─────────────────────────────────────────────────────────────────────
|
|
77
77
|
if (type === 'image') {
|
|
78
|
+
const imageModel = model || 'gemini-3.1-flash-image-preview'
|
|
79
|
+
|
|
80
|
+
// qwen-image-edit-plus:图片编辑,走 /v1/images/edits,multipart/form-data
|
|
81
|
+
if (imageModel.startsWith('qwen-image')) {
|
|
82
|
+
if (!flags.file) throw new Error('qwen-image-edit 需要 --file 指定原始图片路径')
|
|
83
|
+
const imgBuf = fs.readFileSync(path.resolve(flags.file))
|
|
84
|
+
const form = new FormData()
|
|
85
|
+
form.append('model', imageModel)
|
|
86
|
+
form.append('prompt', prompt)
|
|
87
|
+
form.append('size', flags.size || '1024x1024')
|
|
88
|
+
form.append('image', new Blob([imgBuf], { type: 'image/png' }), path.basename(flags.file))
|
|
89
|
+
const res = await request('/images/edits', { method: 'POST', body: form })
|
|
90
|
+
const data = await res.json()
|
|
91
|
+
if (data.error) throw new Error(data.error.message || JSON.stringify(data.error))
|
|
92
|
+
const url = data.data?.[0]?.url
|
|
93
|
+
if (!url) throw new Error('未返回图像URL: ' + JSON.stringify(data).slice(0, 200))
|
|
94
|
+
if (output) await downloadAndSave(url, output)
|
|
95
|
+
else console.log('图像 URL:', url)
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// doubao-seedream-5.0-lite / 其他标准图像模型
|
|
78
100
|
const res = await post('/images/generations', {
|
|
79
|
-
model:
|
|
101
|
+
model: imageModel,
|
|
80
102
|
prompt,
|
|
81
103
|
n: 1,
|
|
82
104
|
size: flags.size || '1024x1024',
|
|
@@ -85,12 +107,8 @@ async function pilot(flags) {
|
|
|
85
107
|
const url = res.data?.[0]?.url || res.data?.[0]?.b64_json
|
|
86
108
|
if (!url) throw new Error('未返回图像数据: ' + JSON.stringify(res).slice(0, 200))
|
|
87
109
|
if (output) {
|
|
88
|
-
if (url.startsWith('http'))
|
|
89
|
-
|
|
90
|
-
} else {
|
|
91
|
-
fs.writeFileSync(output, Buffer.from(url, 'base64'))
|
|
92
|
-
console.log(`✅ 已保存到 ${output}`)
|
|
93
|
-
}
|
|
110
|
+
if (url.startsWith('http')) await downloadAndSave(url, output)
|
|
111
|
+
else { fs.writeFileSync(output, Buffer.from(url, 'base64')); console.log(`✅ 已保存到 ${output}`) }
|
|
94
112
|
} else {
|
|
95
113
|
console.log('图像 URL:', url)
|
|
96
114
|
}
|
|
@@ -216,8 +234,26 @@ async function pilot(flags) {
|
|
|
216
234
|
throw new Error('Suno 生成超时(150s),请手动查询 task_id: ' + taskId)
|
|
217
235
|
|
|
218
236
|
} else {
|
|
219
|
-
// music-2.5(MiniMax
|
|
220
|
-
|
|
237
|
+
// music-2.5(MiniMax),走 /v1/responses,需要 lyrics
|
|
238
|
+
const res = await request('/responses', {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
body: JSON.stringify({
|
|
241
|
+
model: 'music-2.5',
|
|
242
|
+
input: prompt,
|
|
243
|
+
lyrics: flags.lyrics || `[verse]\n${prompt}`,
|
|
244
|
+
audio_setting: { sample_rate: 44100, bitrate: 256000, format: 'mp3' },
|
|
245
|
+
output_format: 'url',
|
|
246
|
+
stream: false,
|
|
247
|
+
}),
|
|
248
|
+
})
|
|
249
|
+
const data = await res.json()
|
|
250
|
+
if (data.error) throw new Error(data.error.message || JSON.stringify(data.error))
|
|
251
|
+
const audioUrl = data.output?.[0]?.content?.[0]?.audio
|
|
252
|
+
if (!audioUrl) throw new Error('未返回音频: ' + JSON.stringify(data).slice(0, 200))
|
|
253
|
+
const duration = ((data.extra_info?.music_duration || 0) / 1000).toFixed(1)
|
|
254
|
+
console.log(`✅ music-2.5 生成成功!时长约 ${duration} 秒`)
|
|
255
|
+
console.log('音频 URL:', audioUrl)
|
|
256
|
+
if (output) await downloadAndSave(audioUrl, output)
|
|
221
257
|
}
|
|
222
258
|
}
|
|
223
259
|
|
|
@@ -265,7 +301,38 @@ async function pilot(flags) {
|
|
|
265
301
|
return
|
|
266
302
|
}
|
|
267
303
|
|
|
268
|
-
|
|
304
|
+
// ── EMBEDDING ─────────────────────────────────────────────────────────────────
|
|
305
|
+
if (type === 'embedding') {
|
|
306
|
+
// doubao-embedding-vision:走 /v1/responses(多模态),input 为数组
|
|
307
|
+
// 简单文本 embedding 也可用
|
|
308
|
+
const inputData = flags.file
|
|
309
|
+
? [{ type: 'image_url', image_url: { url: 'data:image/png;base64,' + fs.readFileSync(path.resolve(flags.file)).toString('base64') } }]
|
|
310
|
+
: [{ type: 'text', text: prompt }]
|
|
311
|
+
const res = await request('/embeddings', {
|
|
312
|
+
method: 'POST',
|
|
313
|
+
body: JSON.stringify({
|
|
314
|
+
model: model || 'doubao-embedding-vision-251215',
|
|
315
|
+
input: inputData,
|
|
316
|
+
encoding_format: 'float',
|
|
317
|
+
dimensions: 1024,
|
|
318
|
+
sparse_embedding: { type: 'disabled' },
|
|
319
|
+
}),
|
|
320
|
+
})
|
|
321
|
+
const data = await res.json()
|
|
322
|
+
if (data.error) throw new Error(data.error.message || JSON.stringify(data.error))
|
|
323
|
+
const embedding = data.data?.[0]?.embedding
|
|
324
|
+
if (!embedding) throw new Error('未返回向量: ' + JSON.stringify(data).slice(0, 200))
|
|
325
|
+
console.log(`✅ Embedding 成功!维度: ${embedding.length}`)
|
|
326
|
+
if (output) {
|
|
327
|
+
fs.writeFileSync(output, JSON.stringify(embedding))
|
|
328
|
+
console.log(`已保存到 ${output}`)
|
|
329
|
+
} else {
|
|
330
|
+
console.log('前5维:', embedding.slice(0, 5))
|
|
331
|
+
}
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
throw new Error(`不支持的类型: ${type},可选: chat | image | tts | stt | music | ocr | video | embedding`)
|
|
269
336
|
}
|
|
270
337
|
|
|
271
338
|
module.exports = { pilot }
|