| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- #!/usr/bin/env node
- /**
- * 验证培训包中的语音克隆能力
- * 检查项:
- * 1. 语音服务模块是否可加载
- * 2. ffmpeg/wx-voice 依赖是否可用
- * 3. Fmode 后端连通性
- */
- const path = require('path');
- const fs = require('fs');
- const TRAINING_EXE = path.join(__dirname, '../dist/qiwei-training/qiwei-workbench.exe');
- const VOICE_CHECK_MARKERS = [
- 'VoiceCloneService',
- 'indextts2', // Fmode 后端接口路径
- 'ffmpeg',
- 'wx-voice',
- 'SILK',
- ];
- async function checkExeExists() {
- if (!fs.existsSync(TRAINING_EXE)) {
- console.error(`❌ 培训包 exe 不存在: ${TRAINING_EXE}`);
- console.error(' 请先运行: node scripts/build-training-package.mjs');
- process.exit(1);
- }
- const sizeMB = (fs.statSync(TRAINING_EXE).size / (1024 * 1024)).toFixed(1);
- console.log(`✅ 培训包 exe 已存在: ${sizeMB} MB`);
- }
- async function checkVoiceModuleInSource() {
- const voiceServicePath = path.join(__dirname, '../mcp/src/core/voice-clone-service.js');
- if (!fs.existsSync(voiceServicePath)) {
- console.error('❌ 源码中缺少 voice-clone-service.js');
- process.exit(1);
- }
- const content = fs.readFileSync(voiceServicePath, 'utf8');
- const missing = VOICE_CHECK_MARKERS.filter(marker => !content.includes(marker));
- if (missing.length > 0) {
- console.error(`❌ 语音服务模块缺少关键组件: ${missing.join(', ')}`);
- process.exit(1);
- }
- console.log('✅ 源码语音服务模块完整');
- }
- async function checkVoiceDependencies() {
- const packageJson = require('../package.json');
- const requiredDeps = [
- '@ffmpeg-installer/ffmpeg',
- '@ffprobe-installer/ffprobe',
- '@binsee/wx-voice',
- ];
- const missing = requiredDeps.filter(dep =>
- !packageJson.dependencies[dep] && !packageJson.optionalDependencies[dep]
- );
- if (missing.length > 0) {
- console.error(`❌ package.json 缺少语音依赖: ${missing.join(', ')}`);
- process.exit(1);
- }
- console.log('✅ package.json 语音依赖已声明');
- }
- async function checkFmodeBackendEndpoint() {
- const voiceServicePath = path.join(__dirname, '../mcp/src/core/voice-clone-service.js');
- const content = fs.readFileSync(voiceServicePath, 'utf8');
- const endpoints = [
- 'https://server.fmode.cn/api/voice/indextts2',
- 'http://127.0.0.1:7338/api/voice/indextts2',
- ];
- const hasEndpoint = endpoints.some(ep => content.includes(ep));
- if (!hasEndpoint) {
- console.error('❌ 语音服务未配置 Fmode 后端地址');
- process.exit(1);
- }
- console.log('✅ Fmode 语音后端地址已配置');
- }
- async function checkREADMEVoiceSection() {
- const readme = path.join(__dirname, '../dist/qiwei-training/README.md');
- if (!fs.existsSync(readme)) {
- console.error('❌ 培训包 README.md 不存在');
- process.exit(1);
- }
- const content = fs.readFileSync(readme, 'utf8');
- if (!content.includes('## 语音克隆功能')) {
- console.error('❌ README.md 缺少语音克隆说明');
- process.exit(1);
- }
- console.log('✅ README.md 包含语音克隆文档');
- }
- async function main() {
- console.log('开始验证培训包语音能力...\n');
- await checkExeExists();
- await checkVoiceModuleInSource();
- await checkVoiceDependencies();
- await checkFmodeBackendEndpoint();
- await checkREADMEVoiceSection();
- console.log('\n✅ 所有检查通过!培训包已包含完整语音克隆能力。');
- console.log('\n下一步测试:');
- console.log(' 1. 拷贝 dist/qiwei-training/ 到测试机');
- console.log(' 2. 配置 .env.local 中的 QIWEI_AUTH_TOKEN');
- console.log(' 3. 运行 qiwei-workbench.exe');
- console.log(' 4. 在工作台中录制参考音频并测试合成');
- }
- main().catch(err => {
- console.error('验证失败:', err.message);
- process.exit(1);
- });
|