chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
|
||||
|
||||
# Adapted from https://github.com/google/TextNormalizationCoveringGrammars
|
||||
# Russian minimally supervised number grammar.
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NON_BREAKING_SPACE,
|
||||
DAMO_SPACE,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
|
||||
RU_LOWER_ALPHA = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
|
||||
RU_UPPER_ALPHA = RU_LOWER_ALPHA.upper()
|
||||
RU_LOWER_ALPHA = pynini.union(*RU_LOWER_ALPHA).optimize()
|
||||
RU_UPPER_ALPHA = pynini.union(*RU_UPPER_ALPHA).optimize()
|
||||
RU_ALPHA = (RU_LOWER_ALPHA | RU_UPPER_ALPHA).optimize()
|
||||
|
||||
RU_STRESSED_MAP = [
|
||||
("А́", "А'"),
|
||||
("Е́", "Е'"),
|
||||
("Ё́", "Е'"),
|
||||
("И́", "И'"),
|
||||
("О́", "О'"),
|
||||
("У́", "У'"),
|
||||
("Ы́", "Ы'"),
|
||||
("Э́", "Э'"),
|
||||
("Ю́", "Ю'"),
|
||||
("Я́", "Я'"),
|
||||
("а́", "а'"),
|
||||
("е́", "е'"),
|
||||
("ё́", "е'"),
|
||||
("и́", "и'"),
|
||||
("о́", "о'"),
|
||||
("у́", "у'"),
|
||||
("ы́", "ы'"),
|
||||
("э́", "э'"),
|
||||
("ю́", "ю'"),
|
||||
("я́", "я'"),
|
||||
("ё", "е"),
|
||||
("Ё", "Е"),
|
||||
]
|
||||
|
||||
REWRITE_STRESSED = pynini.closure(
|
||||
pynini.string_map(RU_STRESSED_MAP).optimize() | RU_ALPHA
|
||||
).optimize()
|
||||
TO_CYRILLIC = pynini.string_file(get_abs_path("data/latin_to_cyrillic.tsv")).optimize()
|
||||
TO_LATIN = pynini.invert(TO_CYRILLIC).optimize()
|
||||
RU_ALPHA_OR_SPACE = pynini.union(RU_ALPHA, DAMO_SPACE, DAMO_NON_BREAKING_SPACE).optimize()
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
р. рубли 0.1
|
||||
р. рубля 0.1
|
||||
р. рублей 0.1
|
||||
р. рублям 0.1
|
||||
р. рублями 0.1
|
||||
р. рублях 0.1
|
||||
руб. рубли -0.1
|
||||
руб. рубля -0.1
|
||||
руб. рублей -0.1
|
||||
руб. рублям -0.1
|
||||
руб. рублями -0.1
|
||||
руб. рублях -0.1
|
||||
₽ рубли 0.1
|
||||
₽ рубля 0.1
|
||||
₽ рублей 0.1
|
||||
₽ рублям 0.1
|
||||
₽ рублями 0.1
|
||||
₽ рублях 0.1
|
||||
RUB рубли 0.1
|
||||
RUB рублей 0.1
|
||||
RUB рубля 0.1
|
||||
RUB рублям 0.1
|
||||
RUB рублями 0.1
|
||||
RUB рублях 0.1
|
||||
$ доллары 0.1
|
||||
$ долларов 0.1
|
||||
$ доллара 0.1
|
||||
$ долларам 0.1
|
||||
$ доллары 0.1
|
||||
$ долларами 0.1
|
||||
USD доллары -0.1
|
||||
USD долларов -0.1
|
||||
USD долларам -0.1
|
||||
USD долларах -0.1
|
||||
USD долларами -0.1
|
||||
USD американские доллары 0.1
|
||||
USD американских долларов 0.1
|
||||
USD американским долларам 0.1
|
||||
USD американскими долларами 0.1
|
||||
USD американских долларах 0.1
|
||||
долл. США долларов сэ ш а 0.1
|
||||
долл. США долларов с ш а 0.1
|
||||
долл. США долларов сша -0.1
|
||||
долл. США доллара сша -0.1
|
||||
£ фунта 0.1
|
||||
£ фунтов 0.1
|
||||
€ евро 0.1
|
||||
€ евро 0.1
|
||||
коп. копейки
|
||||
коп. копеек
|
||||
коп. копейкам
|
||||
коп. копейками
|
||||
коп. копейках
|
||||
|
@@ -0,0 +1,48 @@
|
||||
р. рубль 1
|
||||
р. рубля 1
|
||||
р. рублю 1
|
||||
р. рублем 1
|
||||
р. рубле 1
|
||||
руб. рубль -1
|
||||
руб. рубля -1
|
||||
руб. рублю -1
|
||||
руб. рублем -1
|
||||
руб. рубле -1
|
||||
₽ рубль 1
|
||||
₽ рубля 1
|
||||
₽ рублю 1
|
||||
₽ рублем 1
|
||||
₽ рубле 1
|
||||
RUB рубль 1
|
||||
RUB рубль 1
|
||||
RUB рубля 1
|
||||
RUB рублю 1
|
||||
RUB рублем 1
|
||||
RUB рубле 1
|
||||
USD доллар -1
|
||||
USD доллара -1
|
||||
USD доллару -1
|
||||
USD долларом -1
|
||||
USD долларе -1
|
||||
USD американский доллар 1
|
||||
USD американского доллара 1
|
||||
USD американскому доллару 1
|
||||
USD американским долларом 1
|
||||
USD американском долларе 1
|
||||
$ доллар 1
|
||||
$ доллар сэ ш а
|
||||
$ доллар с ш а
|
||||
$ доллар 1
|
||||
$ доллара 1
|
||||
$ доллару 1
|
||||
$ долларом 1
|
||||
$ долларе 1
|
||||
£ фунт
|
||||
€ евро
|
||||
коп. копейка
|
||||
коп. копейки
|
||||
коп. копейке
|
||||
коп. копейку
|
||||
коп. копейкой
|
||||
коп. копейкою
|
||||
коп. копейке
|
||||
|
@@ -0,0 +1,9 @@
|
||||
com ком
|
||||
uk
|
||||
fr
|
||||
net нет
|
||||
br
|
||||
in
|
||||
ru ру
|
||||
de
|
||||
it
|
||||
|
@@ -0,0 +1,17 @@
|
||||
gmail джи мейл
|
||||
n vidia н видия
|
||||
n vidia эн видия
|
||||
n vidia энвидия
|
||||
n vidia нвидия
|
||||
outlook аутлук
|
||||
hotmail хот мейл
|
||||
yahoo яху
|
||||
aol
|
||||
gmx
|
||||
msn
|
||||
live лайв
|
||||
yandex яндекс
|
||||
orange орандж
|
||||
wanadoo ванаду
|
||||
web веб
|
||||
comcast комкаст
|
||||
|
@@ -0,0 +1,28 @@
|
||||
. точка
|
||||
- тире
|
||||
- дефис
|
||||
- минус
|
||||
_ нижнее подчеркивание
|
||||
_ знак подчеркивания
|
||||
! восклицательный знак
|
||||
# решетка
|
||||
$ доллар
|
||||
% процент
|
||||
& энд
|
||||
& амперсанд
|
||||
' кавычка
|
||||
* звездочка
|
||||
* знак умножения
|
||||
+ плюс
|
||||
/ слэш
|
||||
/ косая черта
|
||||
\ бэк слэш
|
||||
\ обратная косая черта
|
||||
= равно
|
||||
? вопросительный знак
|
||||
^ знак вставки
|
||||
` кавычка
|
||||
{ открытая фигурная скобка
|
||||
| вертикальный слэш
|
||||
} закрытая фигурная скобка
|
||||
~ тильда
|
||||
|
@@ -0,0 +1,38 @@
|
||||
a эй
|
||||
b би
|
||||
b бэ
|
||||
c си
|
||||
d ди
|
||||
e и
|
||||
f эф
|
||||
f ф
|
||||
h эйч
|
||||
h х
|
||||
i ай
|
||||
g джи
|
||||
j джей
|
||||
k кей
|
||||
k к
|
||||
l л
|
||||
l эл
|
||||
m эм
|
||||
n н
|
||||
n эн
|
||||
o оу
|
||||
o о
|
||||
p пи
|
||||
q кью
|
||||
r а
|
||||
r ар
|
||||
r р
|
||||
s эс
|
||||
t ти
|
||||
u ю
|
||||
v ви
|
||||
w дабл ю
|
||||
w дабл в
|
||||
x экс
|
||||
y уай
|
||||
z з
|
||||
z зед
|
||||
z зи
|
||||
|
@@ -0,0 +1,321 @@
|
||||
°F Фаренгейт
|
||||
°F градусов Фаренгейта
|
||||
°F градусов по Фаренгейту
|
||||
°F фаренгейт
|
||||
°F градусов фаренгейта
|
||||
°F градусов по фаренгейту
|
||||
°C цельсия
|
||||
°C градусов цельсия
|
||||
°C градусов по цельсию
|
||||
°C Цельсия
|
||||
°C градусов цельсия
|
||||
°C градусов по цельсию
|
||||
° градус
|
||||
° градуса
|
||||
° градусу
|
||||
° градусом
|
||||
° градусе
|
||||
° градусы
|
||||
° градусов
|
||||
° градусам
|
||||
° градусы
|
||||
° градусами
|
||||
° градусах
|
||||
рад радиан
|
||||
рад радиана
|
||||
рад радиану
|
||||
рад радианом
|
||||
рад радиане
|
||||
рад радианы
|
||||
рад радианов
|
||||
рад радианам
|
||||
рад радианами
|
||||
рад радианах
|
||||
км километр
|
||||
км километры
|
||||
км километра
|
||||
км километров
|
||||
км километру
|
||||
км километрам
|
||||
км километром
|
||||
км километрами
|
||||
км километре
|
||||
км километрах
|
||||
м метр
|
||||
м метра
|
||||
м метру
|
||||
м метра
|
||||
м метром
|
||||
м метре
|
||||
м метры
|
||||
м метров
|
||||
м метрам
|
||||
м метров
|
||||
м метрами
|
||||
м метрах
|
||||
см сантиметр
|
||||
см сантиметры
|
||||
см сантиметра
|
||||
см сантиметров
|
||||
см сантиметру
|
||||
см сантиметрам
|
||||
см сантиметром
|
||||
см сантиметрами
|
||||
см сантиметре
|
||||
см сантиметрах
|
||||
мм миллиметр
|
||||
мм миллиметры
|
||||
мм миллиметра
|
||||
мм миллиметров
|
||||
мм миллиметру
|
||||
мм миллиметрам
|
||||
мм миллиметр
|
||||
мм миллиметром
|
||||
мм миллиметрами
|
||||
мм миллиметре
|
||||
мм миллиметрах
|
||||
га гектар
|
||||
га гектары
|
||||
га гектара
|
||||
га гектаров
|
||||
га гектару
|
||||
га гектарам
|
||||
га гектаром
|
||||
га гектарами
|
||||
га гектаре
|
||||
га гектарах
|
||||
м² квадратный метр -0.11
|
||||
м² квадратные метры -0.11
|
||||
м² квадратного метра -0.11
|
||||
м² квадратных метров -0.11
|
||||
м² квадратному метру -0.11
|
||||
м² квадратным метрам -0.11
|
||||
м² квадратные метры -0.11
|
||||
м² квадратным метром -0.11
|
||||
м² квадратными метрами -0.11
|
||||
м² квадратном метре -0.11
|
||||
м² квадратных метрах -0.11
|
||||
кв. м. квадратный метр -0.1
|
||||
кв. м. квадратные метры -0.1
|
||||
кв. м. квадратного метра -0.1
|
||||
кв. м. квадратных метров -0.1
|
||||
кв. м. квадратному метру -0.1
|
||||
кв. м. квадратным метрам -0.1
|
||||
кв. м. квадратные метры -0.1
|
||||
кв. м. квадратным метром -0.1
|
||||
кв. м. квадратными метрами -0.1
|
||||
кв. м. квадратном метре -0.1
|
||||
кв.м. квадратных метрах -0.1
|
||||
кв.м. квадратный метр -0.1
|
||||
кв.м. квадратные метры -0.1
|
||||
кв.м. квадратного метра -0.1
|
||||
кв.м. квадратных метров -0.1
|
||||
кв.м. квадратному метру -0.1
|
||||
кв.м. квадратным метрам -0.1
|
||||
кв.м. квадратные метры -0.1
|
||||
кв.м. квадратным метром -0.1
|
||||
кв.м. квадратными метрами -0.1
|
||||
кв.м. квадратном метре -0.1
|
||||
кв.м. квадратных метрах -0.1
|
||||
м2 квадратный метр 0.1
|
||||
м2 квадратные метры 0.1
|
||||
м2 квадратного метра 0.1
|
||||
м2 квадратных метров 0.1
|
||||
м2 квадратному метру 0.1
|
||||
м2 квадратным метрам 0.1
|
||||
м2 квадратные метры 0.1
|
||||
м2 квадратным метром 0.1
|
||||
м2 квадратными метрами 0.1
|
||||
м2 квадратном метре 0.1
|
||||
м2 квадратных метрах 0.1
|
||||
₽ рублей 0.1
|
||||
₽ рубля 0.1
|
||||
₽ рубль 0.1
|
||||
RUB рублей 0.1
|
||||
RUB рубля 0.1
|
||||
RUB рубль 0.1
|
||||
pуб. рублей -0.1
|
||||
pуб. рубля -0.1
|
||||
pуб. рубль -0.1
|
||||
pуб рублей 0.1
|
||||
pуб рубля 0.1
|
||||
pуб рубль 0.1
|
||||
км² квадратный километр -0.1
|
||||
км2 квадратный километр 0.1
|
||||
% процент
|
||||
% проценты
|
||||
% процента
|
||||
% процентов
|
||||
% проценту
|
||||
% процентам
|
||||
% процентом
|
||||
% процентами
|
||||
% проценте
|
||||
% процентах
|
||||
кВт киловатт
|
||||
л. с. лошадиная сила
|
||||
л. с. лошадиные силы
|
||||
л. с. лошадиной силы
|
||||
л. с. лошадиных сил
|
||||
л. с. лошадиной силе
|
||||
л. с. лошадиным силам
|
||||
л. с. лошадиную силу
|
||||
л. с. лошадиные силы
|
||||
л. с. лошадиной силой
|
||||
л. с. лошадиной силою
|
||||
л. с. лошадиными силами
|
||||
л. с. лошадиных силах
|
||||
мг миллиграм
|
||||
кг килограм
|
||||
кг килограма
|
||||
кг килограму
|
||||
кг килограм
|
||||
кг килограмом
|
||||
кг килограме
|
||||
кг килограмы
|
||||
кг килограмов
|
||||
кг килограмам
|
||||
кг килограмы
|
||||
кг килограмами
|
||||
кг килограмах
|
||||
л литр
|
||||
л литры
|
||||
л литра
|
||||
л литров
|
||||
л литру
|
||||
л литрам
|
||||
л литры
|
||||
л литром
|
||||
л литрами
|
||||
л литре
|
||||
л литрах
|
||||
л литре
|
||||
кл килолитр
|
||||
гл гектолитр
|
||||
Мл мегалитр
|
||||
Гл гигалитр
|
||||
мл миллиитр
|
||||
ч час
|
||||
сек. секунд -0.1
|
||||
сек. секунда -0.1
|
||||
сек. секунды -0.1
|
||||
сек. секунды -0.1
|
||||
сек. секунд -0.1
|
||||
сек. секунде -0.1
|
||||
сек. секундам -0.1
|
||||
сек. секунду -0.1
|
||||
сек. секунды -0.1
|
||||
сек. секундой -0.1
|
||||
сек. секундами -0.1
|
||||
сек. секунде -0.1
|
||||
сек. секундах -0.1
|
||||
сек секунд 0.1
|
||||
сек секунда 0.1
|
||||
сек секунды 0.1
|
||||
сек секунды 0.1
|
||||
сек секунд 0.1
|
||||
сек секунде 0.1
|
||||
сек секундам 0.1
|
||||
сек секунду 0.1
|
||||
сек секунды 0.1
|
||||
сек секундой 0.1
|
||||
сек секундами 0.1
|
||||
сек секунде 0.1
|
||||
сек секундах 0.1
|
||||
с секунд 0.1
|
||||
с секунда 0.1
|
||||
с секунды 0.1
|
||||
с секунды 0.1
|
||||
с секунд 0.1
|
||||
с секунде 0.1
|
||||
с секундам 0.1
|
||||
с секунду 0.1
|
||||
с секунды 0.1
|
||||
с секундой 0.1
|
||||
с секундами 0.1
|
||||
с секунде 0.1
|
||||
с секундах 0.1
|
||||
дас декасекунда
|
||||
кс килосекунда
|
||||
Мс мегасекунда
|
||||
мс миллисекунда
|
||||
нм нанометр
|
||||
нм нанометра
|
||||
нм нанометров
|
||||
нм нанометры
|
||||
А ампер
|
||||
К кельвин
|
||||
кд кандела
|
||||
мА миллиампер
|
||||
кВт⋅ч киловатт час
|
||||
м³ кубический метр -0.1
|
||||
м³ кубический метров -0.1
|
||||
м3 кубический метр 0.1
|
||||
м3 кубический метров 0.1
|
||||
м³ кубометр -0.1
|
||||
м³ кубометров -0.1
|
||||
км/ч километров в час
|
||||
км/ч километра в час
|
||||
В вольт
|
||||
гВ гектовольт
|
||||
кВ киловольт
|
||||
МВ мегавольт
|
||||
мВ милливольт
|
||||
мВт мегаватт
|
||||
ТВт тераватт
|
||||
мкм микрометр
|
||||
г грамм
|
||||
г граммов
|
||||
дБ децибел
|
||||
Б байт
|
||||
Кбайт килобайт
|
||||
Мбайт мегабайт
|
||||
Пбайт петабайт
|
||||
Тбайт терабайт 0.1
|
||||
ТБ терабайт -0.1
|
||||
Гбайт гигабайт 0.1
|
||||
Гб гигабайт -0.1
|
||||
Гц герц
|
||||
даГц декагерц
|
||||
дГц децигерц
|
||||
гГц гектогерц
|
||||
сГц сантигерц
|
||||
кГц килогерц
|
||||
мГц миллигерц
|
||||
МГц мегагерц
|
||||
мкГц микрогерц
|
||||
ГГц гигагерц
|
||||
нГц наногерц
|
||||
ТГц терагерц
|
||||
пГц пикогерц
|
||||
ПГц петагерц
|
||||
фГц фемтогерц
|
||||
ЭГц эксагерц
|
||||
аГц аттогерц
|
||||
ЗГц зеттагерц
|
||||
зГц зептогерц
|
||||
ИГц иоттагерц
|
||||
иГц иоктогерц
|
||||
кбит килобит
|
||||
Мбит мегабит
|
||||
Гбит гигабит
|
||||
Тбит терабит
|
||||
бит/с бит в секунду
|
||||
кбит/с килобит в секунду
|
||||
Мбит/с мегабит в секунду
|
||||
Гбит/с гигабит в секунду
|
||||
нс наносекунда
|
||||
нс наносекунды
|
||||
нс наносекунд
|
||||
мм² квадратный миллиметр -0.1
|
||||
мм² квадратных миллиметров -0.1
|
||||
мм² квадратных миллиметра -0.1
|
||||
мм2 квадратный миллиметр 0.1
|
||||
мм2 квадратных миллимета 0.1
|
||||
мм2 квадратных миллиметров 0.1
|
||||
см² квадратный сантиметр -0.1
|
||||
см² квадратных сантимета -0.1
|
||||
см² квадратных сантиметров -0.1
|
||||
см2 квадратный сантиметр 0.1
|
||||
см2 квадратных сантиметра 0.1
|
||||
см2 квадратных сантиметров 0.1
|
||||
|
@@ -0,0 +1,12 @@
|
||||
янв январь
|
||||
фев февраль
|
||||
мар март
|
||||
апр апрель
|
||||
май май
|
||||
июнь июнь
|
||||
июль июль
|
||||
авг август
|
||||
сент сентябрь
|
||||
окт октябрь
|
||||
нояб ноябрь
|
||||
дек декабрь
|
||||
|
@@ -0,0 +1,62 @@
|
||||
янв январь 0.1
|
||||
янв января -0.1
|
||||
янв январю 0.1
|
||||
янв январем 0.1
|
||||
янв январе 0.1
|
||||
фев февраль 0.1
|
||||
фев февраль 0.1
|
||||
фев февраля -0.1
|
||||
фев февралю 0.1
|
||||
фев февралем 0.1
|
||||
фев феврале 0.1
|
||||
мар март 0.1
|
||||
мар марта -0.1
|
||||
мар марту 0.1
|
||||
мар мартом 0.1
|
||||
мар марте 0.1
|
||||
апр апрель 0.1
|
||||
апр апреля -0.1
|
||||
апр апрелю 0.1
|
||||
апр апрелем 0.1
|
||||
апр апреле 0.1
|
||||
май май 0.1
|
||||
май мая -0.1
|
||||
май маю 0.1
|
||||
май маем 0.1
|
||||
май мае 0.1
|
||||
июнь июнь 0.1
|
||||
июнь июня -0.1
|
||||
июнь июню 0.1
|
||||
июнь июнем 0.1
|
||||
июнь июне 0.1
|
||||
июль июль 0.1
|
||||
июль июля -0.1
|
||||
июль июлю 0.1
|
||||
июль июлем 0.1
|
||||
июль июле 0.1
|
||||
авг август 0.1
|
||||
авг августа -0.1
|
||||
авг августу 0.1
|
||||
авг август 0.1
|
||||
авг августом 0.1
|
||||
авг августе 0.1
|
||||
сент сентябрь 0.1
|
||||
сент сентября -0.1
|
||||
сент сентябрю 0.1
|
||||
сент сентябрем 0.1
|
||||
сент сентябре 0.1
|
||||
окт октябрь 0.1
|
||||
окт октября -0.1
|
||||
окт октябрю 0.1
|
||||
окт октябрем 0.1
|
||||
окт октябре 0.1
|
||||
нояб ноябрь 0.1
|
||||
нояб ноября -0.1
|
||||
нояб ноябрю 0.1
|
||||
нояб ноябрем 0.1
|
||||
нояб ноябре 0.1
|
||||
дек декабрь 0.1
|
||||
дек декабря -0.1
|
||||
дек декабрю 0.1
|
||||
дек декабрем 0.1
|
||||
дек декабре 0.1
|
||||
|
@@ -0,0 +1,21 @@
|
||||
1 янв
|
||||
2 фев
|
||||
3 мар
|
||||
4 апр
|
||||
5 май
|
||||
6 июнь
|
||||
7 июль
|
||||
8 авг
|
||||
9 сент
|
||||
10 окт
|
||||
11 нояб
|
||||
12 дек
|
||||
01 янв
|
||||
02 фев
|
||||
03 мар
|
||||
04 апр
|
||||
05 май
|
||||
06 июнь
|
||||
07 июль
|
||||
08 авг
|
||||
09 сент
|
||||
|
@@ -0,0 +1,50 @@
|
||||
0 ноль
|
||||
1 один
|
||||
1 одна
|
||||
1 одно
|
||||
1 одни
|
||||
2 два
|
||||
2 две
|
||||
3 три
|
||||
4 четыре
|
||||
5 пять
|
||||
6 шесть
|
||||
7 семь
|
||||
8 восемь
|
||||
9 девять
|
||||
10 десять
|
||||
11 одиннадцать
|
||||
12 двенадцать
|
||||
13 тринадцать
|
||||
14 четырнадцать
|
||||
15 пятнадцать
|
||||
16 шестнадцать
|
||||
17 семнадцать
|
||||
18 восемнадцать
|
||||
19 девятнадцать
|
||||
20 двадцать
|
||||
30 тридцать
|
||||
40 сорок
|
||||
50 пятьдесят
|
||||
60 шестьдесят
|
||||
70 семьдесят
|
||||
80 восемьдесят
|
||||
90 девяносто
|
||||
100 сто
|
||||
200 двести
|
||||
300 триста
|
||||
400 четыреста
|
||||
500 пятьсот
|
||||
600 шестьсот
|
||||
700 семьсот
|
||||
800 восемьсот
|
||||
900 девятьсот
|
||||
1000 тысяч
|
||||
1000 тысяча
|
||||
1000 тысячи
|
||||
1000000 миллион
|
||||
1000000 миллиона
|
||||
1000000 миллионов
|
||||
1000000000 миллиард
|
||||
1000000000 миллиарда
|
||||
1000000000 миллиардов
|
||||
|
@@ -0,0 +1,45 @@
|
||||
0 ноля
|
||||
1 одного
|
||||
1 одной
|
||||
1 одних
|
||||
2 двух
|
||||
3 трех
|
||||
4 четырех
|
||||
5 пяти
|
||||
6 шести
|
||||
7 семи
|
||||
8 восьми
|
||||
9 девяти
|
||||
10 десяти
|
||||
11 одиннадцати
|
||||
12 двенадцати
|
||||
13 тринадцати
|
||||
14 четырнадцати
|
||||
15 пятнадцати
|
||||
16 шестнадцати
|
||||
17 семнадцати
|
||||
18 восемнадцати
|
||||
19 девятнадцати
|
||||
20 двадцати
|
||||
30 тридцати
|
||||
40 сорока
|
||||
50 пятидесяти
|
||||
60 шестидесяти
|
||||
70 семидесяти
|
||||
80 восьмидесяти
|
||||
90 девяноста
|
||||
100 ста
|
||||
200 двухсот
|
||||
300 трехсот
|
||||
400 четырехсот
|
||||
500 пятисот
|
||||
600 шестисот
|
||||
700 семисот
|
||||
800 восьмисот
|
||||
900 девятисот
|
||||
1000 тысячи
|
||||
1000 тысяч
|
||||
1000000 миллиона
|
||||
1000000 миллионов
|
||||
1000000000 миллиарда
|
||||
1000000000 миллиардов
|
||||
|
@@ -0,0 +1,45 @@
|
||||
0 нолем
|
||||
1 одним
|
||||
1 одному
|
||||
1 одной
|
||||
2 двум
|
||||
3 трем
|
||||
4 четырем
|
||||
5 пяти
|
||||
6 шести
|
||||
7 семи
|
||||
8 восьми
|
||||
9 девяти
|
||||
10 десяти
|
||||
11 одиннадцати
|
||||
12 двенадцати
|
||||
13 тринадцати
|
||||
14 четырнадцати
|
||||
15 пятнадцати
|
||||
16 шестнадцати
|
||||
17 семнадцати
|
||||
18 восемнадцати
|
||||
19 девятнадцати
|
||||
20 двадцати
|
||||
30 тридцати
|
||||
40 сорока
|
||||
50 пятидесяти
|
||||
60 шестидесяти
|
||||
70 семидесяти
|
||||
80 восьмидесяти
|
||||
90 девяноста
|
||||
100 ста
|
||||
200 двумстам
|
||||
300 тремстам
|
||||
400 четыремстам
|
||||
500 пятистам
|
||||
600 шестистам
|
||||
700 семистам
|
||||
800 восьмистам
|
||||
900 девятистам
|
||||
1000 тысяче
|
||||
1000 тысячам
|
||||
1000000 миллиону
|
||||
1000000 миллионам
|
||||
1000000000 миллиарду
|
||||
1000000000 миллиардам
|
||||
|
@@ -0,0 +1,48 @@
|
||||
0 ноль
|
||||
1 один
|
||||
1 одного
|
||||
1 одни
|
||||
1 одно
|
||||
1 одну
|
||||
2 два
|
||||
2 две
|
||||
3 трех
|
||||
4 четырех
|
||||
5 пять
|
||||
6 шесть
|
||||
7 семь
|
||||
8 восемь
|
||||
9 девять
|
||||
10 десять
|
||||
11 одиннадцать
|
||||
12 двенадцать
|
||||
13 тринадцать
|
||||
14 четырнадцать
|
||||
15 пятнадцать
|
||||
16 шестнадцать
|
||||
17 семнадцать
|
||||
18 восемнадцать
|
||||
19 девятнадцать
|
||||
20 двадцать
|
||||
30 тридцать
|
||||
40 сорок
|
||||
50 пятьдесят
|
||||
60 шестьдесят
|
||||
70 семьдесят
|
||||
80 восемьдесят
|
||||
90 девяносто
|
||||
100 сто
|
||||
200 двести
|
||||
300 триста
|
||||
400 четыреста
|
||||
500 пятьсот
|
||||
600 шестьсот
|
||||
700 семьсот
|
||||
800 восемьсот
|
||||
900 девятьсот
|
||||
1000 тысячи
|
||||
1000 тысячу
|
||||
1000000 миллион
|
||||
1000000 миллионы
|
||||
1000000000 миллиард
|
||||
1000000000 миллиарды
|
||||
|
@@ -0,0 +1,47 @@
|
||||
0 нолем
|
||||
1 одним
|
||||
1 одними
|
||||
1 одной
|
||||
1 одною
|
||||
1 одну
|
||||
2 двумя
|
||||
3 тремя
|
||||
4 четырьмя
|
||||
5 пятью
|
||||
6 шестью
|
||||
7 семью
|
||||
8 восемью
|
||||
8 восьмью
|
||||
9 девятью
|
||||
10 десятью
|
||||
11 одиннадцатью
|
||||
12 двенадцатью
|
||||
13 тринадцатью
|
||||
14 четырнадцатью
|
||||
15 пятнадцатью
|
||||
16 шестнадцатью
|
||||
17 семнадцатью
|
||||
18 восемнадцатью
|
||||
19 девятнадцатью
|
||||
20 двадцатью
|
||||
30 тридцатью
|
||||
40 сорока
|
||||
50 пятьюдесятью
|
||||
60 шестьюдесятью
|
||||
70 семьюдесятью
|
||||
80 восьмьюдесятью
|
||||
90 девяноста
|
||||
100 ста
|
||||
200 двумястами
|
||||
300 тремястами
|
||||
400 четырьмястами
|
||||
500 пятьюстами
|
||||
600 шестьюстами
|
||||
700 семьюстами
|
||||
800 восемьюстами
|
||||
900 девятьюстами
|
||||
1000000 миллионами
|
||||
1000000 миллионом
|
||||
1000000 миллиону
|
||||
1000000 миллионы
|
||||
1000000000 миллиардом
|
||||
|
@@ -0,0 +1,46 @@
|
||||
0 ноле
|
||||
0 нуле
|
||||
1 одной
|
||||
1 одном
|
||||
2 двух
|
||||
3 трех
|
||||
4 четырех
|
||||
5 пяти
|
||||
6 шести
|
||||
7 семи
|
||||
8 восьми
|
||||
9 девяти
|
||||
10 десяти
|
||||
11 одиннадцати
|
||||
12 двенадцати
|
||||
13 тринадцати
|
||||
14 четырнадцати
|
||||
15 пятнадцати
|
||||
16 шестнадцати
|
||||
17 семнадцати
|
||||
18 восемнадцати
|
||||
19 девятнадцати
|
||||
20 двадцати
|
||||
30 тридцати
|
||||
40 сорока
|
||||
50 пятидесяти
|
||||
60 шестидесяти
|
||||
70 семидесяти
|
||||
90 девяноста
|
||||
100 ста
|
||||
200 двухстах
|
||||
300 трехстах
|
||||
400 четырехстах
|
||||
500 пятистах
|
||||
600 шестистах
|
||||
700 семистах
|
||||
800 восьмистах
|
||||
900 девятистах
|
||||
900 девятьсот
|
||||
900 девятьюстами
|
||||
1000 тысячах
|
||||
1000 тысяче
|
||||
1000000 миллионах
|
||||
1000000 миллионе
|
||||
1000000000 миллиардах
|
||||
1000000000 миллиарде
|
||||
|
@@ -0,0 +1,16 @@
|
||||
1т одна тысяча
|
||||
1т одной тысячи
|
||||
1т одной тысяче
|
||||
1т одну тысячу
|
||||
1т одной тысячей
|
||||
1т одной тысяче
|
||||
1млн один миллион
|
||||
1млн одного миллиона
|
||||
1млн одному миллиону
|
||||
1млн одним миллионом
|
||||
1млн одном миллионе
|
||||
1млрд один миллиард
|
||||
1млрд одного миллиарда
|
||||
1млрд одному миллиарду
|
||||
1млрд одним миллиардом
|
||||
1млрд одном миллиарде
|
||||
|
@@ -0,0 +1,37 @@
|
||||
0 ноль
|
||||
1 один
|
||||
2 два
|
||||
3 три
|
||||
4 четыре
|
||||
5 пять
|
||||
6 шесть
|
||||
7 семь
|
||||
8 восемь
|
||||
9 девять
|
||||
10 десять
|
||||
11 одиннадцать
|
||||
12 двенадцать
|
||||
13 тринадцать
|
||||
14 четырнадцать
|
||||
15 пятнадцать
|
||||
16 шестнадцать
|
||||
17 семнадцать
|
||||
18 восемнадцать
|
||||
19 девятнадцать
|
||||
20 двадцать
|
||||
30 тридцать
|
||||
40 сорок
|
||||
50 пятьдесят
|
||||
60 шестьдесят
|
||||
70 семьдесят
|
||||
80 восемьдесят
|
||||
90 девяносто
|
||||
100 сто
|
||||
200 двести
|
||||
300 триста
|
||||
400 четыреста
|
||||
500 пятьсот
|
||||
600 шестьсот
|
||||
700 семьсот
|
||||
800 восемьсот
|
||||
900 девятьсот
|
||||
|
@@ -0,0 +1,15 @@
|
||||
@@decimal_delimiter@@ целого 0.1
|
||||
@@decimal_delimiter@@ целому 0.1
|
||||
@@decimal_delimiter@@ целый 0.1
|
||||
@@decimal_delimiter@@ целого 0.1
|
||||
@@decimal_delimiter@@ целым 0.1
|
||||
@@decimal_delimiter@@ целом 0.1
|
||||
@@decimal_delimiter@@ целая -0.1
|
||||
@@decimal_delimiter@@ целой 0.1
|
||||
@@decimal_delimiter@@ целую 0.1
|
||||
@@decimal_delimiter@@ целою 0.1
|
||||
@@decimal_delimiter@@ целые -0.1
|
||||
@@decimal_delimiter@@ целых -0.1
|
||||
@@decimal_delimiter@@ целым 0.1
|
||||
@@decimal_delimiter@@ целые 0.1
|
||||
@@decimal_delimiter@@ целыми 0.1
|
||||
|
@@ -0,0 +1,37 @@
|
||||
10 десятая -0.1
|
||||
10 десятой 0.1
|
||||
10 десятой 0.1
|
||||
10 десятую 0.1
|
||||
10 десятою 0.1
|
||||
10 десятой 0.1
|
||||
10 десятые 0.1
|
||||
10 десятых -0.1
|
||||
10 десятым 0.1
|
||||
10 десятыми 0.1
|
||||
100 сотые -0.1
|
||||
100 сотых -0.1
|
||||
100 сотым 0.1
|
||||
100 сотыми 0.1
|
||||
100 сотая -0.1
|
||||
100 сотой 0.1
|
||||
100 сотую 0.1
|
||||
100 сотою 0.1
|
||||
1000 тысячные -0.1
|
||||
1000 тысячных -0.1
|
||||
1000 тысячным 0.1
|
||||
1000 тысячными 0.1
|
||||
1000 тысячная -0.1
|
||||
1000 тысячной 0.1
|
||||
1000 тысячную 0.1
|
||||
1000 тысячною 0.1
|
||||
10000 десятитысячная -0.1
|
||||
10000 десятитысячной 0.1
|
||||
10000 десятитысячной 0.1
|
||||
10000 десятитысячную 0.1
|
||||
10000 десятитысячною 0.1
|
||||
10000 десятитысячной 0.1
|
||||
10000 десятитысячные 0.1
|
||||
10000 десятитысячных -0.1
|
||||
10000 десятитысячным 0.1
|
||||
10000 десятитысячные 0.1
|
||||
10000 десятитысячными 0.1
|
||||
|
@@ -0,0 +1,10 @@
|
||||
0 ноль
|
||||
1 один
|
||||
2 два
|
||||
3 три
|
||||
4 четыре
|
||||
5 пять
|
||||
6 шесть
|
||||
7 семь
|
||||
8 восемь
|
||||
9 девять
|
||||
|
@@ -0,0 +1,40 @@
|
||||
ая-ая
|
||||
ого-го
|
||||
ьего-го
|
||||
ьего-его
|
||||
ьей-ей
|
||||
ьему-ему
|
||||
ьем-ем
|
||||
ое-е
|
||||
ые-е
|
||||
ье-е
|
||||
ий-ий
|
||||
ьими-ими
|
||||
ьим-им
|
||||
ьих-их
|
||||
ьи-и
|
||||
ий-й
|
||||
ой-й
|
||||
ый-й
|
||||
ыми-ми
|
||||
ьими-ми
|
||||
ому-му
|
||||
ьему-му
|
||||
ого-ого
|
||||
ое-ое
|
||||
ой-ой
|
||||
ом-ом
|
||||
ому-ому
|
||||
ую-ую
|
||||
ых-х
|
||||
ьих-х
|
||||
ые-ые
|
||||
ый-ый
|
||||
ыми-ыми
|
||||
ым-ым
|
||||
ых-ых
|
||||
ую-ю
|
||||
ью-ю
|
||||
ая-я
|
||||
ья-я
|
||||
ом-м
|
||||
|
@@ -0,0 +1,752 @@
|
||||
0 нулевая 0.1
|
||||
0 нулевого 0.1
|
||||
0 нулевое 0.1
|
||||
0 нулевой 0.1
|
||||
0 нулевом 0.1
|
||||
0 нулевому 0.1
|
||||
0 нулевую 0.1
|
||||
0 нулевые -0.01
|
||||
0 нулевым 0.1
|
||||
0 нулевыми 0.1
|
||||
0 нулевых 0.1
|
||||
1 первая -0.01
|
||||
1 первого -0.01
|
||||
1 первое -0.01
|
||||
1 первой 0.1
|
||||
1 первом 0.1
|
||||
1 первому 0.1
|
||||
1 первую 0.1
|
||||
1 первые 0.1
|
||||
1 первый -0.01
|
||||
1 первым 0.1
|
||||
1 первыми 0.1
|
||||
1 первых 0.1
|
||||
2 вторая -0.01
|
||||
2 второго 0.1
|
||||
2 второе -0.01
|
||||
2 второй -0.01
|
||||
2 втором 0.1
|
||||
2 второму 0.1
|
||||
2 вторую 0.1
|
||||
2 вторые 0.1
|
||||
2 вторым 0.1
|
||||
2 вторыми 0.1
|
||||
2 вторых 0.1
|
||||
3 третий
|
||||
3 третье
|
||||
3 третьего
|
||||
3 третьей
|
||||
3 третьем
|
||||
3 третьему
|
||||
3 третьи
|
||||
3 третьим
|
||||
3 третьим
|
||||
3 третьими
|
||||
3 третьих
|
||||
3 третью
|
||||
3 третья
|
||||
4 четвертая
|
||||
4 четвертого
|
||||
4 четвертое
|
||||
4 четвертой
|
||||
4 четвертом
|
||||
4 четвертому
|
||||
4 четвертую
|
||||
4 четвертые
|
||||
4 четвертый
|
||||
4 четвертым
|
||||
4 четвертым
|
||||
4 четвертыми
|
||||
4 четвертых
|
||||
4 четвертая
|
||||
4 четвертого
|
||||
4 четвертое
|
||||
4 четвертой
|
||||
4 четвертом
|
||||
4 четвертому
|
||||
4 четвертую
|
||||
4 четвертые
|
||||
4 четвертый
|
||||
4 четвертым
|
||||
4 четвертым
|
||||
4 четвертыми
|
||||
4 четвертых
|
||||
5 пятая
|
||||
5 пятого
|
||||
5 пятое
|
||||
5 пятой
|
||||
5 пятом
|
||||
5 пятому
|
||||
5 пятую
|
||||
5 пятые
|
||||
5 пятый
|
||||
5 пятым
|
||||
5 пятым
|
||||
5 пятыми
|
||||
5 пятых
|
||||
6 шестая
|
||||
6 шестого
|
||||
6 шестое
|
||||
6 шестой
|
||||
6 шестом
|
||||
6 шестому
|
||||
6 шестую
|
||||
6 шестые
|
||||
6 шестым
|
||||
6 шестым
|
||||
6 шестыми
|
||||
6 шестых
|
||||
7 седьмая
|
||||
7 седьмого
|
||||
7 седьмое
|
||||
7 седьмой
|
||||
7 седьмом
|
||||
7 седьмому
|
||||
7 седьмую
|
||||
7 седьмые
|
||||
7 седьмым
|
||||
7 седьмым
|
||||
7 седьмыми
|
||||
7 седьмых
|
||||
8 восьмая
|
||||
8 восьмого
|
||||
8 восьмое
|
||||
8 восьмой
|
||||
8 восьмом
|
||||
8 восьмому
|
||||
8 восьмую
|
||||
8 восьмые
|
||||
8 восьмым
|
||||
8 восьмым
|
||||
8 восьмыми
|
||||
8 восьмых
|
||||
9 девятая
|
||||
9 девятого
|
||||
9 девятое
|
||||
9 девятой
|
||||
9 девятом
|
||||
9 девятому
|
||||
9 девятую
|
||||
9 девятые
|
||||
9 девятый
|
||||
9 девятым
|
||||
9 девятым
|
||||
9 девятыми
|
||||
9 девятых
|
||||
10 десятая
|
||||
10 десятого
|
||||
10 десятое
|
||||
10 десятой
|
||||
10 десятом
|
||||
10 десятому
|
||||
10 десятую
|
||||
10 десятые
|
||||
10 десятый
|
||||
10 десятым
|
||||
10 десятым
|
||||
10 десятыми
|
||||
10 десятых
|
||||
11 одиннадцатая
|
||||
11 одиннадцатого
|
||||
11 одиннадцатое
|
||||
11 одиннадцатой
|
||||
11 одиннадцатом
|
||||
11 одиннадцатому
|
||||
11 одиннадцатую
|
||||
11 одиннадцатые
|
||||
11 одиннадцатый
|
||||
11 одиннадцатым
|
||||
11 одиннадцатым
|
||||
11 одиннадцатыми
|
||||
11 одиннадцатых
|
||||
12 двенадцатая
|
||||
12 двенадцатого
|
||||
12 двенадцатое
|
||||
12 двенадцатой
|
||||
12 двенадцатом
|
||||
12 двенадцатому
|
||||
12 двенадцатую
|
||||
12 двенадцатые
|
||||
12 двенадцатый
|
||||
12 двенадцатым
|
||||
12 двенадцатым
|
||||
12 двенадцатыми
|
||||
12 двенадцатых
|
||||
13 тринадцатая
|
||||
13 тринадцатого
|
||||
13 тринадцатое
|
||||
13 тринадцатой
|
||||
13 тринадцатом
|
||||
13 тринадцатому
|
||||
13 тринадцатую
|
||||
13 тринадцатые
|
||||
13 тринадцатый
|
||||
13 тринадцатым
|
||||
13 тринадцатым
|
||||
13 тринадцатыми
|
||||
13 тринадцатых
|
||||
14 четырнадцатая
|
||||
14 четырнадцатого
|
||||
14 четырнадцатое
|
||||
14 четырнадцатой
|
||||
14 четырнадцатом
|
||||
14 четырнадцатому
|
||||
14 четырнадцатую
|
||||
14 четырнадцатые
|
||||
14 четырнадцатый
|
||||
14 четырнадцатым
|
||||
14 четырнадцатым
|
||||
14 четырнадцатыми
|
||||
14 четырнадцатых
|
||||
15 пятнадцатая
|
||||
15 пятнадцатого
|
||||
15 пятнадцатое
|
||||
15 пятнадцатой
|
||||
15 пятнадцатом
|
||||
15 пятнадцатому
|
||||
15 пятнадцатую
|
||||
15 пятнадцатые
|
||||
15 пятнадцатый
|
||||
15 пятнадцатым
|
||||
15 пятнадцатым
|
||||
15 пятнадцатыми
|
||||
15 пятнадцатых
|
||||
16 шестнадцатая
|
||||
16 шестнадцатого
|
||||
16 шестнадцатое
|
||||
16 шестнадцатой
|
||||
16 шестнадцатом
|
||||
16 шестнадцатому
|
||||
16 шестнадцатую
|
||||
16 шестнадцатые
|
||||
16 шестнадцатый
|
||||
16 шестнадцатым
|
||||
16 шестнадцатым
|
||||
16 шестнадцатыми
|
||||
16 шестнадцатых
|
||||
17 семнадцатая
|
||||
17 семнадцатого
|
||||
17 семнадцатое
|
||||
17 семнадцатой
|
||||
17 семнадцатом
|
||||
17 семнадцатому
|
||||
17 семнадцатую
|
||||
17 семнадцатые
|
||||
17 семнадцатый
|
||||
17 семнадцатым
|
||||
17 семнадцатым
|
||||
17 семнадцатыми
|
||||
17 семнадцатых
|
||||
18 восемнадцатая
|
||||
18 восемнадцатого
|
||||
18 восемнадцатое
|
||||
18 восемнадцатой
|
||||
18 восемнадцатом
|
||||
18 восемнадцатому
|
||||
18 восемнадцатую
|
||||
18 восемнадцатые
|
||||
18 восемнадцатый
|
||||
18 восемнадцатым
|
||||
18 восемнадцатым
|
||||
18 восемнадцатыми
|
||||
18 восемнадцатых
|
||||
19 девятнадцатая
|
||||
19 девятнадцатого
|
||||
19 девятнадцатое
|
||||
19 девятнадцатой
|
||||
19 девятнадцатом
|
||||
19 девятнадцатому
|
||||
19 девятнадцатую
|
||||
19 девятнадцатые
|
||||
19 девятнадцатый
|
||||
19 девятнадцатым
|
||||
19 девятнадцатым
|
||||
19 девятнадцатыми
|
||||
19 девятнадцатых
|
||||
20 двадцатая
|
||||
20 двадцатого
|
||||
20 двадцатое
|
||||
20 двадцатой
|
||||
20 двадцатом
|
||||
20 двадцатому
|
||||
20 двадцатую
|
||||
20 двадцатые
|
||||
20 двадцатый
|
||||
20 двадцатым
|
||||
20 двадцатым
|
||||
20 двадцатыми
|
||||
20 двадцатых
|
||||
30 тридцатая
|
||||
30 тридцатого
|
||||
30 тридцатое
|
||||
30 тридцатой
|
||||
30 тридцатом
|
||||
30 тридцатому
|
||||
30 тридцатую
|
||||
30 тридцатые
|
||||
30 тридцатый
|
||||
30 тридцатым
|
||||
30 тридцатым
|
||||
30 тридцатыми
|
||||
30 тридцатых
|
||||
40 сороковая
|
||||
40 сорокового
|
||||
40 сороковое
|
||||
40 сороковой
|
||||
40 сороковом
|
||||
40 сороковому
|
||||
40 сороковую
|
||||
40 сороковые
|
||||
40 сороковым
|
||||
40 сороковым
|
||||
40 сороковыми
|
||||
40 сороковых
|
||||
50 пятидесятая
|
||||
50 пятидесятого
|
||||
50 пятидесятое
|
||||
50 пятидесятой
|
||||
50 пятидесятом
|
||||
50 пятидесятому
|
||||
50 пятидесятую
|
||||
50 пятидесятые
|
||||
50 пятидесятый
|
||||
50 пятидесятым
|
||||
50 пятидесятым
|
||||
50 пятидесятыми
|
||||
50 пятидесятых
|
||||
60 шестидесятая
|
||||
60 шестидесятого
|
||||
60 шестидесятое
|
||||
60 шестидесятой
|
||||
60 шестидесятом
|
||||
60 шестидесятому
|
||||
60 шестидесятую
|
||||
60 шестидесятые
|
||||
60 шестидесятый
|
||||
60 шестидесятым
|
||||
60 шестидесятым
|
||||
60 шестидесятыми
|
||||
60 шестидесятых
|
||||
70 семидесятая
|
||||
70 семидесятого
|
||||
70 семидесятое
|
||||
70 семидесятой
|
||||
70 семидесятом
|
||||
70 семидесятому
|
||||
70 семидесятую
|
||||
70 семидесятые
|
||||
70 семидесятый
|
||||
70 семидесятым
|
||||
70 семидесятым
|
||||
70 семидесятыми
|
||||
70 семидесятых
|
||||
80 восьмидесятая
|
||||
80 восьмидесятого
|
||||
80 восьмидесятое
|
||||
80 восьмидесятой
|
||||
80 восьмидесятом
|
||||
80 восьмидесятому
|
||||
80 восьмидесятую
|
||||
80 восьмидесятые
|
||||
80 восьмидесятый
|
||||
80 восьмидесятым
|
||||
80 восьмидесятым
|
||||
80 восьмидесятыми
|
||||
80 восьмидесятых
|
||||
90 девяностая
|
||||
90 девяностого
|
||||
90 девяностое
|
||||
90 девяностой
|
||||
90 девяностом
|
||||
90 девяностому
|
||||
90 девяностую
|
||||
90 девяностые
|
||||
90 девяностый
|
||||
90 девяностым
|
||||
90 девяностым
|
||||
90 девяностыми
|
||||
90 девяностых
|
||||
100 сотая
|
||||
100 сотого
|
||||
100 сотое
|
||||
100 сотой
|
||||
100 сотом
|
||||
100 сотому
|
||||
100 сотую
|
||||
100 сотые
|
||||
100 сотый
|
||||
100 сотым
|
||||
100 сотым
|
||||
100 сотыми
|
||||
100 сотых
|
||||
200 двухсотая
|
||||
200 двухсотого
|
||||
200 двухсотое
|
||||
200 двухсотой
|
||||
200 двухсотом
|
||||
200 двухсотому
|
||||
200 двухсотую
|
||||
200 двухсотые
|
||||
200 двухсотый
|
||||
200 двухсотым
|
||||
200 двухсотым
|
||||
200 двухсотыми
|
||||
200 двухсотых
|
||||
300 трехсотая
|
||||
300 трехсотого
|
||||
300 трехсотое
|
||||
300 трехсотой
|
||||
300 трехсотом
|
||||
300 трехсотому
|
||||
300 трехсотую
|
||||
300 трехсотые
|
||||
300 трехсотый
|
||||
300 трехсотым
|
||||
300 трехсотым
|
||||
300 трехсотыми
|
||||
300 трехсотых
|
||||
400 четырехсотая
|
||||
400 четырехсотого
|
||||
400 четырехсотое
|
||||
400 четырехсотой
|
||||
400 четырехсотом
|
||||
400 четырехсотому
|
||||
400 четырехсотую
|
||||
400 четырехсотые
|
||||
400 четырехсотый
|
||||
400 четырехсотым
|
||||
400 четырехсотым
|
||||
400 четырехсотыми
|
||||
400 четырехсотых
|
||||
500 пятисотая
|
||||
500 пятисотого
|
||||
500 пятисотое
|
||||
500 пятисотой
|
||||
500 пятисотом
|
||||
500 пятисотому
|
||||
500 пятисотую
|
||||
500 пятисотые
|
||||
500 пятисотый
|
||||
500 пятисотым
|
||||
500 пятисотым
|
||||
500 пятисотыми
|
||||
500 пятисотых
|
||||
600 шестисотая
|
||||
600 шестисотого
|
||||
600 шестисотое
|
||||
600 шестисотой
|
||||
600 шестисотом
|
||||
600 шестисотому
|
||||
600 шестисотую
|
||||
600 шестисотые
|
||||
600 шестисотый
|
||||
600 шестисотым
|
||||
600 шестисотым
|
||||
600 шестисотыми
|
||||
600 шестисотых
|
||||
700 семисотая
|
||||
700 семисотого
|
||||
700 семисотое
|
||||
700 семисотой
|
||||
700 семисотом
|
||||
700 семисотому
|
||||
700 семисотую
|
||||
700 семисотые
|
||||
700 семисотый
|
||||
700 семисотым
|
||||
700 семисотым
|
||||
700 семисотыми
|
||||
700 семисотых
|
||||
800 восьмисотая
|
||||
800 восьмисотого
|
||||
800 восьмисотое
|
||||
800 восьмисотой
|
||||
800 восьмисотом
|
||||
800 восьмисотому
|
||||
800 восьмисотую
|
||||
800 восьмисотые
|
||||
800 восьмисотый
|
||||
800 восьмисотым
|
||||
800 восьмисотым
|
||||
800 восьмисотыми
|
||||
800 восьмисотых
|
||||
900 девятисотая
|
||||
900 девятисотого
|
||||
900 девятисотое
|
||||
900 девятисотой
|
||||
900 девятисотом
|
||||
900 девятисотому
|
||||
900 девятисотую
|
||||
900 девятисотые
|
||||
900 девятисотый
|
||||
900 девятисотым
|
||||
900 девятисотым
|
||||
900 девятисотыми
|
||||
900 девятисотых
|
||||
1000 тысячная
|
||||
1000 тысячного
|
||||
1000 тысячное
|
||||
1000 тысячной
|
||||
1000 тысячном
|
||||
1000 тысячному
|
||||
1000 тысячную
|
||||
1000 тысячные
|
||||
1000 тысячный
|
||||
1000 тысячным
|
||||
1000 тысячным
|
||||
1000 тысячными
|
||||
1000 тысячных
|
||||
1000000 миллионная
|
||||
1000000 миллионного
|
||||
1000000 миллионное
|
||||
1000000 миллионной
|
||||
1000000 миллионном
|
||||
1000000 миллионному
|
||||
1000000 миллионную
|
||||
1000000 миллионные
|
||||
1000000 миллионный
|
||||
1000000 миллионным
|
||||
1000000 миллионным
|
||||
1000000 миллионными
|
||||
1000000 миллионных
|
||||
1000000000 миллиардная
|
||||
1000000000 миллиардного
|
||||
1000000000 миллиардное
|
||||
1000000000 миллиардной
|
||||
1000000000 миллиардном
|
||||
1000000000 миллиардному
|
||||
1000000000 миллиардную
|
||||
1000000000 миллиардные
|
||||
1000000000 миллиардный
|
||||
1000000000 миллиардным
|
||||
1000000000 миллиардным
|
||||
1000000000 миллиардными
|
||||
1000000000 миллиардных
|
||||
2000 двухтысячная
|
||||
2000 двухтысячных
|
||||
2000 двухтысячные
|
||||
2000 двухтысячный
|
||||
2000 двухтысячными
|
||||
2000 двухтысячному
|
||||
2000 двухтысячным
|
||||
2000 двухтысячном
|
||||
2000 двухтысячной
|
||||
2000 двухтысячного
|
||||
2000 двухтысячную
|
||||
2000 двухтысячное
|
||||
3000 трехтысячное
|
||||
3000 трехтысячных
|
||||
3000 трехтысячного
|
||||
3000 трехтысячные
|
||||
3000 трехтысячную
|
||||
3000 трехтысячная
|
||||
3000 трехтысячному
|
||||
3000 трехтысячной
|
||||
3000 трехтысячном
|
||||
3000 трехтысячный
|
||||
3000 трехтысячным
|
||||
3000 трехтысячными
|
||||
4000 четырехтысячных
|
||||
4000 четырехтысячный
|
||||
4000 четырехтысячное
|
||||
4000 четырехтысячным
|
||||
4000 четырехтысячными
|
||||
4000 четырехтысячные
|
||||
4000 четырехтысячному
|
||||
4000 четырехтысячного
|
||||
4000 четырехтысячной
|
||||
4000 четырехтысячная
|
||||
4000 четырехтысячную
|
||||
4000 четырехтысячном
|
||||
5000 пятитысячными
|
||||
5000 пятитысячные
|
||||
5000 пятитысячному
|
||||
5000 пятитысячную
|
||||
5000 пятитысячного
|
||||
5000 пятитысячной
|
||||
5000 пятитысячным
|
||||
5000 пятитысячная
|
||||
5000 пятитысячное
|
||||
5000 пятитысячных
|
||||
5000 пятитысячном
|
||||
5000 пятитысячный
|
||||
6000 шеститысячных
|
||||
6000 шеститысячным
|
||||
6000 шеститысячная
|
||||
6000 шеститысячной
|
||||
6000 шеститысячными
|
||||
6000 шеститысячные
|
||||
6000 шеститысячное
|
||||
6000 шеститысячную
|
||||
6000 шеститысячный
|
||||
6000 шеститысячному
|
||||
6000 шеститысячного
|
||||
6000 шеститысячном
|
||||
7000 семитысячную
|
||||
7000 семитысячная
|
||||
7000 семитысячном
|
||||
7000 семитысячным
|
||||
7000 семитысячного
|
||||
7000 семитысячной
|
||||
7000 семитысячный
|
||||
7000 семитысячное
|
||||
7000 семитысячных
|
||||
7000 семитысячными
|
||||
7000 семитысячные
|
||||
7000 семитысячному
|
||||
8000 восьмитысячному
|
||||
8000 восьмитысячном
|
||||
8000 восьмитысячную
|
||||
8000 восьмитысячная
|
||||
8000 восьмитысячными
|
||||
8000 восьмитысячный
|
||||
8000 восьмитысячной
|
||||
8000 восьмитысячного
|
||||
8000 восьмитысячное
|
||||
8000 восьмитысячных
|
||||
8000 восьмитысячным
|
||||
8000 восьмитысячные
|
||||
9000 девятитысячных
|
||||
9000 девятитысячная
|
||||
9000 девятитысячное
|
||||
9000 девятитысячному
|
||||
9000 девятитысячными
|
||||
9000 девятитысячного
|
||||
9000 девятитысячной
|
||||
9000 девятитысячном
|
||||
9000 девятитысячный
|
||||
9000 девятитысячные
|
||||
9000 девятитысячную
|
||||
9000 девятитысячным
|
||||
10000 десятитысячным
|
||||
10000 десятитысячное
|
||||
10000 десятитысячных
|
||||
10000 десятитысячными
|
||||
10000 десятитысячный
|
||||
10000 десятитысячная
|
||||
10000 десятитысячные
|
||||
10000 десятитысячном
|
||||
10000 десятитысячного
|
||||
10000 десятитысячному
|
||||
10000 десятитысячной
|
||||
10000 десятитысячную
|
||||
11000 одиннадцатитысячном
|
||||
11000 одиннадцатитысячное
|
||||
11000 одиннадцатитысячными
|
||||
11000 одиннадцатитысячная
|
||||
11000 одиннадцатитысячных
|
||||
11000 одиннадцатитысячной
|
||||
11000 одиннадцатитысячного
|
||||
11000 одиннадцатитысячную
|
||||
11000 одиннадцатитысячные
|
||||
11000 одиннадцатитысячный
|
||||
11000 одиннадцатитысячным
|
||||
11000 одиннадцатитысячному
|
||||
12000 двенадцатитысячного
|
||||
12000 двенадцатитысячным
|
||||
12000 двенадцатитысячной
|
||||
12000 двенадцатитысячную
|
||||
12000 двенадцатитысячный
|
||||
12000 двенадцатитысячном
|
||||
12000 двенадцатитысячными
|
||||
12000 двенадцатитысячная
|
||||
12000 двенадцатитысячному
|
||||
12000 двенадцатитысячные
|
||||
12000 двенадцатитысячное
|
||||
12000 двенадцатитысячных
|
||||
13000 тринадцатитысячных
|
||||
13000 тринадцатитысячные
|
||||
13000 тринадцатитысячной
|
||||
13000 тринадцатитысячным
|
||||
13000 тринадцатитысячное
|
||||
13000 тринадцатитысячного
|
||||
13000 тринадцатитысячная
|
||||
13000 тринадцатитысячном
|
||||
13000 тринадцатитысячными
|
||||
13000 тринадцатитысячный
|
||||
13000 тринадцатитысячную
|
||||
13000 тринадцатитысячному
|
||||
14000 четырнадцатитысячных
|
||||
14000 четырнадцатитысячном
|
||||
14000 четырнадцатитысячным
|
||||
14000 четырнадцатитысячной
|
||||
14000 четырнадцатитысячному
|
||||
14000 четырнадцатитысячная
|
||||
14000 четырнадцатитысячными
|
||||
14000 четырнадцатитысячный
|
||||
14000 четырнадцатитысячные
|
||||
14000 четырнадцатитысячную
|
||||
14000 четырнадцатитысячного
|
||||
14000 четырнадцатитысячное
|
||||
15000 пятнадцатитысячное
|
||||
15000 пятнадцатитысячных
|
||||
15000 пятнадцатитысячный
|
||||
15000 пятнадцатитысячной
|
||||
15000 пятнадцатитысячную
|
||||
15000 пятнадцатитысячном
|
||||
15000 пятнадцатитысячным
|
||||
15000 пятнадцатитысячными
|
||||
15000 пятнадцатитысячные
|
||||
15000 пятнадцатитысячному
|
||||
15000 пятнадцатитысячная
|
||||
15000 пятнадцатитысячного
|
||||
16000 шестнадцатитысячному
|
||||
16000 шестнадцатитысячным
|
||||
16000 шестнадцатитысячные
|
||||
16000 шестнадцатитысячное
|
||||
16000 шестнадцатитысячный
|
||||
16000 шестнадцатитысячными
|
||||
16000 шестнадцатитысячном
|
||||
16000 шестнадцатитысячного
|
||||
16000 шестнадцатитысячной
|
||||
16000 шестнадцатитысячных
|
||||
16000 шестнадцатитысячная
|
||||
16000 шестнадцатитысячную
|
||||
17000 семнадцатитысячного
|
||||
17000 семнадцатитысячный
|
||||
17000 семнадцатитысячное
|
||||
17000 семнадцатитысячному
|
||||
17000 семнадцатитысячную
|
||||
17000 семнадцатитысячная
|
||||
17000 семнадцатитысячной
|
||||
17000 семнадцатитысячными
|
||||
17000 семнадцатитысячным
|
||||
17000 семнадцатитысячном
|
||||
17000 семнадцатитысячные
|
||||
17000 семнадцатитысячных
|
||||
18000 восемнадцатитысячные
|
||||
18000 восемнадцатитысячным
|
||||
18000 восемнадцатитысячный
|
||||
18000 восемнадцатитысячного
|
||||
18000 восемнадцатитысячному
|
||||
18000 восемнадцатитысячными
|
||||
18000 восемнадцатитысячное
|
||||
18000 восемнадцатитысячном
|
||||
18000 восемнадцатитысячных
|
||||
18000 восемнадцатитысячной
|
||||
18000 восемнадцатитысячную
|
||||
18000 восемнадцатитысячная
|
||||
19000 девятнадцатитысячных
|
||||
19000 девятнадцатитысячного
|
||||
19000 девятнадцатитысячному
|
||||
19000 девятнадцатитысячный
|
||||
19000 девятнадцатитысячным
|
||||
19000 девятнадцатитысячные
|
||||
19000 девятнадцатитысячной
|
||||
19000 девятнадцатитысячными
|
||||
19000 девятнадцатитысячном
|
||||
19000 девятнадцатитысячную
|
||||
19000 девятнадцатитысячная
|
||||
19000 девятнадцатитысячное
|
||||
20000 двадцатитысячном
|
||||
20000 двадцатитысячной
|
||||
20000 двадцатитысячная
|
||||
20000 двадцатитысячным
|
||||
20000 двадцатитысячными
|
||||
20000 двадцатитысячный
|
||||
20000 двадцатитысячного
|
||||
20000 двадцатитысячному
|
||||
20000 двадцатитысячное
|
||||
20000 двадцатитысячные
|
||||
20000 двадцатитысячных
|
||||
20000 двадцатитысячную
|
||||
|
@@ -0,0 +1,16 @@
|
||||
тысяч тысяч 0.1
|
||||
тысяча тысяча 0.1
|
||||
тысячи тысячи 0.1
|
||||
тыс. тысячи 0.1
|
||||
тыс тысячи -0.1
|
||||
миллион миллион 0.1
|
||||
миллионов миллионов 0.1
|
||||
миллиона миллиона 0.1
|
||||
миллиона миллиона 0.1
|
||||
млн. миллиона 0.1
|
||||
млн миллиона -0.1
|
||||
миллиарда миллиарда 0.1
|
||||
миллиард миллиард 0.1
|
||||
миллиардов миллиардов 0.1
|
||||
млрд. миллиарда 0.1
|
||||
млрд миллиарда -0.1
|
||||
|
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
00 час -0.1
|
||||
01 два -0.1
|
||||
02 три -0.1
|
||||
03 четыре -0.1
|
||||
04 пять -0.1
|
||||
05 шесть -0.1
|
||||
06 семь -0.1
|
||||
07 восемь -0.1
|
||||
08 девять -0.1
|
||||
09 десять -0.1
|
||||
10 одиннадцать 0.1
|
||||
11 двенадцать 0.1
|
||||
12 час 0.1
|
||||
13 два 0.1
|
||||
14 три 0.1
|
||||
15 четыре 0.1
|
||||
16 пять 0.1
|
||||
17 шесть 0.1
|
||||
18 семь 0.1
|
||||
19 восемь 0.1
|
||||
20 девять 0.1
|
||||
21 десять 0.1
|
||||
22 одиннадцать 0.1
|
||||
23 двенадцать 0.1
|
||||
|
@@ -0,0 +1,24 @@
|
||||
00 первого 0.1
|
||||
01 второго -0.1
|
||||
02 третьего -0.1
|
||||
03 четвертого -0.1
|
||||
04 пятого -0.1
|
||||
05 шестого -0.1
|
||||
06 седьмого -0.1
|
||||
07 восьмого -0.1
|
||||
08 девятого -0.1
|
||||
09 десятого -0.1
|
||||
10 одиннадцатого -0.1
|
||||
11 двенадцатого -0.1
|
||||
12 первого -0.1
|
||||
13 второго 0.1
|
||||
14 третьего 0.1
|
||||
15 четвертого 0.1
|
||||
16 пятого 0.1
|
||||
17 шестого 0.1
|
||||
18 седьмого 0.1
|
||||
19 восьмого 0.1
|
||||
20 девятого 0.1
|
||||
21 десятого 0.1
|
||||
22 одиннадцатого 0.1
|
||||
23 двенадцатого 0.1
|
||||
|
@@ -0,0 +1,25 @@
|
||||
59 одной минуты
|
||||
58 двух минут
|
||||
57 трех минут
|
||||
56 четырех минут
|
||||
55 пяти минут
|
||||
54 шести минут
|
||||
53 семи минут
|
||||
52 восеми минут
|
||||
51 девяти минут
|
||||
50 десяти минут
|
||||
49 одиннадцати минут
|
||||
48 двенадцати минут
|
||||
47 тринадцати минут
|
||||
46 четырнадцати минут
|
||||
45 пятнадцати минут
|
||||
44 шестнадцати минут
|
||||
43 семнадцати минут
|
||||
42 восемьнадцати минут
|
||||
41 девятнадцати минут
|
||||
40 двадцати минут
|
||||
39 двадцати одной минуты
|
||||
38 двадцати двух минут
|
||||
37 двадцати трех минут
|
||||
36 двадцати четырех минут
|
||||
35 двадцать пяти минут
|
||||
|
@@ -0,0 +1,12 @@
|
||||
13 1
|
||||
14 2
|
||||
15 3
|
||||
16 4
|
||||
17 5
|
||||
18 6
|
||||
19 7
|
||||
20 8
|
||||
21 9
|
||||
22 10
|
||||
23 11
|
||||
24 12
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
гг. годы
|
||||
г. год
|
||||
г. году
|
||||
г. год
|
||||
г. года
|
||||
г. годом
|
||||
г. годе
|
||||
§ параграф
|
||||
комн. комнатная
|
||||
эт. этажный
|
||||
кв. квартира
|
||||
кв. квартал
|
||||
кв. квартала
|
||||
кв. кварталу
|
||||
кв. кварталом
|
||||
кв. квартале
|
||||
ЖК женская консультация
|
||||
ЖК жидкие кристаллы
|
||||
ЖК жилой комплекс
|
||||
ЖК жилищный кооператив
|
||||
ЖК жилищный кодекс
|
||||
р-н район
|
||||
до н. э. до нашей эры
|
||||
н. э. нашей эры
|
||||
см. также смотри также
|
||||
с.ш. северной широты
|
||||
ю.ш. южной широты
|
||||
в.д. восточной долготы
|
||||
з.д. западной долготы
|
||||
и т. д. и так далее
|
||||
и т. п. и тому подобное
|
||||
б/у бывший в употреблении
|
||||
экз. экземпляр
|
||||
экз. экземпляры
|
||||
и др. и другие
|
||||
и пр. и прочие
|
||||
т.е. то есть
|
||||
|
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
|
||||
|
||||
# Adapted from https://github.com/google/TextNormalizationCoveringGrammars
|
||||
# Russian minimally supervised number grammar.
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
DAMO_SIGMA,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA, TO_CYRILLIC
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class CardinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying cardinals, e.g.
|
||||
"1 001" -> cardinal { integer: "тысяча один" }
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
alternative_formats: alternative number formats
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, number_names: dict, alternative_formats: dict, deterministic: bool = False):
|
||||
super().__init__(name="cardinal", kind="classify", deterministic=deterministic)
|
||||
|
||||
self.cardinal_numbers_default = self.get_cardinal_numbers(
|
||||
number_names, alternative_formats, mode="all"
|
||||
)
|
||||
self.cardinal_numbers_nominative = self.get_cardinal_numbers(
|
||||
number_names, alternative_formats, mode="nominative"
|
||||
)
|
||||
self.optional_graph_negative = pynini.closure(
|
||||
pynutil.insert("negative: ") + pynini.cross("-", '"true"') + insert_space, 0, 1
|
||||
)
|
||||
|
||||
self.cardinal_numbers_with_optional_negative = (
|
||||
self.optional_graph_negative
|
||||
+ pynutil.insert('integer: "')
|
||||
+ self.cardinal_numbers_default
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
# "03" -> remove leading zeros and verbalize
|
||||
leading_zeros = pynini.closure(pynini.cross("0", ""))
|
||||
self.cardinal_numbers_with_leading_zeros = (
|
||||
leading_zeros + self.cardinal_numbers_default
|
||||
).optimize()
|
||||
|
||||
# "123" -> "один два три"
|
||||
single_digits_graph = pynini.string_file(
|
||||
get_abs_path("data/numbers/cardinals_nominative_case.tsv")
|
||||
).optimize()
|
||||
single_digits_graph = pynini.compose(DAMO_DIGIT, single_digits_graph)
|
||||
self.single_digits_graph = single_digits_graph + pynini.closure(
|
||||
insert_space + single_digits_graph
|
||||
)
|
||||
|
||||
optional_quantity = pynini.string_file(get_abs_path("data/numbers/quantity.tsv")).optimize()
|
||||
optional_quantity = pynutil.insert('quantity: "') + optional_quantity + pynutil.insert('"')
|
||||
optional_quantity = pynini.closure(
|
||||
(pynutil.add_weight(pynini.accep(DAMO_SPACE), -0.1) | insert_space) + optional_quantity,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
serial_graph = self.get_serial_graph()
|
||||
|
||||
final_graph = (
|
||||
self.optional_graph_negative
|
||||
+ pynutil.insert('integer: "')
|
||||
+ self.cardinal_numbers_with_leading_zeros
|
||||
+ pynutil.insert('"')
|
||||
+ optional_quantity
|
||||
).optimize()
|
||||
|
||||
final_graph = pynutil.add_weight(final_graph, -0.1)
|
||||
final_graph |= (
|
||||
pynutil.insert('integer: "')
|
||||
+ pynutil.add_weight(serial_graph, 10)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
self.final_graph = final_graph
|
||||
|
||||
# to cover cases "2-х" -> "двух" (this is not covered by ordinal endings)
|
||||
final_graph |= pynini.compose(
|
||||
pynini.compose(DAMO_DIGIT ** (1, ...) + pynini.cross("-х", ""), final_graph),
|
||||
DAMO_SIGMA + pynini.accep('х"') + DAMO_SIGMA,
|
||||
)
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
|
||||
def get_cardinal_numbers(
|
||||
self, number_names: dict, alternative_formats: dict, mode: str = "all"
|
||||
):
|
||||
"""Returns cardinal numbers names graph.
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
alternative_formats: alternative number formats
|
||||
mode: "all" - to return graph that includes all Ru cases, "nominative" to return only the nominative form
|
||||
"""
|
||||
if mode == "all":
|
||||
cardinal_names = number_names["cardinal_number_names"]
|
||||
elif mode == "nominative":
|
||||
cardinal_names = number_names["cardinal_names_nominative"]
|
||||
else:
|
||||
raise ValueError(f"{mode} is not supported.")
|
||||
one_thousand_alternative = alternative_formats["one_thousand_alternative"]
|
||||
separators = alternative_formats["separators"]
|
||||
|
||||
cardinal_numbers = cardinal_names | pynini.compose(cardinal_names, one_thousand_alternative)
|
||||
cardinal_numbers = pynini.compose(separators, cardinal_numbers)
|
||||
return cardinal_numbers
|
||||
|
||||
def get_serial_graph(self):
|
||||
"""
|
||||
Finite state transducer for classifying serial.
|
||||
The serial is a combination of digits, letters and dashes, e.g.:
|
||||
c325-b -> tokens { cardinal { integer: "си три два пять би" } }
|
||||
"""
|
||||
num_graph = self.single_digits_graph
|
||||
|
||||
alpha = TO_CYRILLIC | RU_ALPHA
|
||||
|
||||
delimiter = insert_space | pynini.cross("-", " ") | pynini.cross("/", " ")
|
||||
letter_num = pynini.closure(alpha + delimiter, 1) + num_graph
|
||||
num_letter = pynini.closure(num_graph + delimiter, 1) + alpha
|
||||
num_delimiter_num = pynini.closure(num_graph + delimiter, 1) + num_graph
|
||||
next_alpha_or_num = pynini.closure(delimiter + (alpha | num_graph))
|
||||
serial_graph = (letter_num | num_letter | num_delimiter_num) + next_alpha_or_num
|
||||
|
||||
# at least 1 alpha and 1 digit is present
|
||||
at_least_one_alpha_num = (
|
||||
DAMO_SIGMA
|
||||
+ (RU_ALPHA | pynini.project(TO_CYRILLIC, "input"))
|
||||
+ DAMO_SIGMA
|
||||
+ DAMO_DIGIT
|
||||
+ DAMO_SIGMA
|
||||
) | (
|
||||
DAMO_SIGMA
|
||||
+ DAMO_DIGIT
|
||||
+ DAMO_SIGMA
|
||||
+ (RU_ALPHA | pynini.project(TO_CYRILLIC, "input"))
|
||||
+ DAMO_SIGMA
|
||||
)
|
||||
serial_graph = pynini.compose(at_least_one_alpha_num, serial_graph.optimize()).optimize()
|
||||
# numbers only with 2+ delimiters
|
||||
serial_graph |= (
|
||||
num_graph
|
||||
+ delimiter
|
||||
+ num_graph
|
||||
+ delimiter
|
||||
+ num_graph
|
||||
+ pynini.closure(delimiter + num_graph)
|
||||
).optimize()
|
||||
return serial_graph.optimize()
|
||||
@@ -0,0 +1,139 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DateFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying date, e.g.
|
||||
"01.05" -> tokens { date { day: "первое мая" } }
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, number_names: dict, deterministic: bool):
|
||||
super().__init__(name="date", kind="classify", deterministic=deterministic)
|
||||
|
||||
# Ru format: DD-MM-YYYY or DD-MM-YY
|
||||
month_abbr_to_names = pynini.string_file(
|
||||
get_abs_path("data/months/abbr_to_name.tsv")
|
||||
).optimize()
|
||||
|
||||
delete_sep = pynutil.add_weight(pynini.cross(".", " "), 1.09) | pynutil.add_weight(
|
||||
pynini.cross(pynini.union("/", "-"), " "), 1.1
|
||||
)
|
||||
|
||||
numbers = number_names["ordinal_number_names"]
|
||||
|
||||
zero = (pynutil.add_weight(pynini.cross("0", ""), -0.1)) | (
|
||||
pynutil.add_weight(pynini.cross("0", "ноль "), 0.1)
|
||||
)
|
||||
zero_digit = zero + pynini.compose(DAMO_DIGIT, numbers)
|
||||
digit_day = (pynini.union("1", "2", "3") + DAMO_DIGIT) | DAMO_DIGIT
|
||||
digit_day = pynini.compose(digit_day, numbers)
|
||||
|
||||
day = zero_digit | digit_day
|
||||
day = pynini.compose(
|
||||
day,
|
||||
pynini.difference(DAMO_SIGMA, DAMO_SIGMA + pynini.union("ой", "ая", "ых", "ые", "ыми")),
|
||||
)
|
||||
day = (pynutil.insert('day: "') + day + pynutil.insert('"')).optimize()
|
||||
|
||||
digit_month = zero_digit | pynini.compose(pynini.accep("1") + DAMO_DIGIT, numbers)
|
||||
month_number_to_abbr = pynini.string_file(
|
||||
get_abs_path("data/months/numbers.tsv")
|
||||
).optimize()
|
||||
month_number_to_abbr = (
|
||||
(
|
||||
((pynutil.add_weight(pynini.cross("0", ""), -0.1) | pynini.accep("1")) + DAMO_DIGIT)
|
||||
| DAMO_DIGIT
|
||||
).optimize()
|
||||
@ month_number_to_abbr
|
||||
).optimize()
|
||||
|
||||
month_name = (
|
||||
(month_number_to_abbr @ month_abbr_to_names)
|
||||
| pynutil.add_weight(month_abbr_to_names, 0.1)
|
||||
).optimize()
|
||||
month = (
|
||||
pynutil.insert('month: "')
|
||||
+ (month_name | pynutil.add_weight(digit_month, 0.1))
|
||||
+ pynutil.insert('"')
|
||||
).optimize()
|
||||
year = pynini.compose(((DAMO_DIGIT**4) | (DAMO_DIGIT**2)), numbers).optimize()
|
||||
year |= zero_digit
|
||||
|
||||
# reduce year options
|
||||
year_wrong_endings = ["ую", "ая"]
|
||||
year_wrong_beginning = ["две тысяча", "два тысяч", "два тысячи", "две тысяч "]
|
||||
year = pynini.compose(
|
||||
year, pynini.difference(DAMO_SIGMA, DAMO_SIGMA + pynini.union("ой", "ого"))
|
||||
) | pynutil.add_weight(pynini.compose(year, DAMO_SIGMA + pynini.union("ой", "ого")), -0.1)
|
||||
|
||||
year_restrict1 = pynini.difference(
|
||||
DAMO_SIGMA, pynini.union(*year_wrong_beginning) + DAMO_SIGMA
|
||||
)
|
||||
year_restrict2 = pynini.difference(
|
||||
DAMO_SIGMA, DAMO_SIGMA + pynini.union(*year_wrong_endings)
|
||||
)
|
||||
year = pynini.compose(pynini.compose(year, year_restrict1), year_restrict2)
|
||||
|
||||
year_word_singular = ["год", "года", "году", "годом", "годе"]
|
||||
year_word_plural = ["годы", "годов", "годам", "годами", "годам", "годах"]
|
||||
|
||||
year_word = pynini.cross("г.", pynini.union(*year_word_singular))
|
||||
year_word |= pynini.cross("гг.", pynini.union(*year_word_plural))
|
||||
year_word = (
|
||||
pynutil.add_weight(insert_space, -0.1) | pynutil.add_weight(pynini.accep(" "), 0.1)
|
||||
) + year_word
|
||||
|
||||
year_optional = (
|
||||
pynutil.insert('year: "') + year + pynini.closure(year_word, 0, 1) + pynutil.insert('"')
|
||||
)
|
||||
year_optional = pynini.closure(delete_sep + year_optional, 0, 1).optimize()
|
||||
year_only = pynutil.insert('year: "') + year + year_word + pynutil.insert('"')
|
||||
|
||||
tagger_graph = (day + delete_sep + month + year_optional) | year_only
|
||||
|
||||
# Verbalizer
|
||||
day = (
|
||||
pynutil.delete("day:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
month = (
|
||||
pynutil.delete("month:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
year = (
|
||||
pynutil.delete("year:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
year_optional = pynini.closure(delete_extra_space + year, 0, 1)
|
||||
graph_dmy = day + delete_extra_space + month + year_optional
|
||||
verbalizer_graph = (graph_dmy | year) + delete_space
|
||||
|
||||
self.final_graph = pynini.compose(tagger_graph, verbalizer_graph).optimize()
|
||||
self.fst = pynutil.insert('day: "') + self.final_graph + pynutil.insert('"')
|
||||
self.fst = self.add_tokens(self.fst).optimize()
|
||||
@@ -0,0 +1,114 @@
|
||||
from collections import defaultdict
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.utils import load_labels
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
delete_space = pynutil.delete(" ")
|
||||
|
||||
|
||||
def prepare_labels_for_insertion(file_path: str):
|
||||
"""
|
||||
Read the file and creates a union insertion graph
|
||||
|
||||
Args:
|
||||
file_path: path to a file (3 columns: a label type e.g.
|
||||
"@@decimal_delimiter@@", a label e.g. "целого", and a weight e.g. "0.1").
|
||||
|
||||
Returns dictionary mapping from label type to an fst that inserts the labels with the specified weights.
|
||||
|
||||
"""
|
||||
labels = load_labels(file_path)
|
||||
mapping = defaultdict(list)
|
||||
for k, v, w in labels:
|
||||
mapping[k].append((v, w))
|
||||
|
||||
for k in mapping:
|
||||
mapping[k] = (
|
||||
insert_space
|
||||
+ pynini.union(
|
||||
*[pynutil.add_weight(pynutil.insert(end), weight) for end, weight in mapping[k]]
|
||||
)
|
||||
).optimize()
|
||||
return mapping
|
||||
|
||||
|
||||
class DecimalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying decimal, e.g.
|
||||
"1,08" -> tokens { decimal { integer_part: "одно целая" fractional_part: "восемь сотых} }
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst, deterministic: bool = False):
|
||||
super().__init__(name="decimal", kind="classify", deterministic=deterministic)
|
||||
|
||||
integer_part = cardinal.cardinal_numbers_default
|
||||
cardinal_numbers_with_leading_zeros = cardinal.cardinal_numbers_with_leading_zeros
|
||||
|
||||
delimiter_map = prepare_labels_for_insertion(
|
||||
get_abs_path("data/numbers/decimal_delimiter.tsv")
|
||||
)
|
||||
delimiter = (
|
||||
pynini.cross(",", "")
|
||||
+ delimiter_map["@@decimal_delimiter@@"]
|
||||
+ pynini.closure(pynutil.add_weight(pynutil.insert(" и"), 0.5), 0, 1)
|
||||
).optimize()
|
||||
|
||||
decimal_endings_map = prepare_labels_for_insertion(
|
||||
get_abs_path("data/numbers/decimal_endings.tsv")
|
||||
)
|
||||
|
||||
self.integer_part = integer_part + delimiter
|
||||
graph_integer = pynutil.insert('integer_part: "') + self.integer_part + pynutil.insert('"')
|
||||
|
||||
graph_fractional = (
|
||||
DAMO_DIGIT @ cardinal_numbers_with_leading_zeros + decimal_endings_map["10"]
|
||||
)
|
||||
graph_fractional |= (
|
||||
DAMO_DIGIT + DAMO_DIGIT
|
||||
) @ cardinal_numbers_with_leading_zeros + decimal_endings_map["100"]
|
||||
graph_fractional |= (
|
||||
DAMO_DIGIT + DAMO_DIGIT + DAMO_DIGIT
|
||||
) @ cardinal_numbers_with_leading_zeros + decimal_endings_map["1000"]
|
||||
graph_fractional |= (
|
||||
DAMO_DIGIT + DAMO_DIGIT + DAMO_DIGIT + DAMO_DIGIT
|
||||
) @ cardinal_numbers_with_leading_zeros + decimal_endings_map["10000"]
|
||||
|
||||
self.optional_quantity = pynini.string_file(
|
||||
get_abs_path("data/numbers/quantity.tsv")
|
||||
).optimize()
|
||||
|
||||
self.graph_fractional = graph_fractional
|
||||
graph_fractional = (
|
||||
pynutil.insert('fractional_part: "') + graph_fractional + pynutil.insert('"')
|
||||
)
|
||||
optional_quantity = pynini.closure(
|
||||
(pynutil.add_weight(pynini.accep(DAMO_SPACE), -0.1) | insert_space)
|
||||
+ pynutil.insert('quantity: "')
|
||||
+ self.optional_quantity
|
||||
+ pynutil.insert('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
self.final_graph = (
|
||||
cardinal.optional_graph_negative
|
||||
+ graph_integer
|
||||
+ insert_space
|
||||
+ graph_fractional
|
||||
+ optional_quantity
|
||||
)
|
||||
|
||||
self.final_graph = self.add_tokens(self.final_graph)
|
||||
self.fst = self.final_graph.optimize()
|
||||
@@ -0,0 +1,113 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_ALPHA,
|
||||
DAMO_DIGIT,
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA, TO_CYRILLIC
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class ElectronicFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying electronic: email addresses
|
||||
e.g. "ab@nd.ru" -> electronic { username: "эй би собака эн ди точка ру" }
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="electronic", kind="classify", deterministic=deterministic)
|
||||
|
||||
# tagger
|
||||
accepted_symbols = []
|
||||
with open(get_abs_path("data/electronic/symbols.tsv"), "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
symbol, _ = line.split("\t")
|
||||
accepted_symbols.append(pynini.accep(symbol))
|
||||
username = (
|
||||
pynutil.insert('username: "')
|
||||
+ DAMO_ALPHA
|
||||
+ pynini.closure(DAMO_ALPHA | DAMO_DIGIT | pynini.union(*accepted_symbols))
|
||||
+ pynutil.insert('"')
|
||||
+ pynini.cross("@", " ")
|
||||
)
|
||||
domain_graph = (
|
||||
DAMO_ALPHA
|
||||
+ (pynini.closure(DAMO_ALPHA | DAMO_DIGIT | pynini.accep("-") | pynini.accep(".")))
|
||||
+ (DAMO_ALPHA | DAMO_DIGIT)
|
||||
)
|
||||
domain_graph = pynutil.insert('domain: "') + domain_graph + pynutil.insert('"')
|
||||
tagger_graph = (username + domain_graph).optimize()
|
||||
|
||||
# verbalizer
|
||||
graph_digit = pynini.string_file(
|
||||
get_abs_path("data/numbers/digits_nominative_case.tsv")
|
||||
).optimize()
|
||||
graph_symbols = pynini.string_file(get_abs_path("data/electronic/symbols.tsv")).optimize()
|
||||
user_name = (
|
||||
pynutil.delete("username:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ (
|
||||
pynini.closure(
|
||||
pynutil.add_weight(graph_digit + insert_space, 1.09)
|
||||
| pynutil.add_weight(pynini.closure(graph_symbols + pynutil.insert(" ")), 1.09)
|
||||
| pynutil.add_weight(DAMO_NOT_QUOTE + insert_space, 1.1)
|
||||
)
|
||||
)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
domain_default = (
|
||||
pynini.closure(DAMO_NOT_QUOTE + insert_space)
|
||||
+ pynini.cross(".", "точка ")
|
||||
+ DAMO_NOT_QUOTE
|
||||
+ pynini.closure(insert_space + DAMO_NOT_QUOTE)
|
||||
)
|
||||
|
||||
server_default = (
|
||||
pynini.closure((graph_digit | DAMO_ALPHA) + insert_space, 1)
|
||||
+ pynini.closure(graph_symbols + insert_space)
|
||||
+ pynini.closure((graph_digit | DAMO_ALPHA) + insert_space, 1)
|
||||
)
|
||||
server_common = (
|
||||
pynini.string_file(get_abs_path("data/electronic/server_name.tsv")) + insert_space
|
||||
)
|
||||
domain_common = pynini.cross(".", "точка ") + pynini.string_file(
|
||||
get_abs_path("data/electronic/domain.tsv")
|
||||
)
|
||||
domain = (
|
||||
pynutil.delete("domain:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ (pynutil.add_weight(server_common, 1.09) | pynutil.add_weight(server_default, 1.1))
|
||||
+ (pynutil.add_weight(domain_common, 1.09) | pynutil.add_weight(domain_default, 1.1))
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
graph = (
|
||||
user_name
|
||||
+ delete_space
|
||||
+ pynutil.insert("собака ")
|
||||
+ delete_space
|
||||
+ domain
|
||||
+ delete_space
|
||||
)
|
||||
# replace all latin letters with their Ru verbalization
|
||||
verbalizer_graph = (
|
||||
graph.optimize() @ (pynini.closure(TO_CYRILLIC | RU_ALPHA | pynini.accep(" ")))
|
||||
).optimize()
|
||||
verbalizer_graph = verbalizer_graph.optimize()
|
||||
|
||||
self.final_graph = (tagger_graph @ verbalizer_graph).optimize()
|
||||
self.fst = self.add_tokens(
|
||||
pynutil.insert('username: "') + self.final_graph + pynutil.insert('"')
|
||||
).optimize()
|
||||
@@ -0,0 +1,183 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NON_BREAKING_SPACE,
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MeasureFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying measure, e.g.
|
||||
"2 кг" -> measure { cardinal { integer: "два килограма" } }
|
||||
This class also converts words containing numbers and letters
|
||||
e.g. "тест-8" —> "тест восемь"
|
||||
e.g. "тест-1,02" —> "тест одна целая две сотых"
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
decimal: DecimalFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst, decimal: GraphFst, deterministic: bool = True):
|
||||
super().__init__(name="measure", kind="classify", deterministic=deterministic)
|
||||
|
||||
# adding weight to make sure the space is preserved for ITN
|
||||
delete_space = pynini.closure(
|
||||
pynutil.add_weight(
|
||||
pynutil.delete(pynini.union(DAMO_SPACE, DAMO_NON_BREAKING_SPACE)), -1
|
||||
),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
cardinal_graph = cardinal.cardinal_numbers_default
|
||||
cardinal_graph_nominative = cardinal.cardinal_numbers_nominative
|
||||
graph_unit = pynini.string_file(get_abs_path("data/measurements.tsv"))
|
||||
optional_graph_negative = cardinal.optional_graph_negative
|
||||
|
||||
space_for_units = (
|
||||
pynutil.add_weight(pynutil.insert(DAMO_NON_BREAKING_SPACE), -0.1)
|
||||
| pynutil.add_weight(pynutil.insert(DAMO_SPACE), 0.1)
|
||||
).optimize()
|
||||
slash_unit = (
|
||||
(pynini.cross("/", "в") | pynini.cross("/", "за")) + space_for_units + graph_unit
|
||||
)
|
||||
|
||||
unit_slash_unit = pynutil.add_weight(graph_unit + space_for_units + slash_unit, -0.1)
|
||||
default_units = (
|
||||
pynutil.insert('units: "') + (graph_unit | unit_slash_unit) + pynutil.insert('"')
|
||||
)
|
||||
slash_units = pynutil.insert('units: "') + slash_unit + pynutil.insert('"')
|
||||
subgraph_decimal = decimal.final_graph + ((delete_space + default_units) | slash_units)
|
||||
|
||||
cardinal_space = (
|
||||
pynutil.insert("cardinal { ")
|
||||
+ optional_graph_negative
|
||||
+ pynutil.insert('integer: "')
|
||||
+ cardinal_graph
|
||||
+ (
|
||||
(delete_space + pynutil.insert('"') + pynutil.insert(" } ") + default_units)
|
||||
| (pynutil.insert('"') + pynutil.insert(" } ") + slash_units)
|
||||
)
|
||||
)
|
||||
|
||||
cardinal_optional_dash_alpha = (
|
||||
pynutil.insert('cardinal { integer: "')
|
||||
+ cardinal_graph
|
||||
+ pynini.closure(pynini.cross("-", ""), 0, 1)
|
||||
+ pynutil.insert('" } units: "')
|
||||
+ pynini.closure(RU_ALPHA, 1)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
alpha_optional_dash_cardinal = (
|
||||
pynutil.insert('units: "')
|
||||
+ pynini.closure(RU_ALPHA, 1)
|
||||
+ pynini.closure(pynini.cross("-", ""), 0, 1)
|
||||
+ pynutil.insert('"')
|
||||
+ pynutil.insert(' cardinal { integer: "')
|
||||
+ cardinal_graph_nominative
|
||||
+ pynutil.insert('" } preserve_order: true')
|
||||
)
|
||||
|
||||
decimal_dash_alpha = (
|
||||
decimal.final_graph
|
||||
+ pynini.cross("-", "")
|
||||
+ pynutil.insert(' units: "')
|
||||
+ pynini.closure(RU_ALPHA, 1)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
alpha_dash_decimal = (
|
||||
pynutil.insert('units: "')
|
||||
+ pynini.closure(RU_ALPHA, 1)
|
||||
+ pynini.cross("-", "")
|
||||
+ pynutil.insert('" ')
|
||||
+ decimal.final_graph
|
||||
+ pynutil.insert(" preserve_order: true")
|
||||
)
|
||||
|
||||
self.tagger_graph_default = (subgraph_decimal | cardinal_space).optimize()
|
||||
|
||||
tagger_graph = (
|
||||
self.tagger_graph_default
|
||||
| cardinal_optional_dash_alpha
|
||||
| alpha_optional_dash_cardinal
|
||||
| decimal_dash_alpha
|
||||
| alpha_dash_decimal
|
||||
).optimize()
|
||||
|
||||
# verbalizer
|
||||
unit = (
|
||||
pynutil.delete('units: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
)
|
||||
|
||||
optional_sign = pynini.closure(pynini.cross('negative: "true" ', "минус "), 0, 1)
|
||||
integer = pynutil.delete(' "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
integer_part = pynutil.delete("integer_part:") + integer
|
||||
fractional_part = pynutil.delete("fractional_part:") + integer
|
||||
optional_quantity_part = pynini.closure(
|
||||
pynini.accep(" ")
|
||||
+ pynutil.delete('quantity: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
graph_decimal = (
|
||||
optional_sign
|
||||
+ integer_part
|
||||
+ pynini.accep(" ")
|
||||
+ fractional_part
|
||||
+ optional_quantity_part
|
||||
)
|
||||
|
||||
graph_decimal = (
|
||||
pynutil.delete("decimal {")
|
||||
+ delete_space
|
||||
+ graph_decimal
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
|
||||
graph_cardinal = (
|
||||
pynutil.delete("cardinal {")
|
||||
+ delete_space
|
||||
+ optional_sign
|
||||
+ pynutil.delete('integer: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
|
||||
verbalizer_graph = (graph_cardinal | graph_decimal) + delete_space + insert_space + unit
|
||||
|
||||
# SH adds "preserve_order: true" by default
|
||||
preserve_order = (
|
||||
pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space
|
||||
)
|
||||
verbalizer_graph |= (
|
||||
unit
|
||||
+ insert_space
|
||||
+ (graph_cardinal | graph_decimal)
|
||||
+ delete_space
|
||||
+ pynini.closure(preserve_order, 0, 1)
|
||||
)
|
||||
self.verbalizer_graph = verbalizer_graph.optimize()
|
||||
|
||||
final_graph = (tagger_graph @ verbalizer_graph).optimize()
|
||||
self.fst = self.add_tokens(
|
||||
pynutil.insert('cardinal { integer: "') + final_graph + pynutil.insert('" }')
|
||||
).optimize()
|
||||
@@ -0,0 +1,97 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MoneyFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying money, e.g.
|
||||
"5руб." -> money { "пять рублей" }
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
decimal: DecimalFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst, decimal: GraphFst, deterministic: bool = True):
|
||||
super().__init__(name="money", kind="classify", deterministic=deterministic)
|
||||
cardinal_graph = cardinal.cardinal_numbers_default
|
||||
decimal_graph = decimal.final_graph
|
||||
|
||||
unit_singular = pynini.string_file(get_abs_path("data/currency/currency_singular.tsv"))
|
||||
unit_plural = pynini.string_file(get_abs_path("data/currency/currency_plural.tsv"))
|
||||
|
||||
# adding weight to make sure the space is preserved for ITN
|
||||
optional_delimiter = pynini.closure(
|
||||
pynutil.add_weight(pynini.cross(DAMO_SPACE, ""), -100), 0, 1
|
||||
)
|
||||
graph_unit_singular = (
|
||||
optional_delimiter
|
||||
+ pynutil.insert(' currency: "')
|
||||
+ unit_singular
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
graph_unit_plural = (
|
||||
optional_delimiter + pynutil.insert(' currency: "') + unit_plural + pynutil.insert('"')
|
||||
)
|
||||
|
||||
one = pynini.compose(pynini.accep("1"), cardinal_graph).optimize()
|
||||
singular_graph = (
|
||||
pynutil.insert('integer_part: "') + one + pynutil.insert('"') + graph_unit_singular
|
||||
)
|
||||
|
||||
graph_decimal = decimal_graph + graph_unit_plural
|
||||
|
||||
graph_integer = (
|
||||
pynutil.insert('integer_part: "')
|
||||
+ ((DAMO_SIGMA - "1") @ cardinal_graph)
|
||||
+ pynutil.insert('"')
|
||||
+ (graph_unit_plural)
|
||||
)
|
||||
|
||||
graph_integer |= singular_graph
|
||||
tagger_graph = (graph_integer.optimize() | graph_decimal.optimize()).optimize()
|
||||
|
||||
# verbalizer
|
||||
integer = pynutil.delete('"') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
integer_part = pynutil.delete("integer_part: ") + integer
|
||||
|
||||
unit = (
|
||||
pynutil.delete("currency: ")
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
unit = pynini.accep(DAMO_SPACE) + unit
|
||||
|
||||
verbalizer_graph_cardinal = (integer_part + unit).optimize()
|
||||
|
||||
fractional_part = pynutil.delete("fractional_part: ") + integer
|
||||
optional_quantity = pynini.closure(
|
||||
pynini.accep(DAMO_SPACE) + pynutil.delete("quantity: ") + integer, 0, 1
|
||||
)
|
||||
|
||||
verbalizer_graph_decimal = (
|
||||
pynutil.delete("decimal { ")
|
||||
+ integer_part
|
||||
+ pynini.accep(" ")
|
||||
+ fractional_part
|
||||
+ optional_quantity
|
||||
+ pynutil.delete(" }")
|
||||
+ unit
|
||||
)
|
||||
|
||||
verbalizer_graph = (verbalizer_graph_cardinal | verbalizer_graph_decimal).optimize()
|
||||
|
||||
self.final_graph = (tagger_graph @ verbalizer_graph).optimize()
|
||||
self.fst = self.add_tokens(
|
||||
pynutil.insert('integer_part: "') + self.final_graph + pynutil.insert('"')
|
||||
).optimize()
|
||||
@@ -0,0 +1,138 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
|
||||
|
||||
# Adapted from https://github.com/google/TextNormalizationCoveringGrammars
|
||||
# Russian minimally supervised number grammar.
|
||||
#
|
||||
# Supports cardinals and ordinals in all inflected forms.
|
||||
#
|
||||
# The language-specific acceptor G was compiled with digit, teen, decade,
|
||||
# century, and big power-of-ten preterminals. The lexicon transducer is
|
||||
# highly ambiguous, but no LM is used.
|
||||
|
||||
# Intersects the universal factorization transducer (F) with language-specific
|
||||
# acceptor (G).
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_SIGMA
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path, load_labels
|
||||
from pynini.lib import pynutil, rewrite
|
||||
|
||||
|
||||
def get_number_names():
|
||||
"""
|
||||
Creates numbers names.
|
||||
|
||||
Based on: 1) Gorman, K., and Sproat, R. 2016. Minimally supervised number normalization.
|
||||
Transactions of the Association for Computational Linguistics 4: 507-519.
|
||||
and 2) Ng, A. H., Gorman, K., and Sproat, R. 2017.
|
||||
Minimally supervised written-to-spoken text normalization. In ASRU, pages 665-670.
|
||||
"""
|
||||
a = pynini.Far(get_abs_path("data/utils/util_arithmetic.far"), mode="r")
|
||||
d = a["DELTA_STAR"]
|
||||
f = a["IARITHMETIC_RESTRICTED"]
|
||||
g = pynini.Fst.read(get_abs_path("data/utils/g.fst"))
|
||||
fg = (d @ (f @ (f @ (f @ g).optimize()).optimize()).optimize()).optimize()
|
||||
assert rewrite.top_rewrite("230", fg) == "(+ 200 30 +)"
|
||||
|
||||
# Compiles lexicon transducers (L).
|
||||
cardinal_name_nominative = pynini.string_file(
|
||||
get_abs_path("data/numbers/1_cardinals_nominative.tsv")
|
||||
).optimize()
|
||||
cardinal_name_genitive = pynini.string_file(
|
||||
get_abs_path("data/numbers/2_cardinals_genitive.tsv")
|
||||
).optimize()
|
||||
cardinal_name_dative = pynini.string_file(
|
||||
get_abs_path("data/numbers/3_cardinals_dative.tsv")
|
||||
).optimize()
|
||||
cardinal_name_accusative = pynini.string_file(
|
||||
get_abs_path("data/numbers/4_cardinals_accusative.tsv")
|
||||
).optimize()
|
||||
cardinal_name_instrumental = pynini.string_file(
|
||||
get_abs_path("data/numbers/5_cardinals_instrumental.tsv")
|
||||
).optimize()
|
||||
cardinal_name_prepositional = pynini.string_file(
|
||||
get_abs_path("data/numbers/6_cardinals_prepositional.tsv")
|
||||
).optimize()
|
||||
|
||||
cardinal_name_nominative = (
|
||||
pynini.closure(cardinal_name_nominative + pynini.accep(" ")) + cardinal_name_nominative
|
||||
).optimize()
|
||||
cardinal_l = pynutil.add_weight(cardinal_name_nominative, -0.1)
|
||||
for case in [
|
||||
pynutil.add_weight(cardinal_name_genitive, 0.1).optimize(),
|
||||
pynutil.add_weight(cardinal_name_dative, 0.1).optimize(),
|
||||
pynutil.add_weight(cardinal_name_accusative, 0.1).optimize(),
|
||||
pynutil.add_weight(cardinal_name_instrumental, 0.1).optimize(),
|
||||
pynutil.add_weight(cardinal_name_prepositional, 0.1).optimize(),
|
||||
]:
|
||||
cardinal_l |= (pynini.closure(case + pynini.accep(" ")) + case).optimize()
|
||||
|
||||
# Numbers in nominative case (to use, for example, with telephone or serial_graph (in cardinals))
|
||||
cardinal_names_nominative_l = (
|
||||
pynini.closure(cardinal_name_nominative + pynini.accep(" ")) + cardinal_name_nominative
|
||||
).optimize()
|
||||
|
||||
# Convert e.g. "(* 5 1000 *)" back to "5000" so complex ordinals will be formed correctly,
|
||||
# e.g. "пятитысячный" will eventually be formed. (If we didn't do this, the incorrect phrase
|
||||
# "пять тысячный" would be formed).
|
||||
# We do this for all thousands from "(*2 1000 *)" —> "2000" to "(*20 1000 *)" —> "20000".
|
||||
# We do not go higher, in order to prevent the WFST graph becoming even larger.
|
||||
complex_numbers = pynini.cross("(* 2 1000 *)", "2000")
|
||||
for number in range(3, 21):
|
||||
complex_numbers |= pynini.cross(f"(* {number} 1000 *)", f"{number}000")
|
||||
|
||||
complex_numbers = (
|
||||
DAMO_SIGMA
|
||||
+ pynutil.add_weight(complex_numbers, -1)
|
||||
+ pynini.closure(pynini.union(" ", ")", "(", "+", "*"))
|
||||
).optimize()
|
||||
fg_ordinal = pynutil.add_weight(pynini.compose(fg, complex_numbers), -1) | fg
|
||||
ordinal_name = pynini.string_file(get_abs_path("data/numbers/ordinals.tsv"))
|
||||
ordinal_l = (
|
||||
pynini.closure(cardinal_name_nominative + pynini.accep(" ")) + ordinal_name
|
||||
).optimize()
|
||||
|
||||
# Composes L with the leaf transducer (P), then composes that with FG.
|
||||
p = a["LEAVES"]
|
||||
number_names = {}
|
||||
number_names["ordinal_number_names"] = (fg_ordinal @ (p @ ordinal_l)).optimize()
|
||||
number_names["cardinal_number_names"] = (fg @ (p @ cardinal_l)).optimize()
|
||||
number_names["cardinal_names_nominative"] = (fg @ (p @ cardinal_names_nominative_l)).optimize()
|
||||
return number_names
|
||||
|
||||
|
||||
def get_alternative_formats():
|
||||
"""
|
||||
Utils to get alternative formats for numbers.
|
||||
"""
|
||||
one_alternatives = load_labels(get_abs_path("data/numbers/cardinals_alternatives.tsv"))
|
||||
one_thousand_map = []
|
||||
for k in one_alternatives:
|
||||
default, alternative = k
|
||||
one_thousand_map.append((alternative.split()[1], alternative))
|
||||
one_thousand_map = pynini.string_map(one_thousand_map)
|
||||
|
||||
one_thousand_alternative = pynini.cdrewrite(one_thousand_map, "[BOS]", "", DAMO_SIGMA)
|
||||
|
||||
# Adapted from
|
||||
# https://github.com/google/TextNormalizationCoveringGrammars/blob/master/src/universal/thousands_punct.grm
|
||||
# Specifies common ways of delimiting thousands in digit strings.
|
||||
t = pynini.Far(get_abs_path("data/utils/universal_thousands_punct.far"))
|
||||
separators = (
|
||||
pynutil.add_weight(t["dot_thousands"], 0.1)
|
||||
| pynutil.add_weight(t["no_delimiter"], -0.1)
|
||||
| pynutil.add_weight(t["space_thousands"], 0.1)
|
||||
)
|
||||
alternative_formats = {}
|
||||
alternative_formats["one_thousand_alternative"] = one_thousand_alternative.optimize()
|
||||
alternative_formats["separators"] = separators.optimize()
|
||||
return alternative_formats
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from fun_text_processing.text_normalization.en.graph_utils import generator_main
|
||||
|
||||
numbers = get_number_names()
|
||||
for k, v in numbers.items():
|
||||
generator_main(f"{k}.far", {k: v})
|
||||
@@ -0,0 +1,52 @@
|
||||
# Adapted from https://github.com/google/TextNormalizationCoveringGrammars
|
||||
# Russian minimally supervised number grammar.
|
||||
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_SIGMA, GraphFst
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class OrdinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying cardinals, e.g.
|
||||
"2" -> ordinal { integer: "второе" } }
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
alternative_formats: alternative format for cardinal and ordinal numbers
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, number_names: dict, alternative_formats: dict, deterministic=False):
|
||||
super().__init__(name="ordinal", kind="classify", deterministic=deterministic)
|
||||
|
||||
one_thousand_alternative = alternative_formats["one_thousand_alternative"]
|
||||
separators = alternative_formats["separators"]
|
||||
|
||||
ordinal = number_names["ordinal_number_names"]
|
||||
|
||||
ordinal |= ordinal @ one_thousand_alternative
|
||||
ordinal_numbers = separators @ ordinal
|
||||
|
||||
# to handle cases like 2-ая
|
||||
endings = pynini.string_file(get_abs_path("data/numbers/ordinal_endings.tsv"))
|
||||
not_dash = pynini.closure(pynini.difference(DAMO_SIGMA, "-"))
|
||||
del_ending = pynini.cdrewrite(pynini.cross("-" + not_dash, ""), "", "[EOS]", DAMO_SIGMA)
|
||||
ordinal_numbers_marked = (
|
||||
((separators @ ordinal).optimize() + pynini.accep("-") + not_dash).optimize()
|
||||
@ (DAMO_SIGMA + endings).optimize()
|
||||
@ del_ending
|
||||
).optimize()
|
||||
|
||||
self.ordinal_numbers = ordinal_numbers
|
||||
# "03" -> remove leading zeros and verbalize
|
||||
leading_zeros = pynini.closure(pynini.cross("0", ""))
|
||||
self.ordinal_numbers_with_leading_zeros = (leading_zeros + ordinal_numbers).optimize()
|
||||
|
||||
final_graph = (ordinal_numbers | ordinal_numbers_marked).optimize()
|
||||
final_graph = pynutil.insert('integer: "') + final_graph + pynutil.insert('"')
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,71 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA_OR_SPACE
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TelephoneFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying telephone, which includes country code, number part and extension
|
||||
|
||||
E.g
|
||||
"8-913-983-56-01" -> telephone { number_part: "восемь девятьсот тринадцать девятьсот восемьдесят три пятьдесят шесть ноль один" }
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, number_names: dict, deterministic: bool = True):
|
||||
super().__init__(name="telephone", kind="classify", deterministic=deterministic)
|
||||
|
||||
separator = pynini.cross("-", " ") # between components
|
||||
number = number_names["cardinal_names_nominative"]
|
||||
|
||||
country_code = (
|
||||
pynutil.insert('country_code: "')
|
||||
+ pynini.closure(pynutil.add_weight(pynutil.delete("+"), 0.1), 0, 1)
|
||||
+ number
|
||||
+ separator
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
optional_country_code = pynini.closure(country_code + insert_space, 0, 1)
|
||||
|
||||
number_part = (
|
||||
DAMO_DIGIT**3 @ number
|
||||
+ separator
|
||||
+ DAMO_DIGIT**3 @ number
|
||||
+ separator
|
||||
+ DAMO_DIGIT**2 @ number
|
||||
+ separator
|
||||
+ DAMO_DIGIT**2 @ (pynini.closure(pynini.cross("0", "ноль ")) + number)
|
||||
)
|
||||
number_part = pynutil.insert('number_part: "') + number_part + pynutil.insert('"')
|
||||
tagger_graph = (optional_country_code + number_part).optimize()
|
||||
|
||||
# verbalizer
|
||||
verbalizer_graph = pynini.closure(
|
||||
pynutil.delete('country_code: "')
|
||||
+ pynini.closure(RU_ALPHA_OR_SPACE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
verbalizer_graph += (
|
||||
pynutil.delete('number_part: "')
|
||||
+ pynini.closure(RU_ALPHA_OR_SPACE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
verbalizer_graph = verbalizer_graph.optimize()
|
||||
|
||||
self.final_graph = (tagger_graph @ verbalizer_graph).optimize()
|
||||
self.fst = self.add_tokens(
|
||||
pynutil.insert('number_part: "') + self.final_graph + pynutil.insert('"')
|
||||
).optimize()
|
||||
@@ -0,0 +1,115 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TimeFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying time, e.g.
|
||||
"02:15" -> time { hours: "два часа пятнадцать минут" }
|
||||
|
||||
Args:
|
||||
number_names: number_names for cardinal and ordinal numbers
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, number_names: dict, deterministic: bool = True):
|
||||
super().__init__(name="time", kind="classify", deterministic=deterministic)
|
||||
|
||||
increment_hour_ordinal = pynini.string_file(
|
||||
get_abs_path("data/time/increment_hour_ordinal.tsv")
|
||||
)
|
||||
increment_hour_cardinal = pynini.string_file(
|
||||
get_abs_path("data/time/increment_hour_cardinal.tsv")
|
||||
)
|
||||
convert_hour = pynini.string_file(get_abs_path("data/time/time_convert.tsv"))
|
||||
|
||||
number = (
|
||||
pynini.closure(pynini.cross("0", ""), 0, 1) + number_names["cardinal_names_nominative"]
|
||||
)
|
||||
hour_options = pynini.project(increment_hour_ordinal, "input")
|
||||
hour_options = hour_options | pynini.project(convert_hour, "output")
|
||||
|
||||
hour_exeption_ends_with_one = pynini.union(*["01", "21"])
|
||||
hour_exeption_ends_rest = pynini.union(*["02", "03", "04", "22", "23"])
|
||||
hour_other = (
|
||||
pynini.difference(
|
||||
hour_options, pynini.union(hour_exeption_ends_with_one, hour_exeption_ends_rest)
|
||||
)
|
||||
).optimize()
|
||||
|
||||
hour = hour_exeption_ends_with_one @ number + pynutil.insert(" час")
|
||||
hour |= hour_exeption_ends_rest @ number + pynutil.insert(" часа")
|
||||
hour |= hour_other @ number + pynutil.insert(" часов")
|
||||
|
||||
optional_and = pynini.closure(pynutil.insert("и "), 0, 1)
|
||||
digits = pynini.union(*[str(x) for x in range(10)])
|
||||
mins_start = pynini.union(*"012345")
|
||||
mins_options = mins_start + digits
|
||||
mins_exception_ends_with_one = mins_start + pynini.accep("1")
|
||||
mins_exception_ends_rest = pynini.difference(
|
||||
mins_start + pynini.union(*"234"), pynini.union(*["12", "13", "14"])
|
||||
)
|
||||
mins_other = pynini.difference(
|
||||
mins_options, pynini.union(mins_exception_ends_with_one, mins_exception_ends_rest)
|
||||
)
|
||||
|
||||
minutes = mins_exception_ends_with_one @ number + pynutil.insert(" минута")
|
||||
minutes |= mins_exception_ends_rest @ number + pynutil.insert(" минуты")
|
||||
minutes |= mins_other @ number + pynutil.insert(" минут")
|
||||
self.minutes = minutes.optimize()
|
||||
# 17:15 -> "семнадцать часов и пятнадцать минут"
|
||||
hm = (
|
||||
pynutil.insert('hours: "')
|
||||
+ hour.optimize()
|
||||
+ pynutil.insert('"')
|
||||
+ (
|
||||
pynini.cross(":", " ")
|
||||
+ pynutil.insert('minutes: "')
|
||||
+ optional_and
|
||||
+ minutes.optimize()
|
||||
)
|
||||
+ pynutil.insert('"')
|
||||
+ pynutil.insert(" preserve_order: true")
|
||||
)
|
||||
h = pynutil.insert('hours: "') + hour + pynutil.insert('"') + pynutil.delete(":00")
|
||||
self.graph_preserve_order = (hm | h).optimize()
|
||||
|
||||
# 17:15 -> "пятнадцать минут шестого"
|
||||
# Requires permutations for the correct verbalization
|
||||
self.increment_hour_ordinal = pynini.compose(
|
||||
hour_options, increment_hour_ordinal
|
||||
).optimize()
|
||||
m_next_h = (
|
||||
pynutil.insert('hours: "')
|
||||
+ self.increment_hour_ordinal
|
||||
+ pynutil.insert('"')
|
||||
+ pynini.cross(":", " ")
|
||||
+ pynutil.insert('minutes: "')
|
||||
+ minutes
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
# 17:45 -> "без пятнадцати минут шесть"
|
||||
# Requires permutations for the correct verbalization
|
||||
self.mins_to_h = pynini.string_file(
|
||||
get_abs_path("data/time/minutes_to_hour.tsv")
|
||||
).optimize()
|
||||
self.increment_hour_cardinal = pynini.compose(
|
||||
hour_options, increment_hour_cardinal
|
||||
).optimize()
|
||||
m_to_h = (
|
||||
pynutil.insert('hours: "')
|
||||
+ self.increment_hour_cardinal
|
||||
+ pynutil.insert('"')
|
||||
+ pynini.cross(":", " ")
|
||||
+ pynutil.insert('minutes: "без ')
|
||||
+ self.mins_to_h
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
self.final_graph = m_next_h | self.graph_preserve_order | m_to_h
|
||||
self.fst = self.add_tokens(self.final_graph)
|
||||
self.fst = self.fst.optimize()
|
||||
@@ -0,0 +1,149 @@
|
||||
import os
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
generator_main,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.taggers.punctuation import PunctuationFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.cardinal import CardinalFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.date import DateFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.decimals import DecimalFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.electronic import ElectronicFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.measure import MeasureFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.money import MoneyFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.number_names import (
|
||||
get_alternative_formats,
|
||||
get_number_names,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.taggers.ordinal import OrdinalFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.telephone import TelephoneFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.time import TimeFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.whitelist import WhiteListFst
|
||||
from fun_text_processing.text_normalization.ru.taggers.word import WordFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class ClassifyFst(GraphFst):
|
||||
"""
|
||||
Final class that composes all other classification grammars. This class can process an entire sentence, that is lower cased.
|
||||
For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File.
|
||||
More details to deployment at NeMo/tools/text_processing_deployment.
|
||||
|
||||
Args:
|
||||
input_case: accepting either "lower_cased" or "cased" input.
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache.
|
||||
overwrite_cache: set to True to overwrite .far files
|
||||
whitelist: path to a file with whitelist replacements
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_case: str,
|
||||
deterministic: bool = False,
|
||||
cache_dir: str = None,
|
||||
overwrite_cache: bool = False,
|
||||
whitelist: str = None,
|
||||
):
|
||||
super().__init__(name="tokenize_and_classify", kind="classify", deterministic=deterministic)
|
||||
if deterministic:
|
||||
raise ValueError(
|
||||
"Ru TN only supports non-deterministic cases and produces multiple normalization options."
|
||||
)
|
||||
far_file = None
|
||||
if cache_dir is not None and cache_dir != "None":
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
whitelist_file = os.path.basename(whitelist) if whitelist else ""
|
||||
far_file = os.path.join(
|
||||
cache_dir, f"_{input_case}_ru_tn_{deterministic}_deterministic{whitelist_file}.far"
|
||||
)
|
||||
if not overwrite_cache and far_file and os.path.exists(far_file):
|
||||
self.fst = pynini.Far(far_file, mode="r")["tokenize_and_classify"]
|
||||
logging.info(f"ClassifyFst.fst was restored from {far_file}.")
|
||||
else:
|
||||
logging.info(f"Creating ClassifyFst grammars. This might take some time...")
|
||||
number_names = get_number_names()
|
||||
alternative_formats = get_alternative_formats()
|
||||
|
||||
self.cardinal = CardinalFst(
|
||||
number_names=number_names,
|
||||
alternative_formats=alternative_formats,
|
||||
deterministic=deterministic,
|
||||
)
|
||||
cardinal_graph = self.cardinal.fst
|
||||
|
||||
self.ordinal = OrdinalFst(
|
||||
number_names=number_names,
|
||||
alternative_formats=alternative_formats,
|
||||
deterministic=deterministic,
|
||||
)
|
||||
ordinal_graph = self.ordinal.fst
|
||||
|
||||
self.decimal = DecimalFst(cardinal=self.cardinal, deterministic=deterministic)
|
||||
decimal_graph = self.decimal.fst
|
||||
|
||||
self.measure = MeasureFst(
|
||||
cardinal=self.cardinal, decimal=self.decimal, deterministic=deterministic
|
||||
)
|
||||
measure_graph = self.measure.fst
|
||||
self.date = DateFst(number_names=number_names, deterministic=deterministic)
|
||||
date_graph = self.date.fst
|
||||
word_graph = WordFst(deterministic=deterministic).fst
|
||||
self.time = TimeFst(number_names=number_names, deterministic=deterministic)
|
||||
time_graph = self.time.fst
|
||||
self.telephone = TelephoneFst(number_names=number_names, deterministic=deterministic)
|
||||
telephone_graph = self.telephone.fst
|
||||
self.electronic = ElectronicFst(deterministic=deterministic)
|
||||
electronic_graph = self.electronic.fst
|
||||
self.money = MoneyFst(
|
||||
cardinal=self.cardinal, decimal=self.decimal, deterministic=deterministic
|
||||
)
|
||||
money_graph = self.money.fst
|
||||
self.whitelist = WhiteListFst(
|
||||
input_case=input_case, deterministic=deterministic, input_file=whitelist
|
||||
)
|
||||
whitelist_graph = self.whitelist.fst
|
||||
punct_graph = PunctuationFst(deterministic=deterministic).fst
|
||||
|
||||
classify = (
|
||||
pynutil.add_weight(whitelist_graph, 1.01)
|
||||
| pynutil.add_weight(time_graph, 1.1)
|
||||
| pynutil.add_weight(date_graph, 1.09)
|
||||
| pynutil.add_weight(decimal_graph, 1.1)
|
||||
| pynutil.add_weight(measure_graph, 0.9)
|
||||
| pynutil.add_weight(cardinal_graph, 1.1)
|
||||
| pynutil.add_weight(ordinal_graph, 1.1)
|
||||
| pynutil.add_weight(money_graph, 1.1)
|
||||
| pynutil.add_weight(telephone_graph, 1.1)
|
||||
| pynutil.add_weight(electronic_graph, 1.1)
|
||||
| pynutil.add_weight(word_graph, 100)
|
||||
)
|
||||
|
||||
punct = (
|
||||
pynutil.insert("tokens { ")
|
||||
+ pynutil.add_weight(punct_graph, weight=1.1)
|
||||
+ pynutil.insert(" }")
|
||||
)
|
||||
token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }")
|
||||
token_plus_punct = (
|
||||
pynini.closure(punct + pynutil.insert(" "))
|
||||
+ token
|
||||
+ pynini.closure(pynutil.insert(" ") + punct)
|
||||
)
|
||||
|
||||
graph = token_plus_punct + pynini.closure(
|
||||
pynutil.add_weight(delete_extra_space, 1.1) + token_plus_punct
|
||||
)
|
||||
graph = delete_space + graph + delete_space
|
||||
|
||||
self.fst = graph.optimize()
|
||||
|
||||
if far_file:
|
||||
generator_main(far_file, {"tokenize_and_classify": self.fst})
|
||||
logging.info(f"ClassifyFst grammars are saved to {far_file}.")
|
||||
@@ -0,0 +1,51 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_CHAR, GraphFst, convert_space
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA, TO_CYRILLIC
|
||||
from fun_text_processing.text_normalization.ru.utils import get_abs_path, load_labels
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WhiteListFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying whitelist, e.g.
|
||||
misses -> tokens { name: "mrs" }
|
||||
for non-deterministic case: "Dr. Abc" ->
|
||||
tokens { name: "drive" } tokens { name: "Abc" }
|
||||
tokens { name: "doctor" } tokens { name: "Abc" }
|
||||
tokens { name: "Dr." } tokens { name: "Abc" }
|
||||
This class has highest priority among all classifier grammars. Whitelisted tokens are defined and loaded from "data/whitelist.tsv".
|
||||
|
||||
Args:
|
||||
input_case: accepting either "lower_cased" or "cased" input.
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
input_file: path to a file with whitelist replacements
|
||||
"""
|
||||
|
||||
def __init__(self, input_case: str, deterministic: bool = True, input_file: str = None):
|
||||
super().__init__(name="whitelist", kind="classify", deterministic=deterministic)
|
||||
|
||||
def _get_whitelist_graph(input_case, file):
|
||||
whitelist = load_labels(file)
|
||||
if input_case == "lower_cased":
|
||||
whitelist = [[x[0].lower()] + x[1:] for x in whitelist]
|
||||
else:
|
||||
whitelist = [[x[0].lower()] + x[1:] for x in whitelist]
|
||||
graph = pynini.string_map(whitelist)
|
||||
return graph
|
||||
|
||||
graph = _get_whitelist_graph(input_case, get_abs_path("data/whitelist.tsv"))
|
||||
|
||||
if input_file:
|
||||
graph = _get_whitelist_graph(input_case, input_file)
|
||||
|
||||
units_graph = _get_whitelist_graph(input_case, file=get_abs_path("data/measurements.tsv"))
|
||||
# do not replace single letter units, like `м`, `°` and `%` will be replaced
|
||||
units_graph = pynini.compose(
|
||||
(DAMO_CHAR ** (2, ...) | pynini.difference(DAMO_CHAR, RU_ALPHA)), units_graph
|
||||
)
|
||||
graph |= units_graph.optimize()
|
||||
graph |= TO_CYRILLIC + pynini.closure(pynutil.insert(" ") + TO_CYRILLIC)
|
||||
|
||||
self.final_graph = convert_space(graph)
|
||||
self.fst = (pynutil.insert('name: "') + self.final_graph + pynutil.insert('"')).optimize()
|
||||
@@ -0,0 +1,19 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_SPACE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WordFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying word.
|
||||
e.g. sleep -> tokens { name: "sleep" }
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="word", kind="classify")
|
||||
word = pynutil.insert('name: "') + pynini.closure(DAMO_NOT_SPACE, 1) + pynutil.insert('"')
|
||||
self.fst = word.optimize()
|
||||
@@ -0,0 +1,34 @@
|
||||
import csv
|
||||
import os
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def get_abs_path(rel_path):
|
||||
"""
|
||||
Get absolute path
|
||||
|
||||
Args:
|
||||
rel_path: relative path to this file
|
||||
|
||||
Returns absolute path
|
||||
"""
|
||||
abs_path = os.path.dirname(os.path.abspath(__file__)) + os.sep + rel_path
|
||||
|
||||
if not os.path.exists(abs_path):
|
||||
logging.warning(f"{abs_path} does not exist")
|
||||
return abs_path
|
||||
|
||||
|
||||
def load_labels(abs_path):
|
||||
"""
|
||||
loads relative path file as dictionary
|
||||
|
||||
Args:
|
||||
abs_path: absolute path
|
||||
|
||||
Returns dictionary of mappings
|
||||
"""
|
||||
label_tsv = open(abs_path, encoding="utf-8")
|
||||
labels = list(csv.reader(label_tsv, delimiter="\t"))
|
||||
return labels
|
||||
@@ -0,0 +1,32 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_QUOTE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class CardinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing cardinals
|
||||
e.g. cardinal { integer: "тысяча один" } -> "тысяча один"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic)
|
||||
optional_sign = pynini.closure(pynini.cross('negative: "true" ', "минус "), 0, 1)
|
||||
optional_quantity_part = pynini.closure(
|
||||
pynini.accep(" ")
|
||||
+ pynutil.delete('quantity: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
integer = (
|
||||
pynutil.delete('integer: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
)
|
||||
self.graph = optional_sign + integer + optional_quantity_part
|
||||
delete_tokens = self.delete_tokens(self.graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,22 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DateFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing date, e.g.
|
||||
tokens { date { day: "первое мая" } } -> "первое мая"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="date", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = pynutil.delete('day: "') + pynini.closure(RU_ALPHA | " ", 1) + pynutil.delete('"')
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,46 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DecimalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing decimal, e.g.
|
||||
tokens { decimal { integer_part: "одно целая" fractional_part: "восемь сотых} } ->
|
||||
"одно целая восемь сотых"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="decimal", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
optional_sign = pynini.closure(pynini.cross('negative: "true" ', "минус "), 0, 1)
|
||||
integer = pynutil.delete(' "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
integer_part = pynutil.delete("integer_part:") + integer
|
||||
fractional_part = pynutil.delete("fractional_part:") + integer
|
||||
optional_quantity_part = pynini.closure(
|
||||
pynini.accep(" ")
|
||||
+ pynutil.delete('quantity: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
self.graph = (
|
||||
optional_sign
|
||||
+ integer_part
|
||||
+ pynini.accep(" ")
|
||||
+ fractional_part
|
||||
+ optional_quantity_part
|
||||
+ delete_space
|
||||
)
|
||||
delete_tokens = self.delete_tokens(self.graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,22 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class ElectronicFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing electronic
|
||||
e.g. electronic { username: "эй би собака эн ди точка ру" } -> "эй би собака эн ди точка ру"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="electronic", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = pynutil.delete('username: "') + pynini.closure(RU_ALPHA | " ") + pynutil.delete('"')
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,34 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NON_BREAKING_SPACE,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MeasureFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing measure, e.g.
|
||||
measure { cardinal { integer: "два килограма" } } -> "два килограма"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="measure", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = (
|
||||
pynutil.delete(' cardinal { integer: "')
|
||||
+ pynini.closure(RU_ALPHA | DAMO_SPACE | DAMO_NON_BREAKING_SPACE)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,24 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MoneyFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing money, e.g.
|
||||
money { "пять рублей" } -> пять рублей
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="money", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = pynini.closure(RU_ALPHA | " ")
|
||||
delete_tokens = self.delete_tokens(
|
||||
pynutil.delete('integer_part: "') + graph + pynutil.delete('"')
|
||||
)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,22 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_QUOTE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class OrdinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing roman numerals
|
||||
e.g. ordinal { integer: "второе" } } -> "второе"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="ordinal", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
value = pynini.closure(DAMO_NOT_QUOTE)
|
||||
graph = pynutil.delete('integer: "') + value + pynutil.delete('"')
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,26 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.ru.alphabet import RU_ALPHA
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TelephoneFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing telephone, e.g.
|
||||
telephone { number_part: "восемь девятьсот тринадцать девятьсот восемьдесят три пятьдесят шесть ноль один" } -> "восемь девятьсот тринадцать девятьсот восемьдесят три пятьдесят шесть ноль один"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="telephone", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = (
|
||||
pynutil.delete('number_part: "')
|
||||
+ pynini.closure(RU_ALPHA | " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,51 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TimeFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing electronic
|
||||
e.g. time { hours: "два часа пятнадцать минут" } -> "два часа пятнадцать минут"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="time", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
hour = (
|
||||
pynutil.delete("hours:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
minutes = (
|
||||
pynutil.delete("minutes:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
self.graph = (
|
||||
hour
|
||||
+ delete_space
|
||||
+ insert_space
|
||||
+ minutes
|
||||
+ delete_space
|
||||
+ pynutil.delete("preserve_order: true")
|
||||
)
|
||||
self.graph |= hour + delete_space
|
||||
self.graph |= minutes + delete_space + insert_space + hour + delete_space
|
||||
|
||||
delete_tokens = self.delete_tokens(self.graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,55 @@
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.whitelist import WhiteListFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.cardinal import CardinalFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.date import DateFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.decimal import DecimalFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.electronic import ElectronicFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.measure import MeasureFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.money import MoneyFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.ordinal import OrdinalFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.telephone import TelephoneFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.time import TimeFst
|
||||
|
||||
|
||||
class VerbalizeFst(GraphFst):
|
||||
"""
|
||||
Composes other verbalizer grammars.
|
||||
For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File.
|
||||
More details to deployment at NeMo/tools/text_processing_deployment.
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="verbalize", kind="verbalize", deterministic=deterministic)
|
||||
cardinal = CardinalFst()
|
||||
cardinal_graph = cardinal.fst
|
||||
ordinal_graph = OrdinalFst().fst
|
||||
decimal = DecimalFst()
|
||||
decimal_graph = decimal.fst
|
||||
date = DateFst()
|
||||
date_graph = date.fst
|
||||
measure = MeasureFst()
|
||||
measure_graph = measure.fst
|
||||
electronic = ElectronicFst()
|
||||
electronic_graph = electronic.fst
|
||||
whitelist_graph = WhiteListFst().fst
|
||||
money_graph = MoneyFst().fst
|
||||
telephone_graph = TelephoneFst().fst
|
||||
time_graph = TimeFst().fst
|
||||
|
||||
graph = (
|
||||
measure_graph
|
||||
| cardinal_graph
|
||||
| decimal_graph
|
||||
| ordinal_graph
|
||||
| date_graph
|
||||
| electronic_graph
|
||||
| money_graph
|
||||
| whitelist_graph
|
||||
| telephone_graph
|
||||
| time_graph
|
||||
)
|
||||
self.fst = graph
|
||||
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
generator_main,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.verbalizers.word import WordFst
|
||||
from fun_text_processing.text_normalization.ru.verbalizers.verbalize import VerbalizeFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class VerbalizeFinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer that verbalizes an entire sentence, e.g.
|
||||
tokens { name: "its" } tokens { time { hours: "12" minutes: "30" } } tokens { name: "now" } -> its 12:30 now
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache.
|
||||
overwrite_cache: set to True to overwrite .far files
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, deterministic: bool = True, cache_dir: str = None, overwrite_cache: bool = False
|
||||
):
|
||||
super().__init__(name="verbalize_final", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
far_file = None
|
||||
if cache_dir is not None and cache_dir != "None":
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
far_file = os.path.join(
|
||||
cache_dir, f"ru_tn_{deterministic}_deterministic_verbalizer.far"
|
||||
)
|
||||
if not overwrite_cache and far_file and os.path.exists(far_file):
|
||||
self.fst = pynini.Far(far_file, mode="r")["verbalize"]
|
||||
logging.info(f"VerbalizeFinalFst graph was restored from {far_file}.")
|
||||
else:
|
||||
|
||||
verbalize = VerbalizeFst().fst
|
||||
word = WordFst().fst
|
||||
types = verbalize | word
|
||||
graph = (
|
||||
pynutil.delete("tokens")
|
||||
+ delete_space
|
||||
+ pynutil.delete("{")
|
||||
+ delete_space
|
||||
+ types
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space
|
||||
self.fst = graph.optimize()
|
||||
|
||||
if far_file:
|
||||
generator_main(far_file, {"verbalize": self.fst})
|
||||
logging.info(f"VerbalizeFinalFst grammars are saved to {far_file}.")
|
||||
Reference in New Issue
Block a user