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))