40 lines
1.2 KiB
Python
40 lines
1.2 KiB
Python
"""Text helpers shared by the adapters."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
_WHITESPACE = re.compile(r"\s+")
|
|
|
|
|
|
def normalise(text: str) -> str:
|
|
"""Collapse whitespace and trim. Keeps the robot from reading stray newlines."""
|
|
return _WHITESPACE.sub(" ", text or "").strip()
|
|
|
|
|
|
def is_cjk(char: str) -> bool:
|
|
code = ord(char)
|
|
return (
|
|
0x4E00 <= code <= 0x9FFF # CJK unified ideographs
|
|
or 0x3400 <= code <= 0x4DBF # extension A
|
|
or 0x3040 <= code <= 0x30FF # kana
|
|
or 0xAC00 <= code <= 0xD7AF # hangul
|
|
)
|
|
|
|
|
|
def estimate_speech_seconds(text: str, words_per_minute: int = 150) -> float:
|
|
"""Rough spoken duration.
|
|
|
|
Used only when the robot does not report utterance completion itself, so the
|
|
dashboard can still return to "Ready" at a believable moment instead of
|
|
hanging on "Speaking..." forever.
|
|
"""
|
|
cleaned = normalise(text)
|
|
if not cleaned:
|
|
return 0.0
|
|
cjk_chars = sum(1 for ch in cleaned if is_cjk(ch))
|
|
latin_words = len([w for w in cleaned.split() if any(not is_cjk(c) for c in w)])
|
|
# ~2.5 CJK characters per second is a typical TTS cadence.
|
|
seconds = (latin_words / max(60, words_per_minute)) * 60.0 + (cjk_chars / 2.5)
|
|
return max(0.8, seconds)
|