File size: 2,043 Bytes
845ded6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""Pure helpers of the LFM3 Space (no model, no network): text pieces and voices.

Kept apart from app.py so they can be unit-tested without torch or transformers.
"""
import re

FIRST_PIECE_MAX = 60  # first sentence longer than this is cut at its first clause

_SENTENCE = re.compile(r"(?<=[.!?…])\s+")
_CLAUSE = re.compile(r"(?<=[,;:])\s+")

# The Kokoro voice ids the app already sends (af_heart, bm_george, ...) are
# accepted, so the same client can be pointed at either Space. LFM3 has no
# named voices: only a language/locale and a female or male voice.
_KOKORO_LANG = {"a": "American English", "b": "British English"}
_GENDER = {"f": "female", "m": "male"}
_KOKORO_VOICE = re.compile(r"^([ab])([fm])_[a-z]+$")


def split_for_streaming(text: str) -> list:
    """Sentences, with the first one cut at its first clause when long, so
    the first audio arrives after synthesizing only a few words."""
    sentences = [s.strip() for s in _SENTENCE.split(text) if s.strip()]
    if not sentences:
        return []
    first = sentences[0]
    if len(first) > FIRST_PIECE_MAX:
        parts = _CLAUSE.split(first, maxsplit=1)
        if len(parts) == 2 and len(parts[0]) >= 12 and len(parts[1]) >= 12:
            return [parts[0], parts[1]] + sentences[1:]
    return sentences


def parse_voice(voice: str):
    """(language, gender) for a voice id, or None when it is not supported.

    "female" / "male" mean American English; "af_heart"-style ids map the
    first letter to American (a) or British (b) English and the second to the
    gender. Portuguese Kokoro voices (pf_, pm_) are not mapped on purpose:
    this Space is for comparing English."""
    voice = (voice or "").strip().lower()
    if voice in ("female", "male"):
        return "American English", voice
    match = _KOKORO_VOICE.match(voice)
    if match:
        return _KOKORO_LANG[match.group(1)], _GENDER[match.group(2)]
    return None


def system_prompt(language: str, gender: str) -> str:
    return f"Perform TTS in {language} using a {gender} voice."