You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Discord.js开发Discord机器人:Vosk语音转文本实现问题

Discord Vosk语音转录机器人问题解决方案

一、修复KaldiRecognizer构造错误

出现TypeError: KaldiRecognizer is not a constructor是因为未正确引用Vosk的构造函数,两种修复方式任选其一:

方式1:解构导入Vosk模块

取消注释代码中的解构导入语句,直接引用KaldiRecognizer:

const { Model, KaldiRecognizer } = require('vosk');
// 替换原有的 const vosk = require('vosk');

之后即可正常使用new KaldiRecognizer(model, 16000)。

方式2:通过vosk对象访问构造函数

如果保留const vosk = require('vosk');的导入方式,需通过vosk实例访问构造函数:

const recognizer = new vosk.KaldiRecognizer(model, 16000);

二、正确获取语音频道音频并实现转录

Discord.js Voice的AudioPlayer用于播放音频,接收用户语音需使用VoiceConnection的receiver对象。以下是修正后的完整实现:

修正后的核心代码

替换原有的performSpeechRecognition函数及execute逻辑:

const { SlashCommandBuilder} = require('discord.js');
const { joinVoiceChannel } = require('@discordjs/voice');
const { Model, KaldiRecognizer } = require('vosk');

// 推荐使用绝对路径避免模型路径问题
const model = new Model('./model/vosk-model-en-us-0.42-gigaspeech');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('connect')
        .setDescription('Join channel to start listening'),
    async execute(interaction) {
        const transcriptChannel = interaction.guild.channels.cache.find(c => c.name === 'transcript');
        const voiceChannel = interaction.member.voice.channel;

        if (!voiceChannel) {
            await interaction.reply({content: 'Error: 请先加入语音频道!', ephemeral: true});
            return;
        }
        if (!transcriptChannel) {
            await interaction.reply({content: 'Error: 未找到名为"transcript"的文本频道!', ephemeral: true});
            return;
        }

        const voiceConn = joinVoiceChannel({
            channelId: voiceChannel.id,
            guildId: interaction.guild.id,
            adapterCreator: interaction.guild.voiceAdapterCreator,
            selfDeaf: false, // 必须关闭自聋才能接收语音
        });

        await interaction.reply({ content: '已准备好监听语音!', ephemeral: true });
        setupSpeechRecognition(voiceConn, model, transcriptChannel, interaction.guild);
    }
};

function setupSpeechRecognition(voiceConn, model, transcriptChannel, guild) {
    // 监听用户说话开始事件
    voiceConn.receiver.speaking.on('start', (userId) => {
        const speaker = guild.members.cache.get(userId);
        if (!speaker) return;

        // 创建针对当前说话用户的音频流
        const audioStream = voiceConn.receiver.subscribe(userId, {
            end: { behavior: 'manual' } // 手动控制流结束,避免提前断开
        });

        // 初始化Vosk识别器(16000Hz采样率,单声道PCM)
        const recognizer = new KaldiRecognizer(model, 16000);
        recognizer.setWords(true);

        // 处理音频流数据
        audioStream.on('data', (chunk) => {
            if (recognizer.acceptWaveform(chunk)) {
                const result = JSON.parse(recognizer.result());
                if (result.text.trim()) {
                    transcriptChannel.send(`**${speaker.displayName}**: ${result.text}`);
                }
            }
        });

        // 音频流结束时获取最终识别结果
        audioStream.on('end', () => {
            const finalResult = JSON.parse(recognizer.finalResult());
            if (finalResult.text.trim()) {
                transcriptChannel.send(`**${speaker.displayName}**: ${finalResult.text}`);
            }
            recognizer.free(); // 释放识别器资源
        });

        // 处理识别错误
        recognizer.on('error', (err) => {
            console.error(`识别错误(用户:${speaker.displayName}):`, err);
            recognizer.free();
        });
    });
}

关键说明

  • 使用voiceConn.receiver接收用户语音流,AudioPlayer仅用于播放音频,不可用于接收
  • 为每个说话用户创建独立的KaldiRecognizer实例,避免识别内容混淆
  • 必须设置selfDeaf: false,否则机器人无法接收频道内的语音
  • 音频流结束时调用recognizer.finalResult()获取完整转录文本,避免遗漏内容
  • 识别完成后调用recognizer.free()释放资源,防止内存泄漏

内容的提问来源于stack exchange,提问作者Dem Snip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:22:43