修改: - main.ts: 模型不存在时显示配置指引而不是退出 - model-loader.ts: 重构模型路径解析逻辑 - 使用动态路径代替硬编码路径 - 添加 MODEL_FILES 常量定义模型优先级 - 支持从任意目录加载模型 用户指引: - 无模型时显示模型下载链接 - 显示模型文件应放置的位置 - 支持 --model 参数指定模型路径 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
4.3 KiB
TypeScript
132 lines
4.3 KiB
TypeScript
/**
|
||
* 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 <lang>', '识别语言', 'zh')
|
||
.option('-m, --model <path>', '模型文件路径(可选,无模型时以配置模式启动)')
|
||
.option('-o, --output <mode>', '输出模式: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('<file>', '音频文件路径')
|
||
.option('-l, --language <lang>', '识别语言', 'zh')
|
||
.option('-m, --model <path>', '模型文件路径')
|
||
.option('-o, --output <file>', '输出文件路径')
|
||
.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();
|