dsh-line-bot 0.10.2 → 0.10.4
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/CHANGELOG.md +10 -0
- package/lib/host.mjs +2 -2
- package/lib/tts.mjs +39 -15
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 0.10.4
|
|
2
|
+
|
|
3
|
+
- Windows 語音引擎:優先選擇含 `openblas.dll` 的完整 CrispASR bundle,忽略舊安裝留下的裸 `crispasr.exe`(避免 `STATUS_DLL_NOT_FOUND`)。
|
|
4
|
+
- `--version` 驗證改在執行檔所在資料夾執行,確保 DLL 可被找到;失敗訊息保留實際 stderr。
|
|
5
|
+
|
|
6
|
+
## 0.10.3
|
|
7
|
+
|
|
8
|
+
- 面板「重新偵測」不再同步匯入 MLX 套件(原本可能卡住 8–30 秒),偵測一律走快取與檔案檢查。
|
|
9
|
+
- 語音狀態與參考音長度改為快取,`/api/line-bot/status` 不會被語音偵測拖慢。
|
|
10
|
+
|
|
1
11
|
## 0.10.2
|
|
2
12
|
|
|
3
13
|
- 修正 Windows 一鍵配置語音環境:改為直接使用解壓後的 `crispasr.exe`(與 `openblas.dll` 同資料夾),不再只複製 exe 導致缺少 DLL、`--version` 失敗。
|
package/lib/host.mjs
CHANGED
|
@@ -51,7 +51,7 @@ const { createVision } = visionMod
|
|
|
51
51
|
const { createTts } = ttsMod
|
|
52
52
|
const { chunkText, clip, inQuietWindow, jsonFail, jsonOk, maskSecret, readJsonBody, safeArray, sleep, readJsonSafe } = utilMod
|
|
53
53
|
|
|
54
|
-
export const VERSION = '0.10.
|
|
54
|
+
export const VERSION = '0.10.4'
|
|
55
55
|
|
|
56
56
|
// 環境變數提供的 Cloudflare API Token(方便用 shell 注入、不用把 token 寫進設定檔)。
|
|
57
57
|
// 設定檔裡的 token 優先;兩者都沒有時才用環境變數。
|
|
@@ -2801,7 +2801,7 @@ export async function create({ ctx, config: pluginConfig, logger: upstream }) {
|
|
|
2801
2801
|
return { messages: built.messages, parsed: built.parsed }
|
|
2802
2802
|
}
|
|
2803
2803
|
case 'voice-detect':
|
|
2804
|
-
return tts.detect({ force: true
|
|
2804
|
+
return tts.detect({ force: true })
|
|
2805
2805
|
case 'voice-install': {
|
|
2806
2806
|
if (tts.status().installing) return { started: false, already: true }
|
|
2807
2807
|
tts.install()
|
package/lib/tts.mjs
CHANGED
|
@@ -212,6 +212,18 @@ export function createTts({ dir, logger, getConfig }) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
function hasWindowsRuntime(exe) {
|
|
216
|
+
if (!isWin()) return true
|
|
217
|
+
try {
|
|
218
|
+
const names = fs.readdirSync(path.dirname(exe)).map((item) => String(item).toLowerCase())
|
|
219
|
+
// Windows CPU 版 CrispASR 需要同資料夾的 openblas.dll。舊安裝可能留下
|
|
220
|
+
// 只有 exe 的裸副本,不能只憑「檔案存在」就選它。
|
|
221
|
+
return names.includes('openblas.dll')
|
|
222
|
+
} catch {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
215
227
|
function findCrispExe(dir, depth = 3) {
|
|
216
228
|
if (depth < 0) return ''
|
|
217
229
|
let entries = []
|
|
@@ -220,19 +232,38 @@ export function createTts({ dir, logger, getConfig }) {
|
|
|
220
232
|
} catch {
|
|
221
233
|
return ''
|
|
222
234
|
}
|
|
235
|
+
const candidates = []
|
|
223
236
|
for (const entry of entries) {
|
|
224
|
-
if (entry.isFile() && /^crispasr\.exe$/i.test(entry.name))
|
|
237
|
+
if (entry.isFile() && /^crispasr\.exe$/i.test(entry.name)) candidates.push(path.join(dir, entry.name))
|
|
225
238
|
}
|
|
226
239
|
for (const entry of entries) {
|
|
227
240
|
if (!entry.isDirectory()) continue
|
|
228
241
|
const hit = findCrispExe(path.join(dir, entry.name), depth - 1)
|
|
229
|
-
if (hit)
|
|
242
|
+
if (hit) candidates.push(hit)
|
|
243
|
+
}
|
|
244
|
+
// 優先完整 bundle;舊的裸 exe 即使存在也不選。
|
|
245
|
+
return candidates.find((item) => hasWindowsRuntime(item)) || candidates[0] || ''
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function crispVersion(exe) {
|
|
249
|
+
try {
|
|
250
|
+
const output = execFileSync(exe, ['--version'], {
|
|
251
|
+
encoding: 'utf8',
|
|
252
|
+
timeout: 15000,
|
|
253
|
+
cwd: path.dirname(exe),
|
|
254
|
+
})
|
|
255
|
+
return { ok: true, output: String(output || '') }
|
|
256
|
+
} catch (error) {
|
|
257
|
+
return {
|
|
258
|
+
ok: false,
|
|
259
|
+
error: String(error?.stderr || error?.message || error).slice(0, 500),
|
|
260
|
+
}
|
|
230
261
|
}
|
|
231
|
-
return ''
|
|
232
262
|
}
|
|
233
263
|
|
|
234
264
|
function ggufBinary() {
|
|
235
|
-
|
|
265
|
+
// 忽略舊 Windows 安裝留下的裸 exe:它存在但載不到同 bundle 的 DLL。
|
|
266
|
+
if (state.ggufBinary && fileExists(state.ggufBinary) && hasWindowsRuntime(state.ggufBinary)) return state.ggufBinary
|
|
236
267
|
if (isWin()) {
|
|
237
268
|
const found = findCrispExe(paths.winDir)
|
|
238
269
|
if (found) return found
|
|
@@ -245,12 +276,7 @@ export function createTts({ dir, logger, getConfig }) {
|
|
|
245
276
|
const bin = ggufBinary()
|
|
246
277
|
if (!bin) return false
|
|
247
278
|
if (!validate) return true
|
|
248
|
-
|
|
249
|
-
execFileSync(bin, ['--version'], { stdio: 'ignore', timeout: 8000 })
|
|
250
|
-
return true
|
|
251
|
-
} catch {
|
|
252
|
-
return false
|
|
253
|
-
}
|
|
279
|
+
return crispVersion(bin).ok
|
|
254
280
|
}
|
|
255
281
|
|
|
256
282
|
function detect({ force = false, validate = false } = {}) {
|
|
@@ -418,11 +444,9 @@ export function createTts({ dir, logger, getConfig }) {
|
|
|
418
444
|
await run('powershell', ['-NoProfile', '-Command', `Expand-Archive -LiteralPath ${JSON.stringify(zip)} -DestinationPath ${JSON.stringify(paths.winDir)} -Force`], { timeout: 300000 })
|
|
419
445
|
const exe = findCrispExe(paths.winDir)
|
|
420
446
|
if (!exe) throw new Error('解壓縮後找不到 crispasr.exe')
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const detail = String(error?.stderr || error?.message || error).slice(0, 300)
|
|
425
|
-
throw new Error(`crispasr.exe 無法執行(可能是缺少 DLL):${detail}`)
|
|
447
|
+
const version = crispVersion(exe)
|
|
448
|
+
if (!version.ok) {
|
|
449
|
+
throw new Error(`crispasr.exe 無法執行(可能是缺少 DLL):${version.error}`)
|
|
426
450
|
}
|
|
427
451
|
state.ggufBinary = exe
|
|
428
452
|
return 'gguf'
|