Fix sentence splitting for CJK and other non-Latin languages in TTS pipeline
NLTK's sent_tokenize() only supports ~15 European languages and defaults to English. For Japanese, Chinese, Korean, Hindi, Arabic, and other non-Latin languages, NLTK fails to recognize sentence boundaries like 。?! causing text to accumulate until flush instead of being emitted sentence-by-sentence. Add a fallback in match_endofsentence() that scans for unambiguous non-Latin sentence-ending punctuation when NLTK fails to split the text. Latin punctuation (. ! ? ; …) is excluded from the fallback since NLTK handles those correctly and they can be ambiguous (abbreviations, decimals, etc.). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -124,6 +124,62 @@ class TestSimpleTextAggregator(unittest.IsolatedAsyncioTestCase):
|
||||
result = await self.aggregator.flush()
|
||||
assert result.text == "W"
|
||||
|
||||
async def test_japanese_multiple_sentences(self):
|
||||
"""Test that Japanese sentences are properly split during streaming."""
|
||||
text = "こんにちは。元気ですか?"
|
||||
results = [agg async for agg in self.aggregator.aggregate(text)]
|
||||
|
||||
# First sentence detected when 元 arrives as lookahead after 。
|
||||
assert len(results) == 1
|
||||
assert results[0].text == "こんにちは。"
|
||||
|
||||
# Flush returns the second sentence
|
||||
result = await self.aggregator.flush()
|
||||
assert result.text == "元気ですか?"
|
||||
|
||||
async def test_japanese_sentence_with_lookahead(self):
|
||||
"""Test that a Japanese sentence is detected with a lookahead character."""
|
||||
text = "こんにちは。元"
|
||||
results = [agg async for agg in self.aggregator.aggregate(text)]
|
||||
|
||||
# 。 triggers lookahead, then 元 confirms it
|
||||
assert len(results) == 1
|
||||
assert results[0].text == "こんにちは。"
|
||||
|
||||
# Flush returns remainder
|
||||
result = await self.aggregator.flush()
|
||||
assert result.text == "元"
|
||||
|
||||
async def test_chinese_streaming_tokens(self):
|
||||
"""Test Chinese text split across multiple streaming tokens."""
|
||||
aggregator = SimpleTextAggregator()
|
||||
|
||||
tokens = ["你好", "世界", "。", "下一", "句话", "。"]
|
||||
all_results = []
|
||||
for token in tokens:
|
||||
results = [agg async for agg in aggregator.aggregate(token)]
|
||||
all_results.extend(results)
|
||||
|
||||
# First sentence detected when 下 arrives after 。
|
||||
assert len(all_results) == 1
|
||||
assert all_results[0].text == "你好世界。"
|
||||
|
||||
# Flush returns the second sentence
|
||||
result = await aggregator.flush()
|
||||
assert result.text == "下一句话。"
|
||||
|
||||
async def test_japanese_single_sentence_flush(self):
|
||||
"""Test that a single Japanese sentence with no lookahead flushes correctly."""
|
||||
text = "こんにちは。"
|
||||
results = [agg async for agg in self.aggregator.aggregate(text)]
|
||||
|
||||
# No lookahead yet - waiting
|
||||
assert len(results) == 0
|
||||
|
||||
# Flush returns the complete sentence
|
||||
result = await self.aggregator.flush()
|
||||
assert result.text == "こんにちは。"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user