/** * Impress ASR Input - 主入口 * 命令行模式入口文件 */ import { Command } from 'commander'; import { SpeechRecognizer, RecognitionResult } from './core/speech-recognizer.js'; import { TextOutput } from './core/text-output.js'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const packageJson = JSON.parse( readFileSync(join(__dirname, '../package.json'), 'utf-8') ); const program = new Command(); program .name('impress-asr-input') .description('基于 ONNX 的本地语音识别输入工具') .version(packageJson.version); program .command('start') .description('开始语音识别') .option('-l, --language ', '识别语言', 'zh') .option('-m, --model ', '模型文件路径(可选,无模型时以配置模式启动)') .option('-o, --output ', '输出模式:clipboard|keyboard|both', 'clipboard') .action(async (options) => { console.log('🎤 Impress ASR Input'); console.log(` 版本:${packageJson.version}`); console.log(` 语言:${options.language}`); console.log(` 输出:${options.output}`); // 检查模型文件是否存在 const { existsSync } = await import('fs'); const modelPath = options.model || join(__dirname, '../models/model.onnx'); if (!existsSync(modelPath)) { console.log('\n⚠️ 未检测到模型文件,以配置模式启动'); console.log('\n📥 模型下载指引:'); console.log(' 1. SenseVoice (推荐): https://huggingface.co/FunAudioLLM/SenseVoice'); console.log(' 2. Whisper: https://huggingface.co/onnx-community/whisper-base'); console.log(' 3. Paraformer: https://www.modelscope.cn/models/damo/speech_paraformer-large-vad-punct'); console.log('\n📁 将下载的模型文件放入以下目录之一:'); console.log(' - ./models/sensevoice.onnx'); console.log(' - ./models/whisper.onnx'); console.log(' - ./models/paraformer.onnx'); console.log('\n💡 或使用 --model 参数指定模型路径'); console.log(' 示例:npm start -- start -m /path/to/your/model.onnx'); return; } console.log(` 模型:${modelPath}`); const recognizer = new SpeechRecognizer({ modelPath, language: options.language, useVad: true, beamSize: 5, }); const textOutput = new TextOutput({ outputMode: options.output as 'clipboard' | 'keyboard' | 'both', autoPaste: true, delayMs: 50, }); // 绑定事件 recognizer.on('ready', () => { console.log('✅ 模型加载完成,开始识别...'); recognizer.start(); }); recognizer.on('result', (result: RecognitionResult) => { console.log(`📝 ${result.text}`); textOutput.output(result); }); recognizer.on('error', (error: Error) => { console.error('❌ 识别错误:', error.message); process.exit(1); }); // 初始化并开始 try { await recognizer.initialize(); // 注意:音频采集在纯 Node.js 环境需要额外处理 // 这里仅作为框架演示 console.log('⚠️ 当前为演示模式,完整功能需要 Electron 环境'); } catch (error) { console.error('❌ 启动失败:', error); process.exit(1); } // 优雅退出 process.on('SIGINT', async () => { console.log('\n🛑 停止识别...'); recognizer.stop(); await recognizer.release(); process.exit(0); }); }); program .command('transcribe') .description('转写音频文件') .argument('', '音频文件路径') .option('-l, --language ', '识别语言', 'zh') .option('-m, --model ', '模型文件路径') .option('-o, --output ', '输出文件路径') .action(async (file, options) => { console.log(`🎵 转写文件:${file}`); console.log(` 语言:${options.language}`); // TODO: 实现文件转写功能 console.log('⚠️ 文件转写功能开发中...'); }); program .command('list-devices') .description('列出可用音频设备') .action(() => { console.log('🎧 可用音频设备:'); // TODO: 实现设备列表功能 console.log('⚠️ 设备列表功能开发中...'); }); program.parse();