d4bf3627fd
新增运动节拍RepClock全套小程序页面、后端API与数据库服务,新增subhub子工具汇总页面,优化全局主页样式与配置,为web静态资源添加版本缓存参数,补充配套调试脚本
126 lines
5.3 KiB
JavaScript
126 lines
5.3 KiB
JavaScript
const fs = require('fs')
|
||
const path = require('path')
|
||
const envPath = 'C:/Users/Administrator/Toolbox_local_creds.env.local'
|
||
if (fs.existsSync(envPath)) {
|
||
const txt = fs.readFileSync(envPath, 'utf-8')
|
||
txt.split(/\r?\n/).forEach(line => {
|
||
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)$/i)
|
||
if (!m) return
|
||
let v = m[2].trim()
|
||
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1)
|
||
if (!(m[1] in process.env)) process.env[m[1]] = v
|
||
})
|
||
}
|
||
process.chdir('d:/Trae_Files/TRAE-Toolbox')
|
||
|
||
global.__builtin_fetch = globalThis.fetch
|
||
const API_KEY = process.env.DASHSCOPE_API_KEY
|
||
|
||
const { getDb } = require(path.join(process.cwd(), 'src/server/mp_rep_clock/db'))
|
||
const tts = require(path.join(process.cwd(), 'src/server/mp_rep_clock/tts.js'))
|
||
|
||
console.log('=== 0. 自检 global/环境 ===')
|
||
console.log(' global.__builtin_fetch === globalThis.fetch:', global.__builtin_fetch === globalThis.fetch)
|
||
console.log(' typeof global.__builtin_fetch:', typeof global.__builtin_fetch)
|
||
console.log(' process.cwd():', process.cwd())
|
||
console.log(' TTS_ROOT:', tts.TTS_ROOT)
|
||
console.log(' TTS_ROOT exists:', fs.existsSync(tts.TTS_ROOT))
|
||
console.log(' apiKey.len:', API_KEY.length)
|
||
|
||
;(async () => {})()
|
||
|
||
async function main() {
|
||
console.log('\n=== 0.5 INLINE callCosyVoice 对比(与 debug_tts_inner.js 相同) ===')
|
||
const crypto = require('crypto')
|
||
const TTS_ROOT = tts.TTS_ROOT
|
||
const callCosyVoiceInline = async (text, voice) => {
|
||
const apiKey = process.env.DASHSCOPE_API_KEY || ''
|
||
const t = String(text || '').trim()
|
||
const isMale = voice.indexOf('male') >= 0
|
||
const headers = { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }
|
||
const fallbacks = [
|
||
{
|
||
name: 'Inline-A',
|
||
url: 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation',
|
||
body: { model: 'qwen3-tts-flash', input: { text: t, voice: 'Cherry', language_type: 'Chinese' } },
|
||
},
|
||
]
|
||
for (const fb of fallbacks) {
|
||
try {
|
||
const resp = await global.__builtin_fetch(fb.url, {
|
||
method: 'POST', headers, body: JSON.stringify(fb.body),
|
||
})
|
||
console.log(' inline fb', fb.name, 'status=', resp && resp.status)
|
||
if (!resp || !resp.ok) continue
|
||
const j = await resp.json()
|
||
const output = (j && j.output) || null
|
||
const audioUrl = output && output.audio && output.audio.url || ''
|
||
console.log(' inline fb', fb.name, 'audioUrl=', audioUrl.slice(0, 80))
|
||
if (!audioUrl) continue
|
||
const download = await global.__builtin_fetch(audioUrl)
|
||
if (!download || !download.ok) continue
|
||
const buf = Buffer.from(await download.arrayBuffer())
|
||
const storedName = `inline_${Date.now()}_${crypto.randomBytes(4).toString('hex')}.mp3`
|
||
const absPath = path.join(TTS_ROOT, storedName)
|
||
fs.writeFileSync(absPath, buf)
|
||
const durationMs = Math.max(1000, Math.round(buf.length / (12 * 1024 / 8)))
|
||
return { ok: true, url: `/uploads/mp_rep_clock/tts_cache/${storedName}`, durationMs }
|
||
} catch (e) { console.log(' inline ex', e.message) }
|
||
}
|
||
return { ok: false }
|
||
}
|
||
const inlineR = await callCosyVoiceInline('热身开合跳', 'female_01')
|
||
console.log(' inline result ok=', inlineR.ok, 'url=', inlineR.url)
|
||
|
||
console.log('\n=== 1. 检查 DASHSCOPE_API_KEY ===')
|
||
console.log(' len=', String(process.env.DASHSCOPE_API_KEY || '').length)
|
||
console.log()
|
||
|
||
console.log('=== 2. 先跑单条 synthesize 验证 Fallback ===')
|
||
const single = await tts.synthesize('开始训练,测试一下', 'female_01')
|
||
console.log(' single=', JSON.stringify(single, null, 2))
|
||
console.log()
|
||
|
||
console.log('=== 3. 全量 synthesizeBatch(title=测试一下) ===')
|
||
const card = {
|
||
title: '测试一下',
|
||
loopMode: 'sequential_once',
|
||
loopCount: 1,
|
||
announceLeadSeconds: '5,3',
|
||
steps: [
|
||
{ name: '热身开合跳', durationSec: 30, type: 'action' },
|
||
{ name: '平板支撑', durationSec: 60, type: 'action', restDurationSec: 15, voiceText: '' },
|
||
],
|
||
}
|
||
const batch = await tts.synthesizeBatch(card, 'female_01')
|
||
console.log(' batch total=', batch.total, 'success=', batch.success)
|
||
batch.results.forEach((r, i) => {
|
||
console.log(` [${i}] ok=${r.ok} cached=${r.cached} text=${JSON.stringify(r.text)} url=${r.url || ''} err=${r.error || ''}`)
|
||
})
|
||
console.log()
|
||
|
||
console.log('=== 4. TTS_ROOT uploads/mp_rep_clock/tts_cache files.Count ===')
|
||
const root = tts.TTS_ROOT
|
||
const files = fs.existsSync(root) ? fs.readdirSync(root).filter(f => f.endsWith('.mp3')) : []
|
||
console.log(' root=', root)
|
||
console.log(' files.Count=', files.length)
|
||
files.slice(-12).forEach(f => {
|
||
const stat = fs.statSync(path.join(root, f))
|
||
console.log(' -', f, stat.size, 'bytes')
|
||
})
|
||
console.log()
|
||
|
||
console.log('=== 5. rc_tts_cache 表行数(非 deleted)===')
|
||
try {
|
||
const row = getDb().prepare(`SELECT COUNT(*) as c FROM rc_tts_cache WHERE deleted = 0`).get()
|
||
console.log(' count=', row && row.c)
|
||
} catch (e) { console.log(' err=', e.message) }
|
||
console.log()
|
||
|
||
console.log('=== 6. 全部播报 lines 生成 ===')
|
||
const lines = tts.buildCardTTSBatch(card)
|
||
console.log(' lines=', lines.length)
|
||
lines.forEach((l, i) => console.log(` [${i}]`, l))
|
||
}
|
||
main().catch(e => console.error('FATAL', e))
|