Files
enshrouded-ru-voice/ensvoice/accent.py
T

60 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""RUAccent stresses for the text of the voice.
plus_marks(): '+' before the stressed vowel, carried onto the ORIGINAL text word by word. RUAccent is
fed lowercase (it is worse on Title-case) and drops spaces before "(", so a char-by-char walk drifts and
garbles the tail ("в годод", "))"); here only the n-th Cyrillic word of its output gives its '+' (and ё)
to the n-th word of the source, punctuation and spacing stay the source's. If the word counts differ,
the text is accented clause by clause.
acute_marks(): '+' before a vowel -> the vowel followed by U+0301, the input of the ru-stress model.
"""
import re
VOWELS = "аеёиоуыэюяАЕЁИОУЫЭЮЯ"
W = re.compile(r"[А-Яа-яЁё]+(?:-[А-Яа-яЁё]+)*")
WP = re.compile(r"[А-Яа-яЁё+]+(?:-[А-Яа-яЁё+]+)*")
_acc = None
def accentizer():
global _acc
if _acc is None:
from ruaccent import RUAccent
_acc = RUAccent()
_acc.load(omograph_model_size="turbo3.1", use_dictionary=True, tiny_mode=False)
return _acc
def _transfer(orig, acc):
out, i = [], 0
for ch in acc:
if ch == "+":
out.append("+"); continue
o = orig[i]
out.append(("Ё" if o == "Е" else "ё") if ch.lower() == "ё" and o in "еЕ" else o)
i += 1
return "".join(out)
def _plus(text):
acc = accentizer().process_all(text.lower())
src, dst = list(W.finditer(text)), WP.findall(acc)
if len(src) != len(dst) or any(len(a.group(0)) != len(b.replace("+", "")) for a, b in zip(src, dst)):
return None
out, last = [], 0
for a, b in zip(src, dst):
out += [text[last:a.start()], _transfer(a.group(0), b)]
last = a.end()
return "".join(out) + text[last:]
def plus_marks(text: str) -> str:
r = _plus(text)
if r is not None:
return r
parts = re.split(r"([,.;:!?()«»…]+\s*)", text)
return "".join(p if i % 2 or not p.strip() else (_plus(p) or p) for i, p in enumerate(parts))
def acute_marks(plus_text: str) -> str:
return re.sub(r"\+([" + VOWELS + "])", lambda m: m.group(1) + "́", plus_text).replace("+", "")