diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py index 6a3cd2336..cd99e1fbb 100644 --- a/funasr/utils/postprocess_utils.py +++ b/funasr/utils/postprocess_utils.py @@ -442,6 +442,11 @@ def format_str_v2(s): return s.strip() +def _is_spaced_char(ch): + """Latin and Hangul text separates words with spaces; CJK text does not.""" + return (ch.isascii() and not ch.isspace()) or "\uac00" <= ch <= "\ud7a3" + + def rich_transcription_postprocess(s): """Rich transcription postprocess. @@ -481,6 +486,10 @@ def get_event(s): cur_ent_event = get_event(s_list[i]) if get_emo(s_list[i]) != None and get_emo(s_list[i]) == get_emo(new_s): new_s = new_s[:-1] - new_s += s_list[i].strip().lstrip() + segment = s_list[i].strip() + # Each VAD segment is its own <|lang|> block; keep the word boundary between them. + if segment and _is_spaced_char(new_s[-1]) and _is_spaced_char(segment[0]): + new_s += " " + new_s += segment new_s = new_s.replace("The.", " ") return new_s.strip() diff --git a/runtime/python/libtorch/funasr_torch/utils/postprocess_utils.py b/runtime/python/libtorch/funasr_torch/utils/postprocess_utils.py index 3f8d9999e..d9e1b0643 100644 --- a/runtime/python/libtorch/funasr_torch/utils/postprocess_utils.py +++ b/runtime/python/libtorch/funasr_torch/utils/postprocess_utils.py @@ -346,6 +346,11 @@ def format_str_v2(s): return s.strip() +def _is_spaced_char(ch): + """Latin and Hangul text separates words with spaces; CJK text does not.""" + return (ch.isascii() and not ch.isspace()) or "\uac00" <= ch <= "\ud7a3" + + def rich_transcription_postprocess(s): def get_emo(s): return s[-1] if s[-1] in emo_set else None @@ -370,6 +375,10 @@ def get_event(s): cur_ent_event = get_event(s_list[i]) if get_emo(s_list[i]) != None and get_emo(s_list[i]) == get_emo(new_s): new_s = new_s[:-1] - new_s += s_list[i].strip().lstrip() + segment = s_list[i].strip() + # Each VAD segment is its own <|lang|> block; keep the word boundary between them. + if segment and _is_spaced_char(new_s[-1]) and _is_spaced_char(segment[0]): + new_s += " " + new_s += segment new_s = new_s.replace("The.", " ") return new_s.strip() diff --git a/runtime/python/onnxruntime/funasr_onnx/utils/postprocess_utils.py b/runtime/python/onnxruntime/funasr_onnx/utils/postprocess_utils.py index 343ed383a..84e220166 100644 --- a/runtime/python/onnxruntime/funasr_onnx/utils/postprocess_utils.py +++ b/runtime/python/onnxruntime/funasr_onnx/utils/postprocess_utils.py @@ -400,6 +400,11 @@ def format_str_v2(s): return s.strip() +def _is_spaced_char(ch): + """Latin and Hangul text separates words with spaces; CJK text does not.""" + return (ch.isascii() and not ch.isspace()) or "\uac00" <= ch <= "\ud7a3" + + def rich_transcription_postprocess(s): def get_emo(s): return s[-1] if s[-1] in emo_set else None @@ -424,6 +429,10 @@ def get_event(s): cur_ent_event = get_event(s_list[i]) if get_emo(s_list[i]) != None and get_emo(s_list[i]) == get_emo(new_s): new_s = new_s[:-1] - new_s += s_list[i].strip().lstrip() + segment = s_list[i].strip() + # Each VAD segment is its own <|lang|> block; keep the word boundary between them. + if segment and _is_spaced_char(new_s[-1]) and _is_spaced_char(segment[0]): + new_s += " " + new_s += segment new_s = new_s.replace("The.", " ") return new_s.strip() diff --git a/tests/test_rich_transcription_event_segments.py b/tests/test_rich_transcription_event_segments.py index ed756abfd..a565b5c3c 100644 --- a/tests/test_rich_transcription_event_segments.py +++ b/tests/test_rich_transcription_event_segments.py @@ -34,7 +34,9 @@ def test_repeated_event_only_segments_keep_following_text(postprocess, event, fo result = postprocess.rich_transcription_postprocess(text) - assert result == postprocess.event_dict[event] + "hello" + following_text + assert result == postprocess.event_dict[event] + " ".join( + filter(None, ["hello", following_text]) + ) @pytest.mark.parametrize("event", ["<|Cough|>", "<|Sneeze|>", "<|Applause|>"]) diff --git a/tests/test_rich_transcription_postprocess.py b/tests/test_rich_transcription_postprocess.py index 8e07de09e..2cfc708ad 100644 --- a/tests/test_rich_transcription_postprocess.py +++ b/tests/test_rich_transcription_postprocess.py @@ -32,3 +32,24 @@ def test_cough_and_sneeze_events_render_distinct_emojis(path, event, emoji): text = module.rich_transcription_postprocess(f"<|en|><|NEUTRAL|>{event}<|woitn|>hello") assert text == f"{emoji}hello" + + +@pytest.mark.parametrize("path", POSTPROCESS_UTILS, ids=lambda path: path.parts[-3]) +@pytest.mark.parametrize( + "first, second, expected", + [ + ("Hello world.", "How are you?", "Hello world. How are you?"), + ("so I went to the", "store", "so I went to the store"), + ("안녕하세요.", "감사합니다.", "안녕하세요. 감사합니다."), + ("你好。", "再见。", "你好。再见。"), + ("你好。", "Hello.", "你好。Hello."), + ], +) +def test_vad_segments_keep_a_space_between_spaced_scripts(path, first, second, expected): + module = _load(path) + tags = "<|NEUTRAL|><|Speech|><|withitn|>" + + # AutoModel joins the tagged text of each VAD segment with a single space. + text = module.rich_transcription_postprocess(f"<|en|>{tags}{first} <|en|>{tags}{second}") + + assert text == expected