LiveTalking icon indicating copy to clipboard operation
LiveTalking copied to clipboard

打断有延迟,怎么能做到实时

Open dai0617 opened this issue 10 months ago • 8 comments

请教一下,打断说话的时候,怎么能做到实时打断,而不是延迟2~3秒之后再打断当前说话

dai0617 avatar Feb 25 '25 09:02 dai0617

每次输入的文字不要太长,分多次输入。 或者改代码找到所有队列清空

lipku avatar Feb 25 '25 11:02 lipku

除了multiprocessing中的队列,其他tts和asr的队列都清空了,可是每次发送打断命令还是会有延迟

dai0617 avatar Feb 26 '25 08:02 dai0617

除了multiprocessing中的队列,其他tts和asr的队列都清空了,可是每次发送打断命令还是会有延迟

给你一个我的个人建议,你不妨看看具体ASR的子类,比如musetalke模型使用的是MuseASR类,内部有个 run_step 函数,这个函数的大概作用就是处理音频,使用musetalk为生成后续的视频,只要在这里打断处理音频,应该就可以降低延迟。

我个人体感延迟低了很多

我的做法是在 BaseReal里新增了一个布尔变量interrupt_audio,默认为False,修改flush_talke函数:

    def flush_talk(self):
        # 新增的
        self.interrupt_audio = True
        # 框架源码
        self.tts.flush_talk()
        self.asr.flush_talk()

但是要在put_msg_txt,put_audio_frame,put_audio_file这三个函数中把interrupt_audio 重新设置成False

回到MuseASR类的 run_step 函数中:

 if self.parent.interrupt_audio:
                # 如果是打断,就生成空音频
                audio_frame = np.zeros(self.chunk, dtype=np.float32)
                type = 1
                eventpoint = None
            else:
                audio_frame,type,eventpoint = self.get_audio_frame()
            self.frames.append(audio_frame)
            self.output_queue.put((audio_frame,type,eventpoint))

你可以看看baseasr.py中的get_audio_frame函数,这就是获取音频帧的函数。

LIKEGAKKI avatar Feb 27 '25 03:02 LIKEGAKKI

除了multiprocessing中的队列,其他tts和asr的队列都清空了,可是每次发送打断命令还是会有延迟

给你一个我的个人建议,你不妨看看具体ASR的子类,比如musetalke模型使用的是MuseASR类,内部有个 run_step 函数,这个函数的大概作用就是处理音频,使用musetalk为生成后续的视频,只要在这里打断处理音频,应该就可以降低延迟。

我个人体感延迟低了很多

我的做法是在 BaseReal里新增了一个布尔变量interrupt_audio,默认为False,修改flush_talke函数:

def flush_talk(self):
    # 新增的
    self.interrupt_audio = True
    # 框架源码
    self.tts.flush_talk()
    self.asr.flush_talk()

但是要在put_msg_txt,put_audio_frame,put_audio_file这三个函数中把interrupt_audio 重新设置成False

回到MuseASR类的 run_step 函数中:

if self.parent.interrupt_audio: # 如果是打断,就生成空音频 audio_frame = np.zeros(self.chunk, dtype=np.float32) type = 1 eventpoint = None else: audio_frame,type,eventpoint = self.get_audio_frame() self.frames.append(audio_frame) self.output_queue.put((audio_frame,type,eventpoint)) 你可以看看baseasr.py中的get_audio_frame函数,这就是获取音频帧的函数。

感谢您的思路,但是我发现还是会要说一点再停下 ,这个是因为视频的流已经传到前端了吗?

kkkwjr avatar Mar 07 '25 06:03 kkkwjr

除了multiprocessing中的队列,其他tts和asr的队列都清空了,可是每次发送打断命令还是会有延迟

给你一个我的个人建议,你不妨看看具体ASR的子类,比如musetalke模型使用的是MuseASR类,内部有个 run_step 函数,这个函数的大概作用就是处理音频,使用musetalk为生成后续的视频,只要在这里打断处理音频,应该就可以降低延迟。 我个人体感延迟低了很多 我的做法是在 BaseReal里新增了一个布尔变量interrupt_audio,默认为False,修改flush_talke函数:

def flush_talk(self):
    # 新增的
    self.interrupt_audio = True
    # 框架源码
    self.tts.flush_talk()
    self.asr.flush_talk()

但是要在put_msg_txt,put_audio_frame,put_audio_file这三个函数中把interrupt_audio 重新设置成False 回到MuseASR类的 run_step 函数中: if self.parent.interrupt_audio:

