skillfree 0.1.3 โ 0.1.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/package.json +1 -1
- package/scripts/commands/pilot.js +312 -74
- package/skillfree-0.1.4.tgz +0 -0
package/package.json
CHANGED
|
@@ -1,100 +1,338 @@
|
|
|
1
|
-
const { post, postStream, BASE_URL } = require('../lib/client')
|
|
1
|
+
const { post, postStream, get, request, getApiKey, BASE_URL } = require('../lib/client')
|
|
2
2
|
const fs = require('fs')
|
|
3
3
|
const path = require('path')
|
|
4
4
|
|
|
5
|
+
// โโโ ๅทฅๅ
ท๏ผไธ่ฝฝๆไปถๅนถไฟๅญ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
6
|
+
async function downloadAndSave(url, output) {
|
|
7
|
+
const resp = await fetch(url)
|
|
8
|
+
if (!resp.ok) throw new Error(`ไธ่ฝฝๅคฑ่ดฅ: ${resp.status}`)
|
|
9
|
+
fs.writeFileSync(output, Buffer.from(await resp.arrayBuffer()))
|
|
10
|
+
console.log(`โ
ๅทฒไฟๅญๅฐ ${output}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// โโโ ๅทฅๅ
ท๏ผๅฐ่ฃ
PCM ไธบ WAV โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
14
|
+
function pcmToWav(pcmBytes, sampleRate = 24000, channels = 1, bitsPerSample = 16) {
|
|
15
|
+
const dataSize = pcmBytes.length
|
|
16
|
+
const wav = Buffer.alloc(44 + dataSize)
|
|
17
|
+
wav.write('RIFF', 0); wav.writeUInt32LE(36 + dataSize, 4); wav.write('WAVE', 8)
|
|
18
|
+
wav.write('fmt ', 12); wav.writeUInt32LE(16, 16); wav.writeUInt16LE(1, 20)
|
|
19
|
+
wav.writeUInt16LE(channels, 22); wav.writeUInt32LE(sampleRate, 24)
|
|
20
|
+
wav.writeUInt32LE(sampleRate * channels * bitsPerSample / 8, 28)
|
|
21
|
+
wav.writeUInt16LE(channels * bitsPerSample / 8, 32); wav.writeUInt16LE(bitsPerSample, 34)
|
|
22
|
+
wav.write('data', 36); wav.writeUInt32LE(dataSize, 40)
|
|
23
|
+
pcmBytes.copy(wav, 44)
|
|
24
|
+
return wav
|
|
25
|
+
}
|
|
26
|
+
|
|
5
27
|
async function pilot(flags) {
|
|
6
28
|
const type = flags.type || 'chat'
|
|
7
29
|
const prompt = flags.prompt || flags.text || ''
|
|
8
30
|
const output = flags.output || null
|
|
31
|
+
const model = flags.model || null
|
|
9
32
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
// โโ CHAT โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
34
|
+
if (type === 'chat') {
|
|
35
|
+
if (!output) {
|
|
36
|
+
// ๆตๅผ่พๅบ
|
|
37
|
+
const res = await postStream('/chat/completions', {
|
|
38
|
+
model: model || 'DeepSeek-V3.2-Fast',
|
|
39
|
+
messages: [{ role: 'user', content: prompt }],
|
|
40
|
+
stream: true,
|
|
41
|
+
})
|
|
42
|
+
const reader = res.body.getReader()
|
|
43
|
+
const decoder = new TextDecoder()
|
|
44
|
+
let buf = ''
|
|
45
|
+
process.stdout.write('\n')
|
|
46
|
+
while (true) {
|
|
47
|
+
const { done, value } = await reader.read()
|
|
48
|
+
if (done) break
|
|
49
|
+
buf += decoder.decode(value, { stream: true })
|
|
50
|
+
const lines = buf.split('\n')
|
|
51
|
+
buf = lines.pop()
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (line.startsWith('data: ')) {
|
|
54
|
+
const chunk = line.slice(6)
|
|
55
|
+
if (chunk === '[DONE]') { process.stdout.write('\n'); return }
|
|
56
|
+
try {
|
|
57
|
+
const d = JSON.parse(chunk)
|
|
58
|
+
const text = d.choices?.[0]?.delta?.content
|
|
59
|
+
if (text) process.stdout.write(text)
|
|
60
|
+
} catch {}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
33
63
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
default:
|
|
45
|
-
body.inputs.prompt = prompt
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
const result = await post('/chat/completions', {
|
|
67
|
+
model: model || 'DeepSeek-V3.2-Fast',
|
|
68
|
+
messages: [{ role: 'user', content: prompt }],
|
|
69
|
+
})
|
|
70
|
+
const text = result.choices?.[0]?.message?.content || JSON.stringify(result, null, 2)
|
|
71
|
+
if (output) { fs.writeFileSync(output, text); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}`) }
|
|
72
|
+
else console.log(text)
|
|
73
|
+
return
|
|
46
74
|
}
|
|
47
75
|
|
|
48
|
-
//
|
|
49
|
-
if (type === '
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
// โโ IMAGE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
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 / ๅ
ถไปๆ ๅๅพๅๆจกๅ
|
|
100
|
+
const res = await post('/images/generations', {
|
|
101
|
+
model: imageModel,
|
|
102
|
+
prompt,
|
|
103
|
+
n: 1,
|
|
104
|
+
size: flags.size || '1024x1024',
|
|
54
105
|
})
|
|
106
|
+
if (res.error) throw new Error(res.error.message || JSON.stringify(res.error))
|
|
107
|
+
const url = res.data?.[0]?.url || res.data?.[0]?.b64_json
|
|
108
|
+
if (!url) throw new Error('ๆช่ฟๅๅพๅๆฐๆฎ: ' + JSON.stringify(res).slice(0, 200))
|
|
109
|
+
if (output) {
|
|
110
|
+
if (url.startsWith('http')) await downloadAndSave(url, output)
|
|
111
|
+
else { fs.writeFileSync(output, Buffer.from(url, 'base64')); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}`) }
|
|
112
|
+
} else {
|
|
113
|
+
console.log('ๅพๅ URL:', url)
|
|
114
|
+
}
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// โโ TTS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
119
|
+
if (type === 'tts') {
|
|
120
|
+
const ttsModel = model || 'speech-2.6-hd'
|
|
121
|
+
const text = prompt
|
|
122
|
+
|
|
123
|
+
if (ttsModel === 'speech-2.8-hd' || ttsModel === 'minimax-clone-lastversion') {
|
|
124
|
+
// ่ตฐ /v1/responses๏ผ่ฟๅ hex ้ณ้ข
|
|
125
|
+
const res = await request('/responses', {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
body: JSON.stringify({
|
|
128
|
+
model: ttsModel,
|
|
129
|
+
input: text,
|
|
130
|
+
stream: false,
|
|
131
|
+
voice_setting: {
|
|
132
|
+
voice_id: flags.voice || 'female-shaonv',
|
|
133
|
+
speed: 1, vol: 1, pitch: 0, emotion: 'fluent',
|
|
134
|
+
},
|
|
135
|
+
audio_setting: { sample_rate: 32000, bitrate: 128000, format: 'mp3', channel: 1 },
|
|
136
|
+
output_format: 'hex',
|
|
137
|
+
}),
|
|
138
|
+
})
|
|
139
|
+
const data = await res.json()
|
|
140
|
+
if (!data.data?.audio) throw new Error(JSON.stringify(data).slice(0, 200))
|
|
141
|
+
const audioBuf = Buffer.from(data.data.audio, 'hex')
|
|
142
|
+
if (output) { fs.writeFileSync(output, audioBuf); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}๏ผ${audioBuf.length} bytes๏ผ`) }
|
|
143
|
+
else console.log(`โ
TTS ๆๅ๏ผๆถ้ฟ็บฆ ${(data.extra_info?.audio_length / 1000).toFixed(1)} ็ง`)
|
|
55
144
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
145
|
+
} else if (ttsModel === 'gemini-2.5-pro-preview-tts' || ttsModel === 'gemini-2.5-flash-preview-tts') {
|
|
146
|
+
// Gemini TTS๏ผ่ตฐ /v1beta/models/:id:generateContent๏ผ่ฎค่ฏๆ Bearer
|
|
147
|
+
const apiKey = getApiKey()
|
|
148
|
+
const res = await fetch(BASE_URL.replace('skillfree.tech', 'dmxapi.cn') + '/v1beta/models/' + ttsModel + ':generateContent', {
|
|
149
|
+
method: 'POST',
|
|
150
|
+
headers: { 'Authorization': apiKey, 'Content-Type': 'application/json' },
|
|
151
|
+
body: JSON.stringify({
|
|
152
|
+
contents: [{ parts: [{ text }] }],
|
|
153
|
+
generationConfig: {
|
|
154
|
+
responseModalities: ['AUDIO'],
|
|
155
|
+
speechConfig: {
|
|
156
|
+
voiceConfig: { prebuiltVoiceConfig: { voiceName: flags.voice || 'Kore' } }
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}),
|
|
160
|
+
})
|
|
161
|
+
const data = await res.json()
|
|
162
|
+
if (data.error) throw new Error(data.error.message || JSON.stringify(data.error))
|
|
163
|
+
const pcm = Buffer.from(data.candidates[0].content.parts[0].inlineData.data, 'base64')
|
|
164
|
+
const ext = (output || '').endsWith('.mp3') ? 'mp3' : 'wav'
|
|
165
|
+
const finalBuf = ext === 'wav' ? pcmToWav(pcm) : pcm
|
|
166
|
+
if (output) { fs.writeFileSync(output, finalBuf); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}๏ผ${finalBuf.length} bytes๏ผ`) }
|
|
167
|
+
else console.log(`โ
Gemini TTS ๆๅ๏ผๆถ้ฟ็บฆ ${(pcm.length / (24000 * 2)).toFixed(1)} ็ง`)
|
|
168
|
+
|
|
169
|
+
} else {
|
|
170
|
+
// ๆ ๅ OpenAI ๅ
ผๅฎน๏ผspeech-2.6-hd ็ญ๏ผ
|
|
171
|
+
const res = await request('/audio/speech', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
body: JSON.stringify({
|
|
174
|
+
model: ttsModel,
|
|
175
|
+
input: text,
|
|
176
|
+
voice: flags.voice || 'female-shaonv',
|
|
177
|
+
}),
|
|
178
|
+
})
|
|
179
|
+
if (res.status !== 200) {
|
|
180
|
+
const err = await res.json()
|
|
181
|
+
throw new Error(err.error?.message || JSON.stringify(err))
|
|
182
|
+
}
|
|
183
|
+
const buf = Buffer.from(await res.arrayBuffer())
|
|
184
|
+
if (output) { fs.writeFileSync(output, buf); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}๏ผ${buf.length} bytes๏ผ`) }
|
|
185
|
+
else console.log(`โ
TTS ๆๅ๏ผ${buf.length} bytes`)
|
|
186
|
+
}
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// โโ MUSIC โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
191
|
+
if (type === 'music') {
|
|
192
|
+
const musicModel = model || 'chirp-v5'
|
|
193
|
+
|
|
194
|
+
if (musicModel === 'chirp-v5') {
|
|
195
|
+
// Suno ๅผๆญฅๆฅๅฃ
|
|
196
|
+
const res = await request('/suno/submit/music', {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: { 'Accept': 'application/json' },
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
gpt_description_prompt: prompt,
|
|
201
|
+
make_instrumental: true,
|
|
202
|
+
mv: 'chirp-v5',
|
|
203
|
+
notify_hook: '',
|
|
204
|
+
}),
|
|
205
|
+
})
|
|
206
|
+
const submitData = await res.json()
|
|
207
|
+
if (submitData.code !== 'success') throw new Error(submitData.message || JSON.stringify(submitData))
|
|
208
|
+
const taskId = submitData.data
|
|
209
|
+
console.log(`๐ต Suno ไปปๅกๅทฒๆไบค๏ผtask_id: ${taskId}๏ผ็ญๅพ
็ๆ๏ผ็บฆ 60-90 ็ง๏ผ...`)
|
|
210
|
+
|
|
211
|
+
// ่ฝฎ่ฏข็ปๆ
|
|
212
|
+
for (let i = 0; i < 15; i++) {
|
|
213
|
+
await new Promise(r => setTimeout(r, 10000))
|
|
214
|
+
const poll = await request('/suno/fetch/' + taskId, { method: 'GET' })
|
|
215
|
+
const result = await poll.json()
|
|
216
|
+
if (result.code !== 'success') throw new Error(result.message || JSON.stringify(result))
|
|
217
|
+
const status = result.data?.status
|
|
218
|
+
const progress = result.data?.progress || '0%'
|
|
219
|
+
process.stdout.write(`\r็ถๆ: ${status} ่ฟๅบฆ: ${progress} `)
|
|
220
|
+
if (status === 'SUCCESS') {
|
|
221
|
+
const songs = result.data?.data || []
|
|
222
|
+
process.stdout.write('\n')
|
|
223
|
+
console.log(`โ
็ๆๆๅ๏ผๅ
ฑ ${songs.length} ้ฆ`)
|
|
224
|
+
songs.forEach((s, i) => {
|
|
225
|
+
console.log(` ๆญๆฒ${i+1}: ${s.title} (${Math.floor(s.duration/60)}m${Math.floor(s.duration%60)}s)`)
|
|
226
|
+
console.log(` ้ณ้ข: ${s.audio_url}`)
|
|
227
|
+
})
|
|
228
|
+
// ๅฆๆๆๅฎ output๏ผไธ่ฝฝ็ฌฌไธ้ฆ
|
|
229
|
+
if (output && songs[0]?.audio_url) await downloadAndSave(songs[0].audio_url, output)
|
|
230
|
+
return
|
|
75
231
|
}
|
|
232
|
+
if (status === 'FAILED') throw new Error('Suno ไปปๅกๅคฑ่ดฅ: ' + JSON.stringify(result.data))
|
|
76
233
|
}
|
|
234
|
+
throw new Error('Suno ็ๆ่ถ
ๆถ๏ผ150s๏ผ๏ผ่ฏทๆๅจๆฅ่ฏข task_id: ' + taskId)
|
|
235
|
+
|
|
236
|
+
} else {
|
|
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)
|
|
77
257
|
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// โโ OCR โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
261
|
+
if (type === 'ocr') {
|
|
262
|
+
let input = prompt
|
|
263
|
+
// ๅฆๆๆฏๆฌๅฐๆไปถ่ทฏๅพ๏ผ่ฏปๅไธบ base64
|
|
264
|
+
if (flags.file && fs.existsSync(path.resolve(flags.file))) {
|
|
265
|
+
input = fs.readFileSync(path.resolve(flags.file)).toString('base64')
|
|
266
|
+
}
|
|
267
|
+
const res = await request('/responses', {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
model: model || 'hehe-tywd',
|
|
271
|
+
input,
|
|
272
|
+
parse_mode: 'auto',
|
|
273
|
+
dpi: 144,
|
|
274
|
+
page_start: 0,
|
|
275
|
+
page_count: 1000,
|
|
276
|
+
markdown_details: 1,
|
|
277
|
+
page_details: 0,
|
|
278
|
+
table_flavor: 'html',
|
|
279
|
+
}),
|
|
280
|
+
})
|
|
281
|
+
const data = await res.json()
|
|
282
|
+
if (data.code !== 200) throw new Error(data.message || JSON.stringify(data).slice(0, 200))
|
|
283
|
+
const markdown = data.result?.markdown || ''
|
|
284
|
+
if (output) { fs.writeFileSync(output, markdown); console.log(`โ
OCR ็ปๆๅทฒไฟๅญๅฐ ${output}`) }
|
|
285
|
+
else console.log(markdown)
|
|
78
286
|
return
|
|
79
287
|
}
|
|
80
288
|
|
|
81
|
-
//
|
|
82
|
-
|
|
289
|
+
// โโ STT โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
290
|
+
if (type === 'stt') {
|
|
291
|
+
if (!flags.file) throw new Error('--file ๆฏๅฟ
้็๏ผ้ณ้ขๆไปถ่ทฏๅพ๏ผ')
|
|
292
|
+
const audioBase64 = fs.readFileSync(path.resolve(flags.file)).toString('base64')
|
|
293
|
+
const result = await post('/v1/audio/transcriptions', {
|
|
294
|
+
model: 'whisper-1',
|
|
295
|
+
file: audioBase64,
|
|
296
|
+
filename: path.basename(flags.file),
|
|
297
|
+
})
|
|
298
|
+
const text = result.text || JSON.stringify(result, null, 2)
|
|
299
|
+
if (output) { fs.writeFileSync(output, text); console.log(`โ
ๅทฒไฟๅญๅฐ ${output}`) }
|
|
300
|
+
else console.log(text)
|
|
301
|
+
return
|
|
302
|
+
}
|
|
83
303
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
}
|
|
91
332
|
return
|
|
92
333
|
}
|
|
93
334
|
|
|
94
|
-
|
|
95
|
-
const text = result.choices?.[0]?.message?.content
|
|
96
|
-
|| result.text || result.transcript || JSON.stringify(result, null, 2)
|
|
97
|
-
console.log(text)
|
|
335
|
+
throw new Error(`ไธๆฏๆ็็ฑปๅ: ${type}๏ผๅฏ้: chat | image | tts | stt | music | ocr | video | embedding`)
|
|
98
336
|
}
|
|
99
337
|
|
|
100
338
|
module.exports = { pilot }
|
|
Binary file
|