Initial commit: FunASR Speech Recognition Toolkit
Update API Documentation / build-api-docs (push) Has been cancelled
Update API Documentation / build-api-docs (push) Has been cancelled
Add complete FunASR codebase including models, runtime, and documentation.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Test FSMN-VAD Streaming: chunk-by-chunk voice activity detection"""
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
|
||||
def main():
|
||||
import soundfile
|
||||
from funasr import AutoModel
|
||||
|
||||
print("[FSMN-VAD-Streaming] Loading model...")
|
||||
t0 = time.time()
|
||||
model = AutoModel(
|
||||
model="iic/speech_fsmn_vad_zh-cn-16k-common-pytorch",
|
||||
device="cpu",
|
||||
disable_update=True,
|
||||
disable_pbar=True,
|
||||
)
|
||||
print("[FSMN-VAD-Streaming] Model loaded in %.1fs" % (time.time() - t0))
|
||||
|
||||
wav_file = os.path.join(model.model_path, "example/vad_example.wav")
|
||||
speech, sample_rate = soundfile.read(wav_file)
|
||||
chunk_size = 200 # ms
|
||||
chunk_stride = int(chunk_size * sample_rate / 1000)
|
||||
|
||||
total_chunk_num = int((len(speech) - 1) / chunk_stride + 1)
|
||||
print("[FSMN-VAD-Streaming] Audio: %.2fs, %d chunks of %dms" % (
|
||||
len(speech) / sample_rate, total_chunk_num, chunk_size))
|
||||
|
||||
print("[FSMN-VAD-Streaming] Running streaming inference...")
|
||||
t0 = time.time()
|
||||
|
||||
cache = {}
|
||||
all_events = []
|
||||
for i in range(total_chunk_num):
|
||||
speech_chunk = speech[i * chunk_stride:(i + 1) * chunk_stride]
|
||||
is_final = i == total_chunk_num - 1
|
||||
res = model.generate(
|
||||
input=speech_chunk,
|
||||
cache=cache,
|
||||
is_final=is_final,
|
||||
chunk_size=chunk_size,
|
||||
)
|
||||
if res[0]["value"]:
|
||||
all_events.extend(res[0]["value"])
|
||||
|
||||
print("[FSMN-VAD-Streaming] Inference done in %.1fs" % (time.time() - t0))
|
||||
|
||||
# Parse streaming VAD events into complete segments
|
||||
# Streaming output: [beg, -1] = speech start, [-1, end] = speech end, [beg, end] = complete
|
||||
complete_segments = []
|
||||
pending_start = None
|
||||
for event in all_events:
|
||||
if event[0] >= 0 and event[1] == -1:
|
||||
pending_start = event[0]
|
||||
elif event[0] == -1 and event[1] >= 0:
|
||||
if pending_start is not None:
|
||||
complete_segments.append([pending_start, event[1]])
|
||||
pending_start = None
|
||||
elif event[0] >= 0 and event[1] >= 0:
|
||||
complete_segments.append(event)
|
||||
|
||||
print("[FSMN-VAD-Streaming] Raw events: %d, Complete segments: %d" % (
|
||||
len(all_events), len(complete_segments)))
|
||||
print("[FSMN-VAD-Streaming] Segments: %s" % complete_segments)
|
||||
|
||||
if not complete_segments:
|
||||
print("[FSMN-VAD-Streaming] FAILED - no complete segments")
|
||||
return 1
|
||||
|
||||
# Verify segments have valid ranges
|
||||
for seg in complete_segments:
|
||||
if seg[1] <= seg[0]:
|
||||
print("[FSMN-VAD-Streaming] FAILED - invalid segment: %s" % seg)
|
||||
return 1
|
||||
|
||||
# Verify consistency: run again with fresh cache
|
||||
cache2 = {}
|
||||
all_events2 = []
|
||||
for i in range(total_chunk_num):
|
||||
speech_chunk = speech[i * chunk_stride:(i + 1) * chunk_stride]
|
||||
is_final = i == total_chunk_num - 1
|
||||
res = model.generate(
|
||||
input=speech_chunk, cache=cache2, is_final=is_final, chunk_size=chunk_size,
|
||||
)
|
||||
if res[0]["value"]:
|
||||
all_events2.extend(res[0]["value"])
|
||||
|
||||
if all_events != all_events2:
|
||||
print("[FSMN-VAD-Streaming] FAILED - inconsistent across sessions")
|
||||
return 1
|
||||
|
||||
print("[FSMN-VAD-Streaming] Consistency: 2 sessions identical")
|
||||
print("[FSMN-VAD-Streaming] PASSED")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user