如果是打断,就生成空音频

audio_frame = np.zeros(self.chunk, dtype=np.float32) type = 1 eventpoint = None else: audio_frame,type,eventpoint = self.get_audio_frame() self.frames.append(audio_frame) self.output_queue.put((audio_frame,type,eventpoint)) 你可以看看baseasr.py中的get_audio_frame函数,这就是获取音频帧的函数。

感谢您的思路,但是我发现还是会要说一点再停下 ,这个是因为视频的流已经传到前端了吗?

我猜测应该是的,咱么只能控制还在队列里的,对于已经处理好推送到srs服务器的就没法再做拦截了。 建议一段话多分段吧,不要一次处理的太长。

LIKEGAKKI avatar Mar 07 '25 06:03 LIKEGAKKI

除了multiprocessing中的队列,其他tts和asr的队列都清空了,可是每次发送打断命令还是会有延迟

给你一个我的个人建议,你不妨看看具体ASR的子类,比如musetalke模型使用的是MuseASR类,内部有个 run_step 函数,这个函数的大概作用就是处理音频,使用musetalk为生成后续的视频,只要在这里打断处理音频,应该就可以降低延迟。 我个人体感延迟低了很多 我的做法是在 BaseReal里新增了一个布尔变量interrupt_audio,默认为False,修改flush_talke函数:

def flush_talk(self):
    # 新增的
    self.interrupt_audio = True
    # 框架源码
    self.tts.flush_talk()
    self.asr.flush_talk()

但是要在put_msg_txt,put_audio_frame,put_audio_file这三个函数中把interrupt_audio 重新设置成False 回到MuseASR类的 run_step 函数中: if self.parent.interrupt_audio:

如果是打断,就生成空音频

audio_frame = np.zeros(self.chunk, dtype=np.float32) type = 1 eventpoint = None else: audio_frame,type,eventpoint = self.get_audio_frame() self.frames.append(audio_frame) self.output_queue.put((audio_frame,type,eventpoint)) 你可以看看baseasr.py中的get_audio_frame函数,这就是获取音频帧的函数。

感谢您的思路,但是我发现还是会要说一点再停下 ,这个是因为视频的流已经传到前端了吗?

我猜测应该是的,咱么只能控制还在队列里的,对于已经处理好推送到srs服务器的就没法再做拦截了。 建议一段话多分段吧,不要一次处理的太长。

那我想到的是减小bs,我刚才试了一下bs减小到4的话打断就很流畅了

kkkwjr avatar Mar 07 '25 07:03 kkkwjr

走后端清空队列的确是没法立即停止,我想从前端着手处理: 停止逻辑: // 立即停止音频播放 const audioElement = document.getElementById('audio'); const audioTracks = audioElement.srcObject?.getAudioTracks(); if (audioTracks) { audioTracks.forEach(track => { track.enabled = false; }); } // 停止视频播放 const videoElement = document.getElementById('video'); videoElement.pause();

播放逻辑: // 启动音频播放 const audioElement = document.getElementById('audio'); const audioTracks = audioElement.srcObject?.getAudioTracks(); if (audioTracks) { audioTracks.forEach(track => { track.enabled = true; }); } // 启动视频播放 const videoElement = document.getElementById('video'); videoElement.play();

这样的效果是,音频立即停止了,但视频直接暂停了(静态画面),没法让视频直接初始化,还得借助后端状态

byronv5 avatar May 13 '25 03:05 byronv5

走后端清空队列的确是没法立即停止,我想从前端着手处理: 停止逻辑: // 立即停止音频播放 const audioElement = document.getElementById('audio'); const audioTracks = audioElement.srcObject?.getAudioTracks(); if (audioTracks) { audioTracks.forEach(track => { track.enabled = false; }); } // 停止视频播放 const videoElement = document.getElementById('video'); videoElement.pause();

播放逻辑: // 启动音频播放 const audioElement = document.getElementById('audio'); const audioTracks = audioElement.srcObject?.getAudioTracks(); if (audioTracks) { audioTracks.forEach(track => { track.enabled = true; }); } // 启动视频播放 const videoElement = document.getElementById('video'); videoElement.play();

这样的效果是,音频立即停止了,但视频直接暂停了(静态画面),没法让视频直接初始化,还得借助后端状态

所以我最终的实现是,前端让音频立即停止,然后走打断逻辑,口型虽然有延迟,但是声音是立即停止的。

byronv5 avatar Jul 21 '25 09:07 byronv5