chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.tokenize_and_classify import (
|
||||
ClassifyFst,
|
||||
)
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.verbalize import VerbalizeFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.verbalize_final import (
|
||||
VerbalizeFinalFst,
|
||||
)
|
||||
@@ -0,0 +1,384 @@
|
||||
from argparse import ArgumentParser
|
||||
from typing import List
|
||||
|
||||
import regex as re
|
||||
from fun_text_processing.text_normalization.data_loader_utils import (
|
||||
EOS_TYPE,
|
||||
Instance,
|
||||
load_files,
|
||||
training_data_to_sentences,
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
This file is for evaluation purposes.
|
||||
filter_loaded_data() cleans data (list of instances) for inverse text normalization. Filters and cleaners can be specified for each semiotic class individually.
|
||||
For example, normalized text should only include characters and whitespace characters but no punctuation.
|
||||
Cardinal unnormalized instances should contain at least one integer and all other characters are removed.
|
||||
"""
|
||||
|
||||
|
||||
class Filter:
|
||||
"""
|
||||
Filter class
|
||||
|
||||
Args:
|
||||
class_type: semiotic class used in dataset
|
||||
process_func: function to transform text
|
||||
filter_func: function to filter text
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, class_type: str, process_func: object, filter_func: object):
|
||||
self.class_type = class_type
|
||||
self.process_func = process_func
|
||||
self.filter_func = filter_func
|
||||
|
||||
def filter(self, instance: Instance) -> bool:
|
||||
"""
|
||||
filter function
|
||||
|
||||
Args:
|
||||
filters given instance with filter function
|
||||
|
||||
Returns: True if given instance fulfills criteria or does not belong to class type
|
||||
"""
|
||||
if instance.token_type != self.class_type:
|
||||
return True
|
||||
return self.filter_func(instance)
|
||||
|
||||
def process(self, instance: Instance) -> Instance:
|
||||
"""
|
||||
process function
|
||||
|
||||
Args:
|
||||
processes given instance with process function
|
||||
|
||||
Returns: processed instance if instance belongs to expected class type or original instance
|
||||
"""
|
||||
if instance.token_type != self.class_type:
|
||||
return instance
|
||||
return self.process_func(instance)
|
||||
|
||||
|
||||
def filter_cardinal_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_cardinal_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
un_normalized = re.sub(r"[^0-9]", "", un_normalized)
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_ordinal_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"(st|nd|rd|th)\s*$", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_ordinal_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
un_normalized = re.sub(r"[,\s]", "", un_normalized)
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_decimal_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_decimal_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
un_normalized = re.sub(r",", "", un_normalized)
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_measure_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_measure_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
un_normalized = re.sub(r",", "", un_normalized)
|
||||
un_normalized = re.sub(r"m2", "m²", un_normalized)
|
||||
un_normalized = re.sub(r"(\d)([^\d.\s])", r"\1 \2", un_normalized)
|
||||
normalized = re.sub(r"[^a-z\s]", "", normalized)
|
||||
normalized = re.sub(r"per ([a-z\s]*)s$", r"per \1", normalized)
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_money_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_money_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
un_normalized = re.sub(r",", "", un_normalized)
|
||||
un_normalized = re.sub(r"a\$", r"$", un_normalized)
|
||||
un_normalized = re.sub(r"us\$", r"$", un_normalized)
|
||||
un_normalized = re.sub(r"(\d)m\s*$", r"\1 juta", un_normalized)
|
||||
un_normalized = re.sub(r"(\d)bn?\s*$", r"\1 milyar", un_normalized)
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_time_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_time_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
un_normalized = re.sub(r": ", ":", un_normalized)
|
||||
un_normalized = re.sub(r"(\d)\s?a\s?m\s?", r"\1 a.m.", un_normalized)
|
||||
un_normalized = re.sub(r"(\d)\s?p\s?m\s?", r"\1 p.m.", un_normalized)
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_plain_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_plain_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_punct_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_punct_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_date_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_date_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
un_normalized = re.sub(r",", "", un_normalized)
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_letters_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_letters_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_verbatim_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_verbatim_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_digit_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_digit_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_telephone_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_telephone_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_electronic_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_electronic_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_fraction_1(instance: Instance) -> bool:
|
||||
ok = re.search(r"[0-9]", instance.un_normalized)
|
||||
return ok
|
||||
|
||||
|
||||
def process_fraction_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
def filter_address_1(instance: Instance) -> bool:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
def process_address_1(instance: Instance) -> Instance:
|
||||
un_normalized = instance.un_normalized
|
||||
normalized = instance.normalized
|
||||
normalized = re.sub(r"[^a-z ]", "", normalized)
|
||||
return Instance(
|
||||
token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized
|
||||
)
|
||||
|
||||
|
||||
filters = []
|
||||
filters.append(
|
||||
Filter(class_type="CARDINAL", process_func=process_cardinal_1, filter_func=filter_cardinal_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="ORDINAL", process_func=process_ordinal_1, filter_func=filter_ordinal_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="DECIMAL", process_func=process_decimal_1, filter_func=filter_decimal_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="MEASURE", process_func=process_measure_1, filter_func=filter_measure_1)
|
||||
)
|
||||
filters.append(Filter(class_type="MONEY", process_func=process_money_1, filter_func=filter_money_1))
|
||||
filters.append(Filter(class_type="TIME", process_func=process_time_1, filter_func=filter_time_1))
|
||||
|
||||
filters.append(Filter(class_type="DATE", process_func=process_date_1, filter_func=filter_date_1))
|
||||
filters.append(Filter(class_type="PLAIN", process_func=process_plain_1, filter_func=filter_plain_1))
|
||||
filters.append(Filter(class_type="PUNCT", process_func=process_punct_1, filter_func=filter_punct_1))
|
||||
filters.append(
|
||||
Filter(class_type="LETTERS", process_func=process_letters_1, filter_func=filter_letters_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="VERBATIM", process_func=process_verbatim_1, filter_func=filter_verbatim_1)
|
||||
)
|
||||
filters.append(Filter(class_type="DIGIT", process_func=process_digit_1, filter_func=filter_digit_1))
|
||||
filters.append(
|
||||
Filter(class_type="TELEPHONE", process_func=process_telephone_1, filter_func=filter_telephone_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(
|
||||
class_type="ELECTRONIC", process_func=process_electronic_1, filter_func=filter_electronic_1
|
||||
)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="FRACTION", process_func=process_fraction_1, filter_func=filter_fraction_1)
|
||||
)
|
||||
filters.append(
|
||||
Filter(class_type="ADDRESS", process_func=process_address_1, filter_func=filter_address_1)
|
||||
)
|
||||
filters.append(Filter(class_type=EOS_TYPE, process_func=lambda x: x, filter_func=lambda x: True))
|
||||
|
||||
|
||||
def filter_loaded_data(data: List[Instance], verbose: bool = False) -> List[Instance]:
|
||||
"""
|
||||
Filters list of instances
|
||||
|
||||
Args:
|
||||
data: list of instances
|
||||
|
||||
Returns: filtered and transformed list of instances
|
||||
"""
|
||||
updates_instances = []
|
||||
for instance in data:
|
||||
updated_instance = False
|
||||
for fil in filters:
|
||||
if fil.class_type == instance.token_type and fil.filter(instance):
|
||||
instance = fil.process(instance)
|
||||
updated_instance = True
|
||||
if updated_instance:
|
||||
if verbose:
|
||||
print(instance)
|
||||
updates_instances.append(instance)
|
||||
return updates_instances
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--input", help="input file path", type=str, default="./id_with_types/output-00001-of-00100"
|
||||
)
|
||||
parser.add_argument("--verbose", help="print filtered instances", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
file_path = args.input
|
||||
|
||||
print("Loading training data: " + file_path)
|
||||
instance_list = load_files([file_path]) # List of instances
|
||||
filtered_instance_list = filter_loaded_data(instance_list, args.verbose)
|
||||
training_data_to_sentences(filtered_instance_list)
|
||||
@@ -0,0 +1,37 @@
|
||||
$ dolar
|
||||
$ dolar Amerika
|
||||
$ dolar amerika serikat
|
||||
Rp rupiah
|
||||
IDR rupiah
|
||||
£ pound inggris
|
||||
€ euro
|
||||
₩ won
|
||||
nzd dolar selandia baru
|
||||
rs rupee
|
||||
chf swiss franc
|
||||
dkk kroner Denmark
|
||||
fim markka finlandia
|
||||
aed dirham emirat arab
|
||||
¥ yen
|
||||
czk koruna ceko
|
||||
mro ouguiya mauritania
|
||||
pkr rupee pakistan
|
||||
crc usus besar kosta rika
|
||||
hk$ dollar Hongkong
|
||||
npr rupee nepal
|
||||
awg florin aruba
|
||||
nok kroner norwegia
|
||||
tzs shilling tanzan
|
||||
sek kronor Swedia
|
||||
cyp pound siprus
|
||||
r nyata
|
||||
sar riyal saudi
|
||||
cve escudo tanjung verde
|
||||
rsd dinar serbia
|
||||
dm tanda jerman
|
||||
shp santo helena pound
|
||||
php peso filipina
|
||||
cad dolar Kanada
|
||||
ssp pound sunda selatan
|
||||
scr rupiah seychelles
|
||||
mvr rufiyaa maldivian
|
||||
|
@@ -0,0 +1,11 @@
|
||||
com
|
||||
uk
|
||||
fr
|
||||
net
|
||||
br
|
||||
in
|
||||
ru
|
||||
de
|
||||
it
|
||||
ai
|
||||
id
|
||||
|
@@ -0,0 +1,17 @@
|
||||
g mail gmail
|
||||
gmail
|
||||
n vidia nvidia
|
||||
nvidia
|
||||
outlook
|
||||
hotmail
|
||||
yahoo
|
||||
aol
|
||||
gmx
|
||||
msn
|
||||
live
|
||||
yandex
|
||||
orange
|
||||
wanadoo
|
||||
web
|
||||
comcast
|
||||
google
|
||||
|
@@ -0,0 +1,130 @@
|
||||
. dot
|
||||
- berlari
|
||||
- tanda penghubung
|
||||
_ menggarisbawahi
|
||||
! tanda seru
|
||||
$ tanda dollar
|
||||
& simbol untuk 'dan
|
||||
' mengutip
|
||||
* asterisk
|
||||
+ plus
|
||||
/ memotong
|
||||
? tanda tanya
|
||||
^ sirkomfleks
|
||||
` kutipan tunggal yang tepat
|
||||
{ penyangga kiri
|
||||
| batang vertikal
|
||||
} penjepit kanan
|
||||
~ pasang surut
|
||||
, koma
|
||||
% persen
|
||||
# tanda pagar
|
||||
= sama dengan
|
||||
@ at
|
||||
_ garis bawah
|
||||
~ tilde
|
||||
≥ lebih besar dari atau sama dengan
|
||||
≤ lebih kecil dari atau sama dengan
|
||||
≠ tidak sama dengan
|
||||
≈ mendekati sama dengan
|
||||
± kurang lebih
|
||||
× kali
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
F F
|
||||
G G
|
||||
H H
|
||||
I I
|
||||
J J
|
||||
K K
|
||||
L L
|
||||
M M
|
||||
N N
|
||||
O O
|
||||
P P
|
||||
Q Q
|
||||
R R
|
||||
S S
|
||||
T T
|
||||
U U
|
||||
V V
|
||||
W W
|
||||
X X
|
||||
Y Y
|
||||
Z Z
|
||||
a A
|
||||
b B
|
||||
c C
|
||||
d D
|
||||
e E
|
||||
f F
|
||||
g G
|
||||
h H
|
||||
i I
|
||||
j J
|
||||
k K
|
||||
l L
|
||||
m M
|
||||
n N
|
||||
o O
|
||||
p P
|
||||
q Q
|
||||
r R
|
||||
s S
|
||||
t T
|
||||
u U
|
||||
v V
|
||||
w W
|
||||
x X
|
||||
y Y
|
||||
z Z
|
||||
Α alfa
|
||||
Β beta
|
||||
Γ gamma
|
||||
Δ delta
|
||||
Ε epsilon
|
||||
Ζ zeta
|
||||
Θ theta
|
||||
Ι iota
|
||||
Κ kappa
|
||||
∧ lambda
|
||||
Μ mu
|
||||
Ν nu
|
||||
Ξ ksi
|
||||
Ο omikron
|
||||
∏ pi
|
||||
Ρ rho
|
||||
∑ sigma
|
||||
Τ tau
|
||||
Υ upsilon
|
||||
Φ phi
|
||||
Χ khi
|
||||
Ψ psi
|
||||
Ω omega
|
||||
α alfa
|
||||
β beta
|
||||
γ gamma
|
||||
δ delta
|
||||
ε epsilon
|
||||
ζ zeta
|
||||
η eta
|
||||
θ theta
|
||||
ι iota
|
||||
κ kappa
|
||||
λ lambda
|
||||
μ mu
|
||||
ν nu
|
||||
ξ ksi
|
||||
ο omikron
|
||||
π pi
|
||||
ρ rho
|
||||
σ sigma
|
||||
τ tau
|
||||
υ upsilon
|
||||
φ phi
|
||||
χ khi
|
||||
ψ psi
|
||||
ω omega
|
||||
|
@@ -0,0 +1,4 @@
|
||||
k ribu
|
||||
m juta
|
||||
b milyar
|
||||
t triliun
|
||||
|
@@ -0,0 +1,361 @@
|
||||
fahrenheit f
|
||||
celsius c
|
||||
kilometer km
|
||||
meter m
|
||||
sentimeter cm
|
||||
milimeter mm
|
||||
hektar ha
|
||||
mil mi
|
||||
meter persegi m²
|
||||
kilometer persegi km²
|
||||
kaki ft
|
||||
persen %
|
||||
hertz hz
|
||||
kilowat kw
|
||||
daya kuda hp
|
||||
miligram mg
|
||||
kilogram kg
|
||||
gigahertz ghz
|
||||
kilohertz khz
|
||||
megahertz mhz
|
||||
volt v
|
||||
jam h
|
||||
mega coulomb mc
|
||||
kedua s
|
||||
nanometer nm
|
||||
revolusi per menit rpm
|
||||
menit min
|
||||
mili ampere mA
|
||||
persen %
|
||||
kilo watt jam kwh
|
||||
meter kubik m³
|
||||
mil per jam mph
|
||||
tera watt tw
|
||||
mili volt mv
|
||||
megawatt mw
|
||||
mikrometer μm
|
||||
terabyte tb
|
||||
c c cc
|
||||
gram g
|
||||
dalton da
|
||||
suasana atm
|
||||
ohm ω
|
||||
desibel db
|
||||
peta kedua ps
|
||||
ons oz
|
||||
hekto liter hl
|
||||
mikrogram μg
|
||||
petagram pg
|
||||
gigabyte gb
|
||||
kilobit kb
|
||||
elektron volt ev
|
||||
megabita mb
|
||||
kilobyte kb
|
||||
kilobit per detik kbps
|
||||
megabit per detik mbps
|
||||
batu st
|
||||
kilo liter kl
|
||||
tera joule tj
|
||||
kilo volt kv
|
||||
mega volt mv
|
||||
kilonewton kn
|
||||
megameter mm
|
||||
satuan astronomi au
|
||||
halaman yd
|
||||
radian rad
|
||||
lumen lm
|
||||
hekto detik hs
|
||||
tahi lalat mol
|
||||
giga pascal gpa
|
||||
mililiter ml
|
||||
gigawatt gw
|
||||
mega ampere ma
|
||||
simpul kt
|
||||
kekuatan kilogram kgf
|
||||
nano gram ng
|
||||
nanodetik ns
|
||||
mega siemens ms
|
||||
batang bar
|
||||
giga liter gl
|
||||
mikrodetik μs
|
||||
desi ampere da
|
||||
pascal pa
|
||||
desi detik ds
|
||||
mili detik ms
|
||||
meteran desi dm
|
||||
kubik desi meter dm³
|
||||
satuan massa atom amu
|
||||
megabita mb
|
||||
mega farad mf
|
||||
becquerel bq
|
||||
petabit pb
|
||||
milimeter persegi mm²
|
||||
sentimeter persegi cm²
|
||||
mil persegi sq mi
|
||||
kaki persegi sq ft
|
||||
kilopascal kpa
|
||||
candela cd
|
||||
tera liter tl
|
||||
mega detik ms
|
||||
megapascal mpa
|
||||
meteran peta pm
|
||||
peta byte pb
|
||||
giga watt jam gwh
|
||||
kilo kalori kcal
|
||||
abu-abu gy
|
||||
saringan sv
|
||||
kelas seratus cwt
|
||||
c c cc
|
||||
kaki persegi sq ft
|
||||
inci persegi sq in
|
||||
kaki persegi sqft
|
||||
kaki persegi SqFt
|
||||
milidetik msec
|
||||
kilowatt jam kw·h
|
||||
miliampere-jam mA⋅h
|
||||
kilokalori kcal
|
||||
kilokalori kCal
|
||||
kilokalori Kcal
|
||||
milimeter merkuri mmhg
|
||||
milimeter merkuri mmHg
|
||||
milimeter persegi mm2
|
||||
milimeter kubik mm3
|
||||
sentimeter persegi cm2
|
||||
sentimeter kubik cm3
|
||||
kilometer persegi km2
|
||||
kilometer kubik km3
|
||||
desimeter persegi dm2
|
||||
desimeter kubik dm3
|
||||
detik sec
|
||||
jam hrs
|
||||
mil per jam mph
|
||||
kiloherts khz
|
||||
kiloherts kHz
|
||||
megahertz mhz
|
||||
megahertz mHz
|
||||
gigahertz ghz
|
||||
gigahertz gHz
|
||||
kilowatt jam kwh
|
||||
mol mol
|
||||
sendok the tsp
|
||||
kilopascal kPa
|
||||
volume vol
|
||||
volume Vol
|
||||
rotasi per menit rpm
|
||||
detak per menit bpm
|
||||
galon gal
|
||||
pascal pa
|
||||
megapascal mpa
|
||||
miliampere-jam mah
|
||||
menit min
|
||||
detik SEC
|
||||
kalori cal
|
||||
kilokalori Cal
|
||||
meter persegi m2
|
||||
meter kubik m3
|
||||
milimeter mm
|
||||
sentimeter cm
|
||||
sentimeter CM
|
||||
kilometer km
|
||||
kilometer KM
|
||||
miligram mg
|
||||
kilogram kg
|
||||
kilogram KG
|
||||
jam hr
|
||||
hertz hz
|
||||
hertz Hz
|
||||
mililiter ml
|
||||
mililiter mL
|
||||
miliampere mA
|
||||
sentimeter kubik cc
|
||||
piksel px
|
||||
piksel PX
|
||||
volt v
|
||||
volt V
|
||||
kilovolt kv
|
||||
kilovolt kV
|
||||
hektar ha
|
||||
ekar ac
|
||||
karat ct
|
||||
inci in
|
||||
kaki ft
|
||||
yard yd
|
||||
nanometer nm
|
||||
desimeter dm
|
||||
kilobyte kb
|
||||
megabyte mb
|
||||
gigabyte gb
|
||||
terabyte tb
|
||||
kilobyte KB
|
||||
megabyte MB
|
||||
gigabyte GB
|
||||
terabyte TB
|
||||
daya kuda hp
|
||||
desibel db
|
||||
desibel dB
|
||||
kilojoule kj
|
||||
kilojoule kJ
|
||||
ons oz
|
||||
kilowatt kw
|
||||
kilowatt KW
|
||||
joule j
|
||||
joule J
|
||||
gram g
|
||||
gram G
|
||||
liter l
|
||||
liter L
|
||||
meter m
|
||||
ohm-meter Ω·m
|
||||
mikrometer μm
|
||||
mikrogram μg
|
||||
mikroampere μA
|
||||
derajat Celsius °c
|
||||
derajat Celsius ˚c
|
||||
derajat Fahrenheit °f
|
||||
derajat Fahrenheit ˚f
|
||||
milimeter persegi mm²
|
||||
milimeter kubik mm³
|
||||
sentimeter persegi cm²
|
||||
sentimeter kubik cm³
|
||||
kilometer persegi km²
|
||||
kilometer kubik km³
|
||||
desimeter kubik dm³
|
||||
meter persegi m²
|
||||
meter kubik m³
|
||||
derajat °
|
||||
derajat ˚
|
||||
derajat Celsius ℃
|
||||
derajat Fahrenheit ℉
|
||||
ohm Ω
|
||||
mikrometer μm
|
||||
milimeter persegi mm2
|
||||
milimeter kubik mm3
|
||||
milimeter mm
|
||||
sentimeter persegi cm2
|
||||
sentimeter kubik cm3
|
||||
sentimeter cm
|
||||
sentimeter CM
|
||||
kilometer persegi km2
|
||||
kilometer kubik km3
|
||||
kilometer km
|
||||
kilometer KM
|
||||
desimeter persegi dm2
|
||||
desimeter kubik dm3
|
||||
meter persegi m2
|
||||
meter kubik m3
|
||||
kaki persegi sq ft
|
||||
kaki persegi sq. ft
|
||||
kaki persegi sq.ft
|
||||
kaki persegi sqft
|
||||
kaki persegi SqFt
|
||||
inci persegi sq in
|
||||
mikrogram μg
|
||||
miligram mg
|
||||
kilogram kg
|
||||
kilogram KG
|
||||
milidetik msec
|
||||
detik sec
|
||||
jam hr
|
||||
jam hrs
|
||||
meter per detik m/s
|
||||
kilometer per jam km/h
|
||||
mil per jam mph
|
||||
bit per detik bit/s
|
||||
bit per detik Bit/s
|
||||
byte per detik byte/s
|
||||
byte per detik Byte/s
|
||||
derajat Celsius °c
|
||||
derajat Celsius ˚c
|
||||
derajat Fahrenheit °f
|
||||
derajat Fahrenheit ˚f
|
||||
kilokalori kcal
|
||||
kilokalori kCal
|
||||
kilokalori Kcal
|
||||
ons cairan fl.oz
|
||||
farad per meter F/m
|
||||
gram per liter g/l
|
||||
gram per mililiter g/mL
|
||||
hertz hz
|
||||
hertz Hz
|
||||
kiloherts khz
|
||||
kiloherts kHz
|
||||
megahertz mhz
|
||||
megahertz mHz
|
||||
gigahertz ghz
|
||||
gigahertz gHz
|
||||
kilometer per jam km/h
|
||||
kilowatt per jam kw/h
|
||||
kilowatt jam kw·h
|
||||
kilowatt jam kS·h
|
||||
kilowatt jam kwh
|
||||
kilowatt jam kSh
|
||||
mililiter ml
|
||||
mililiter mL
|
||||
miligram per mililiter mg/ml
|
||||
miligram per mililiter mg/mL
|
||||
miligram per liter mg/l
|
||||
miligram per liter mg/L
|
||||
miliampere mA
|
||||
miliampere-jam mA⋅h
|
||||
mol mol
|
||||
ohm-meter Ω·m
|
||||
siemens per meter S/m
|
||||
sendok the tsp
|
||||
mikroampere μA
|
||||
kilopascal kPa
|
||||
milimeter merkuri mmhg
|
||||
milimeter merkuri mmHg
|
||||
volume vol
|
||||
volume Vol
|
||||
sentimeter kubik cc
|
||||
rotasi per menit rpm
|
||||
rotasi per menit r/min
|
||||
detak per menit bpm
|
||||
piksel px
|
||||
piksel PX
|
||||
volt v
|
||||
volt V
|
||||
kilovolt kv
|
||||
kilovolt kV
|
||||
hektar ha
|
||||
ekar ac
|
||||
karat ct
|
||||
liter l
|
||||
liter L
|
||||
galon gal
|
||||
mol mol
|
||||
pascal pa
|
||||
megapascal mpa
|
||||
miliampere ma
|
||||
miliampere-jam mah
|
||||
inci in
|
||||
kaki ft
|
||||
yard yd
|
||||
nanometer nm
|
||||
meter m
|
||||
desimeter dm
|
||||
gram g
|
||||
gram G
|
||||
kilobyte kb
|
||||
megabyte mb
|
||||
gigabyte gb
|
||||
terabyte tb
|
||||
kilobyte KB
|
||||
megabyte MB
|
||||
gigabyte GB
|
||||
terabyte TB
|
||||
daya kuda hp
|
||||
desibel db
|
||||
desibel dB
|
||||
joule j
|
||||
joule J
|
||||
kilojoule kj
|
||||
kilojoule kJ
|
||||
ons oz
|
||||
kilowatt kw
|
||||
kilowatt KW
|
||||
menit min
|
||||
detik SEC
|
||||
kalori cal
|
||||
kilokalori Cal
|
||||
inci "
|
||||
|
Can't render this file because it contains an unexpected character in line 361 and column 7.
|
@@ -0,0 +1,12 @@
|
||||
Januari
|
||||
Februari
|
||||
Maret
|
||||
April
|
||||
Mei
|
||||
Juni
|
||||
Juli
|
||||
Agustus
|
||||
September
|
||||
Oktober
|
||||
November
|
||||
Desember
|
||||
|
@@ -0,0 +1,9 @@
|
||||
satu 1
|
||||
dua 2
|
||||
tiga 3
|
||||
empat 4
|
||||
lima 5
|
||||
enam 6
|
||||
tujuh 7
|
||||
delapan 8
|
||||
sembilan 9
|
||||
|
@@ -0,0 +1 @@
|
||||
titik .
|
||||
|
@@ -0,0 +1,2 @@
|
||||
ratus
|
||||
seratus
|
||||
|
@@ -0,0 +1,10 @@
|
||||
ratus 1
|
||||
seratus 1
|
||||
dua ratus 2
|
||||
tiga ratus 3
|
||||
empat ratus 4
|
||||
lima ratus 5
|
||||
enam ratus 6
|
||||
tujuh ratus 7
|
||||
delapan ratus 8
|
||||
sembilan ratus 9
|
||||
|
@@ -0,0 +1,15 @@
|
||||
sepuluh 10
|
||||
sebelas 11
|
||||
duabelas 12
|
||||
dua belas 12
|
||||
tigabelas 13
|
||||
tiga belas 13
|
||||
empatbelas 14
|
||||
empat belas 14
|
||||
limabelas 15
|
||||
lima belas 15
|
||||
enambelas 16
|
||||
enam belas 16
|
||||
tujuh belas 17
|
||||
delapan belas 18
|
||||
sembilan belas 19
|
||||
|
@@ -0,0 +1,10 @@
|
||||
ribu 1
|
||||
seribu 1
|
||||
dua ribu 2
|
||||
tiga ribu 3
|
||||
empat ribu 4
|
||||
lima ribu 5
|
||||
enam ribu 6
|
||||
tujuh ribu 7
|
||||
delapan ribu 8
|
||||
sembilan ribu 9
|
||||
|
@@ -0,0 +1,23 @@
|
||||
ribu
|
||||
seribu
|
||||
juta
|
||||
miliar
|
||||
triliun
|
||||
milion lipat empat
|
||||
triliun
|
||||
sextillion
|
||||
septillion
|
||||
oktillion
|
||||
nonmiliar
|
||||
satu juta
|
||||
undecillion
|
||||
duodecillion
|
||||
triliun
|
||||
quattuordecillion
|
||||
quindecillion
|
||||
sexdecillion
|
||||
septendeciliun
|
||||
octodecillion
|
||||
novemdecillion
|
||||
vigintillion
|
||||
centillion
|
||||
|
@@ -0,0 +1,9 @@
|
||||
dua puluh 2
|
||||
tigapuluh 3
|
||||
empat puluh 4
|
||||
empat puluh 4
|
||||
lima puluh 5
|
||||
enam puluh 6
|
||||
tujuh puluh 7
|
||||
delapan puluh 8
|
||||
sembilan puluh 9
|
||||
|
@@ -0,0 +1 @@
|
||||
nol 0
|
||||
|
@@ -0,0 +1,9 @@
|
||||
pertama satu
|
||||
kedua dua
|
||||
ketiga tiga
|
||||
keempat empat
|
||||
kelima lima
|
||||
keenam enam
|
||||
ketujuh tujuh
|
||||
kedelapan delapan
|
||||
kesembilan sembilan
|
||||
|
@@ -0,0 +1 @@
|
||||
keduabelas dua belas
|
||||
|
@@ -0,0 +1,83 @@
|
||||
deer
|
||||
fish
|
||||
sheep
|
||||
foot feet
|
||||
goose geese
|
||||
man men
|
||||
mouse mice
|
||||
tooth teeth
|
||||
woman women
|
||||
won
|
||||
child children
|
||||
ox oxen
|
||||
wife wives
|
||||
wolf wolves
|
||||
analysis analyses
|
||||
criterion criteria
|
||||
lbs
|
||||
focus foci
|
||||
percent
|
||||
hertz
|
||||
kroner krone
|
||||
inch inches
|
||||
calory calories
|
||||
yen
|
||||
megahertz
|
||||
gigahertz
|
||||
kilohertz
|
||||
hertz
|
||||
CC
|
||||
c c
|
||||
horsepower
|
||||
hundredweight
|
||||
kilogram force kilograms force
|
||||
mega siemens
|
||||
revolution per minute revolutions per minute
|
||||
mile per hour miles per hour
|
||||
megabit per second megabits per second
|
||||
square foot square feet
|
||||
kilobit per second kilobits per second
|
||||
degree Celsius degrees Celsius
|
||||
degree Fahrenheit degrees Fahrenheit
|
||||
ATM
|
||||
AU
|
||||
BQ
|
||||
CC
|
||||
CD
|
||||
DA
|
||||
EB
|
||||
EV
|
||||
F
|
||||
GB
|
||||
G
|
||||
GL
|
||||
GPA
|
||||
GY
|
||||
HA
|
||||
H
|
||||
HL
|
||||
GP
|
||||
HS
|
||||
KB
|
||||
KL
|
||||
KN
|
||||
KT
|
||||
KV
|
||||
LM
|
||||
MA
|
||||
MA
|
||||
MB
|
||||
MC
|
||||
MF
|
||||
M
|
||||
MM
|
||||
MS
|
||||
MV
|
||||
MW
|
||||
PB
|
||||
PG
|
||||
PS
|
||||
S
|
||||
TB
|
||||
YB
|
||||
ZB
|
||||
|
@@ -0,0 +1,59 @@
|
||||
1 59
|
||||
2 58
|
||||
3 57
|
||||
4 56
|
||||
5 55
|
||||
6 54
|
||||
7 53
|
||||
8 52
|
||||
9 51
|
||||
10 50
|
||||
11 49
|
||||
12 48
|
||||
13 47
|
||||
14 46
|
||||
15 45
|
||||
16 44
|
||||
17 43
|
||||
18 42
|
||||
19 41
|
||||
20 40
|
||||
21 39
|
||||
22 38
|
||||
23 37
|
||||
24 36
|
||||
25 35
|
||||
26 34
|
||||
27 33
|
||||
28 32
|
||||
29 31
|
||||
30 30
|
||||
31 29
|
||||
32 28
|
||||
33 27
|
||||
34 26
|
||||
35 25
|
||||
36 24
|
||||
37 23
|
||||
38 22
|
||||
39 21
|
||||
40 20
|
||||
41 19
|
||||
42 18
|
||||
43 17
|
||||
44 16
|
||||
45 15
|
||||
46 14
|
||||
47 13
|
||||
48 12
|
||||
49 11
|
||||
50 10
|
||||
51 9
|
||||
52 8
|
||||
53 7
|
||||
54 6
|
||||
55 5
|
||||
56 4
|
||||
57 3
|
||||
58 2
|
||||
59 1
|
||||
|
@@ -0,0 +1,8 @@
|
||||
p m p.m.
|
||||
pm p.m.
|
||||
p.m.
|
||||
p.m p.m.
|
||||
am a.m.
|
||||
a.m.
|
||||
a.m a.m.
|
||||
a m a.m.
|
||||
|
@@ -0,0 +1,7 @@
|
||||
cst c s t
|
||||
cet c e t
|
||||
pst p s t
|
||||
est e s t
|
||||
pt p t
|
||||
et e t
|
||||
gmt g m t
|
||||
|
@@ -0,0 +1,24 @@
|
||||
satu 1
|
||||
dua 2
|
||||
tiga 3
|
||||
empat 4
|
||||
lima 5
|
||||
enam 6
|
||||
tujuh 7
|
||||
delapan 8
|
||||
sembilan 9
|
||||
sepuluh 10
|
||||
sebelas 11
|
||||
dua belas 12
|
||||
satu 13
|
||||
dua 14
|
||||
tiga 15
|
||||
empat 16
|
||||
lima 17
|
||||
enam 18
|
||||
tujuh 19
|
||||
delapan 20
|
||||
sembilan 21
|
||||
sepuluh 22
|
||||
sebelas 23
|
||||
dua belas 24
|
||||
|
@@ -0,0 +1,12 @@
|
||||
e.g. misalnya
|
||||
dr. dokter
|
||||
mr. tuan
|
||||
mrs. rindu
|
||||
st. santo
|
||||
7-eleven tujuhsebelas
|
||||
es3 e s tiga
|
||||
s&p s dan p
|
||||
ASAP a s a p
|
||||
AT&T a t dan t
|
||||
LLP l l p
|
||||
ATM a t m
|
||||
|
@@ -0,0 +1,209 @@
|
||||
import os
|
||||
import string
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from pynini import Far
|
||||
from pynini.examples import plurals
|
||||
from pynini.export import export
|
||||
from pynini.lib import byte, pynutil, utf8
|
||||
|
||||
DAMO_CHAR = utf8.VALID_UTF8_CHAR
|
||||
|
||||
DAMO_DIGIT = byte.DIGIT
|
||||
DAMO_LOWER = pynini.union(*string.ascii_lowercase).optimize()
|
||||
DAMO_UPPER = pynini.union(*string.ascii_uppercase).optimize()
|
||||
DAMO_ALPHA = pynini.union(DAMO_LOWER, DAMO_UPPER).optimize()
|
||||
DAMO_ALNUM = pynini.union(DAMO_DIGIT, DAMO_ALPHA).optimize()
|
||||
DAMO_HEX = pynini.union(*string.hexdigits).optimize()
|
||||
DAMO_NON_BREAKING_SPACE = "\u00A0"
|
||||
DAMO_SPACE = " "
|
||||
DAMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", "\u00A0").optimize()
|
||||
DAMO_NOT_SPACE = pynini.difference(DAMO_CHAR, DAMO_WHITE_SPACE).optimize()
|
||||
DAMO_NOT_QUOTE = pynini.difference(DAMO_CHAR, r'"').optimize()
|
||||
|
||||
DAMO_PUNCT = pynini.union(*map(pynini.escape, string.punctuation)).optimize()
|
||||
DAMO_GRAPH = pynini.union(DAMO_ALNUM, DAMO_PUNCT).optimize()
|
||||
|
||||
DAMO_SIGMA = pynini.closure(DAMO_CHAR)
|
||||
|
||||
delete_space = pynutil.delete(pynini.closure(DAMO_WHITE_SPACE))
|
||||
delete_zero_or_one_space = pynutil.delete(pynini.closure(DAMO_WHITE_SPACE, 0, 1))
|
||||
insert_space = pynutil.insert(" ")
|
||||
delete_extra_space = pynini.cross(pynini.closure(DAMO_WHITE_SPACE, 1), " ")
|
||||
delete_preserve_order = pynini.closure(
|
||||
pynutil.delete(" preserve_order: true")
|
||||
| (pynutil.delete(' field_order: "') + DAMO_NOT_QUOTE + pynutil.delete('"'))
|
||||
)
|
||||
|
||||
suppletive = pynini.string_file(get_abs_path("data/suppletive.tsv"))
|
||||
# _v = pynini.union("a", "e", "i", "o", "u")
|
||||
_c = pynini.union(
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
)
|
||||
_ies = DAMO_SIGMA + _c + pynini.cross("y", "ies")
|
||||
_es = DAMO_SIGMA + pynini.union("s", "sh", "ch", "x", "z") + pynutil.insert("es")
|
||||
_s = DAMO_SIGMA + pynutil.insert("s")
|
||||
|
||||
graph_plural = plurals._priority_union(
|
||||
suppletive,
|
||||
plurals._priority_union(_ies, plurals._priority_union(_es, _s, DAMO_SIGMA), DAMO_SIGMA),
|
||||
DAMO_SIGMA,
|
||||
).optimize()
|
||||
|
||||
SINGULAR_TO_PLURAL = graph_plural
|
||||
PLURAL_TO_SINGULAR = pynini.invert(graph_plural)
|
||||
TO_LOWER = pynini.union(
|
||||
*[pynini.cross(x, y) for x, y in zip(string.ascii_uppercase, string.ascii_lowercase)]
|
||||
)
|
||||
TO_UPPER = pynini.invert(TO_LOWER)
|
||||
MIN_NEG_WEIGHT = -0.0001
|
||||
MIN_POS_WEIGHT = 0.0001
|
||||
|
||||
|
||||
def generator_main(file_name: str, graphs: Dict[str, "pynini.FstLike"]):
|
||||
"""
|
||||
Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name.
|
||||
|
||||
Args:
|
||||
file_name: exported file name
|
||||
graphs: Mapping of a rule name and Pynini WFST graph to be exported
|
||||
"""
|
||||
exporter = export.Exporter(file_name)
|
||||
for rule, graph in graphs.items():
|
||||
exporter[rule] = graph.optimize()
|
||||
exporter.close()
|
||||
print(f"Created {file_name}")
|
||||
|
||||
|
||||
def get_plurals(fst):
|
||||
"""
|
||||
Given singular returns plurals
|
||||
|
||||
Args:
|
||||
fst: Fst
|
||||
|
||||
Returns plurals to given singular forms
|
||||
"""
|
||||
return SINGULAR_TO_PLURAL @ fst
|
||||
|
||||
|
||||
def get_singulars(fst):
|
||||
"""
|
||||
Given plural returns singulars
|
||||
|
||||
Args:
|
||||
fst: Fst
|
||||
|
||||
Returns singulars to given plural forms
|
||||
"""
|
||||
return PLURAL_TO_SINGULAR @ fst
|
||||
|
||||
|
||||
def convert_space(fst) -> "pynini.FstLike":
|
||||
"""
|
||||
Converts space to nonbreaking space.
|
||||
Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty"
|
||||
This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it.
|
||||
|
||||
Args:
|
||||
fst: input fst
|
||||
|
||||
Returns output fst where breaking spaces are converted to non breaking spaces
|
||||
"""
|
||||
return fst @ pynini.cdrewrite(
|
||||
pynini.cross(DAMO_SPACE, DAMO_NON_BREAKING_SPACE), "", "", DAMO_SIGMA
|
||||
)
|
||||
|
||||
|
||||
class GraphFst:
|
||||
"""
|
||||
Base class for all grammar fsts.
|
||||
|
||||
Args:
|
||||
name: name of grammar class
|
||||
kind: either 'classify' or 'verbalize'
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, kind: str, deterministic: bool = True):
|
||||
self.name = name
|
||||
self.kind = kind
|
||||
self._fst = None
|
||||
self.deterministic = deterministic
|
||||
|
||||
self.far_path = Path(os.path.dirname(__file__) + "/grammars/" + kind + "/" + name + ".far")
|
||||
if self.far_exist():
|
||||
self._fst = Far(
|
||||
self.far_path, mode="r", arc_type="standard", far_type="default"
|
||||
).get_fst()
|
||||
|
||||
def far_exist(self) -> bool:
|
||||
"""
|
||||
Returns true if FAR can be loaded
|
||||
"""
|
||||
return self.far_path.exists()
|
||||
|
||||
@property
|
||||
def fst(self) -> "pynini.FstLike":
|
||||
return self._fst
|
||||
|
||||
@fst.setter
|
||||
def fst(self, fst):
|
||||
self._fst = fst
|
||||
|
||||
def add_tokens(self, fst) -> "pynini.FstLike":
|
||||
"""
|
||||
Wraps class name around to given fst
|
||||
|
||||
Args:
|
||||
fst: input fst
|
||||
|
||||
Returns:
|
||||
Fst: fst
|
||||
"""
|
||||
return pynutil.insert(f"{self.name} {{ ") + fst + pynutil.insert(" }")
|
||||
|
||||
def delete_tokens(self, fst) -> "pynini.FstLike":
|
||||
"""
|
||||
Deletes class name wrap around output of given fst
|
||||
|
||||
Args:
|
||||
fst: input fst
|
||||
|
||||
Returns:
|
||||
Fst: fst
|
||||
"""
|
||||
res = (
|
||||
pynutil.delete(f"{self.name}")
|
||||
+ delete_space
|
||||
+ pynutil.delete("{")
|
||||
+ delete_space
|
||||
+ fst
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
return res @ pynini.cdrewrite(pynini.cross("\u00A0", " "), "", "", DAMO_SIGMA)
|
||||
@@ -0,0 +1,29 @@
|
||||
2022
|
||||
300
|
||||
9999
|
||||
100001
|
||||
100
|
||||
1000
|
||||
10289
|
||||
1289
|
||||
01 2345-6789
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
20
|
||||
106
|
||||
600
|
||||
100
|
||||
100
|
||||
1 miliar
|
||||
123
|
||||
123
|
||||
24 maret
|
||||
10076
|
||||
100076
|
||||
10076 rupiah
|
||||
76
|
||||
+62 21 6539-0605
|
||||
@@ -0,0 +1,29 @@
|
||||
dua ribu dua puluh dua
|
||||
tiga ribu
|
||||
sembilan ribu sembilan ratus sembilan puluh sembilan
|
||||
seribu satu
|
||||
ribu
|
||||
seribu
|
||||
seribu dua ratus delapan puluh sembilan
|
||||
ribu dua ratus delapan puluh sembilan
|
||||
nol satu dua tiga empat lima enam tujuh delapan sembilan
|
||||
empat belas
|
||||
limabelas
|
||||
enambelas
|
||||
tujuh belas
|
||||
delapan belas
|
||||
sembilan belas
|
||||
dua puluh
|
||||
seratus enam
|
||||
enam ratus
|
||||
ratus
|
||||
seratus
|
||||
satu miliar
|
||||
seratus dua puluh tiga
|
||||
ratus dua puluh tiga
|
||||
dua puluh empat maret
|
||||
ribu tujuh puluh enam
|
||||
seribu tujuh puluh enam
|
||||
ribu tujuh puluh enam rupiah
|
||||
tujuh puluh enam
|
||||
ditambah enam dua dua satu enam lima tiga sembilan nol enam nol lima
|
||||
@@ -0,0 +1,29 @@
|
||||
dua ribu dua puluh dua 2022
|
||||
tiga ribu 3000
|
||||
sembilan ribu sembilan ratus sembilan puluh sembilan 9999
|
||||
seribu satu 1001
|
||||
ribu 1000
|
||||
seribu 1000
|
||||
seribu dua ratus delapan puluh sembilan 1289
|
||||
ribu dua ratus delapan puluh sembilan 1289
|
||||
nol satu dua tiga empat lima enam tujuh delapan sembilan 01 2345-6789
|
||||
empat belas 14
|
||||
limabelas 15
|
||||
enambelas 16
|
||||
tujuh belas 17
|
||||
delapan belas 18
|
||||
sembilan belas 19
|
||||
dua puluh 20
|
||||
seratus enam 106
|
||||
enam ratus 600
|
||||
ratus 100
|
||||
seratus 100
|
||||
satu miliar 1 miliar
|
||||
seratus dua puluh tiga 123
|
||||
ratus dua puluh tiga 123
|
||||
dua puluh empat maret 24 maret
|
||||
ribu tujuh puluh enam 1076
|
||||
seribu tujuh puluh enam 1076
|
||||
ribu tujuh puluh enam rupiah 1076 rupiah
|
||||
tujuh puluh enam 76
|
||||
ditambah enam dua dua satu enam lima tiga sembilan nol enam nol lima +62 21 6539-0605
|
||||
|
@@ -0,0 +1,161 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path, num_to_word
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_ALPHA,
|
||||
DAMO_DIGIT,
|
||||
DAMO_SIGMA,
|
||||
DAMO_SPACE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class CardinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying cardinals
|
||||
e.g. minus twenty three -> cardinal { integer: "23" negative: "-" } }
|
||||
Numbers below thirteen are not converted.
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="cardinal", kind="classify", deterministic=deterministic)
|
||||
graph_zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv"))
|
||||
graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv"))
|
||||
graph_ties = pynini.string_file(get_abs_path("data/numbers/ties.tsv"))
|
||||
graph_teen = pynini.string_file(get_abs_path("data/numbers/teen.tsv"))
|
||||
graph_hundreds = pynini.string_file(get_abs_path("data/numbers/hundreds.tsv"))
|
||||
graph_thousand = pynini.string_file(get_abs_path("data/numbers/thousand.tsv"))
|
||||
|
||||
graph_hundred = pynini.cross("ratus", "") | pynini.cross("seratus", "")
|
||||
|
||||
graph_hundred_component = pynini.union(
|
||||
graph_digit + delete_space + graph_hundred, pynutil.insert("0")
|
||||
)
|
||||
graph_hundred_component += delete_space
|
||||
graph_hundred_component += pynini.union(
|
||||
graph_teen | pynutil.insert("00"),
|
||||
(graph_ties | pynutil.insert("0")) + delete_space + (graph_digit | pynutil.insert("0")),
|
||||
)
|
||||
|
||||
graph_one_hundred_component = pynini.union(
|
||||
pynini.cross("ratus", "1") | pynini.cross("seratus", "1")
|
||||
)
|
||||
graph_one_hundred_component += delete_space
|
||||
graph_one_hundred_component += pynini.union(
|
||||
graph_teen | pynutil.insert("00"),
|
||||
(graph_ties | pynutil.insert("0")) + delete_space + (graph_digit | pynutil.insert("0")),
|
||||
)
|
||||
graph_hundred_component = graph_hundred_component | graph_one_hundred_component
|
||||
|
||||
graph_hundred_component_at_least_one_none_zero_digit = graph_hundred_component @ (
|
||||
pynini.closure(DAMO_DIGIT) + (DAMO_DIGIT - "0") + pynini.closure(DAMO_DIGIT)
|
||||
)
|
||||
self.graph_hundred_component_at_least_one_none_zero_digit = (
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
)
|
||||
graph_thousand = pynini.cross("ribu", "") | pynini.cross("seribu", "")
|
||||
graph_one_thousand_component = pynini.union(
|
||||
pynini.cross("ribu", "1") | pynini.cross("seribu", "1")
|
||||
)
|
||||
|
||||
graph_thousands = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ (pynutil.delete("ribu") | pynutil.delete("seribu")),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_thousands = graph_thousands | (pynutil.insert("00") + graph_one_thousand_component)
|
||||
|
||||
graph_million = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ (pynutil.delete("juta") | pynutil.delete("sejuta")),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_billion = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ (
|
||||
pynutil.delete("miliar")
|
||||
| pynutil.delete("semiliar")
|
||||
| pynutil.delete("milyar")
|
||||
| pynutil.delete("semilyar")
|
||||
),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_trillion = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ (pynutil.delete("triliun") | pynutil.delete("setriliun")),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_quadrillion = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ pynutil.delete("milion lipat empat"),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_quintillion = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ pynutil.delete("triliun"),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
graph_sextillion = pynini.union(
|
||||
graph_hundred_component_at_least_one_none_zero_digit
|
||||
+ delete_space
|
||||
+ pynutil.delete("sextillion"),
|
||||
pynutil.insert("000", weight=0.1),
|
||||
)
|
||||
|
||||
graph = pynini.union(
|
||||
graph_sextillion
|
||||
+ delete_space
|
||||
+ graph_quintillion
|
||||
+ delete_space
|
||||
+ graph_quadrillion
|
||||
+ delete_space
|
||||
+ graph_trillion
|
||||
+ delete_space
|
||||
+ graph_billion
|
||||
+ delete_space
|
||||
+ graph_million
|
||||
+ delete_space
|
||||
+ graph_thousands
|
||||
+ delete_space
|
||||
+ graph_hundred_component,
|
||||
# graph_digit,
|
||||
graph_zero,
|
||||
)
|
||||
|
||||
graph = graph @ pynini.union(
|
||||
pynutil.delete(pynini.closure("0"))
|
||||
+ pynini.difference(DAMO_DIGIT, "0")
|
||||
+ pynini.closure(DAMO_DIGIT),
|
||||
"0",
|
||||
)
|
||||
|
||||
labels_exception = ["nol"]
|
||||
graph_exception = pynini.union(*labels_exception)
|
||||
|
||||
graph = (
|
||||
pynini.cdrewrite(pynutil.delete("dan"), DAMO_SPACE, DAMO_SPACE, DAMO_SIGMA)
|
||||
@ (DAMO_ALPHA + DAMO_SIGMA)
|
||||
@ graph
|
||||
)
|
||||
|
||||
self.graph_no_exception = graph
|
||||
|
||||
self.graph = (pynini.project(graph, "input") - graph_exception.arcsort()) @ graph
|
||||
|
||||
optional_minus_graph = pynini.closure(
|
||||
pynutil.insert("negative: ") + pynini.cross("kurang", '"-"') + DAMO_SPACE, 0, 1
|
||||
)
|
||||
|
||||
final_graph = (
|
||||
optional_minus_graph + pynutil.insert('integer: "') + self.graph + pynutil.insert('"')
|
||||
)
|
||||
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,150 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_ALPHA,
|
||||
DAMO_DIGIT,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
graph_teen = pynini.string_file(get_abs_path("data/numbers/teen.tsv")).optimize()
|
||||
graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")).optimize()
|
||||
ties_graph = pynini.string_file(get_abs_path("data/numbers/ties.tsv")).optimize()
|
||||
|
||||
|
||||
def _get_month_graph():
|
||||
"""
|
||||
Transducer for month, e.g. march -> march
|
||||
"""
|
||||
month_graph = pynini.string_file(get_abs_path("data/months.tsv"))
|
||||
return month_graph
|
||||
|
||||
|
||||
def _get_ties_graph():
|
||||
"""
|
||||
Transducer for 20-99 e.g
|
||||
twenty three -> 23
|
||||
"""
|
||||
graph = ties_graph + (delete_space + graph_digit | pynutil.insert("0"))
|
||||
return graph
|
||||
|
||||
|
||||
def _get_range_graph():
|
||||
"""
|
||||
Transducer for decades (1**0s, 2**0s), centuries (2*00s, 1*00s), millennia (2000s)
|
||||
"""
|
||||
graph_ties = _get_ties_graph()
|
||||
graph = (graph_ties | graph_teen) + delete_space + pynini.cross("ratusan", "00s")
|
||||
graph |= pynini.cross("dua", "2") + delete_space + pynini.cross("ribuan", "000s")
|
||||
graph |= (
|
||||
(graph_ties | graph_teen)
|
||||
+ delete_space
|
||||
+ (pynini.closure(DAMO_ALPHA, 1) + (pynini.cross("ies", "y") | pynutil.delete("s")))
|
||||
@ (graph_ties | pynini.cross("sepuluh", "10"))
|
||||
+ pynutil.insert("s")
|
||||
)
|
||||
graph @= pynini.union("1", "2") + DAMO_DIGIT + DAMO_DIGIT + DAMO_DIGIT + "s"
|
||||
return graph
|
||||
|
||||
|
||||
def _get_year_graph():
|
||||
"""
|
||||
Transducer for year, e.g. twenty twenty -> 2020
|
||||
"""
|
||||
|
||||
def _get_digits_graph():
|
||||
zero = pynini.cross((pynini.accep("oh") | pynini.accep("o")), "0")
|
||||
graph = zero + delete_space + graph_digit
|
||||
graph.optimize()
|
||||
return graph
|
||||
|
||||
def _get_thousands_graph():
|
||||
graph_ties = _get_ties_graph()
|
||||
graph_hundred_component = (
|
||||
graph_digit + delete_space + pynutil.delete("ratus")
|
||||
) | pynutil.insert("0")
|
||||
graph = (
|
||||
graph_digit
|
||||
+ delete_space
|
||||
+ pynutil.delete("ribu")
|
||||
+ delete_space
|
||||
+ graph_hundred_component
|
||||
+ delete_space
|
||||
+ (graph_teen | graph_ties)
|
||||
)
|
||||
return graph
|
||||
|
||||
graph_ties = _get_ties_graph()
|
||||
graph_digits = _get_digits_graph()
|
||||
graph_thousands = _get_thousands_graph()
|
||||
year_graph = (
|
||||
# 20 19, 40 12, 2012 - assuming no limit on the year
|
||||
(graph_teen + delete_space + (graph_ties | graph_digits | graph_teen))
|
||||
| (graph_ties + delete_space + (graph_ties | graph_digits | graph_teen))
|
||||
| graph_thousands
|
||||
)
|
||||
year_graph.optimize()
|
||||
return year_graph
|
||||
|
||||
|
||||
class DateFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying date,
|
||||
e.g. january fifth twenty twelve -> date { month: "january" day: "5" year: "2012" preserve_order: true }
|
||||
e.g. the fifth of january twenty twelve -> date { day: "5" month: "january" year: "2012" preserve_order: true }
|
||||
e.g. twenty twenty -> date { year: "2012" preserve_order: true }
|
||||
|
||||
Args:
|
||||
ordinal: OrdinalFst
|
||||
"""
|
||||
|
||||
def __init__(self, ordinal: GraphFst):
|
||||
super().__init__(name="date", kind="classify")
|
||||
|
||||
ordinal_graph = ordinal.graph
|
||||
year_graph = _get_year_graph()
|
||||
YEAR_WEIGHT = 0.001
|
||||
year_graph = pynutil.add_weight(year_graph, YEAR_WEIGHT)
|
||||
month_graph = _get_month_graph()
|
||||
|
||||
month_graph = pynutil.insert('month: "') + month_graph + pynutil.insert('"')
|
||||
|
||||
day_graph = (
|
||||
pynutil.insert('day: "') + pynutil.add_weight(ordinal_graph, -0.7) + pynutil.insert('"')
|
||||
)
|
||||
graph_year = (
|
||||
delete_extra_space
|
||||
+ pynutil.insert('year: "')
|
||||
+ pynutil.add_weight(year_graph, -YEAR_WEIGHT)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
optional_graph_year = pynini.closure(
|
||||
graph_year,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
graph_mdy = month_graph + (
|
||||
(delete_extra_space + day_graph)
|
||||
| graph_year
|
||||
| (delete_extra_space + day_graph + graph_year)
|
||||
)
|
||||
graph_dmy = (
|
||||
pynutil.delete("the")
|
||||
+ delete_space
|
||||
+ day_graph
|
||||
+ delete_space
|
||||
+ pynutil.delete("of")
|
||||
+ delete_extra_space
|
||||
+ month_graph
|
||||
+ optional_graph_year
|
||||
)
|
||||
graph_year = (
|
||||
pynutil.insert('year: "') + (year_graph | _get_range_graph()) + pynutil.insert('"')
|
||||
)
|
||||
|
||||
final_graph = graph_mdy | graph_dmy | graph_year
|
||||
final_graph += pynutil.insert(" preserve_order: true")
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,100 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
import pdb
|
||||
|
||||
|
||||
def get_quantity(
|
||||
decimal: "pynini.FstLike", cardinal_up_to_hundred: "pynini.FstLike"
|
||||
) -> "pynini.FstLike":
|
||||
"""
|
||||
Returns FST that transforms either a cardinal or decimal followed by a quantity into a numeral,
|
||||
e.g. one million -> integer_part: "1" quantity: "million"
|
||||
e.g. one point five million -> integer_part: "1" fractional_part: "5" quantity: "million"
|
||||
|
||||
Args:
|
||||
decimal: decimal FST
|
||||
cardinal_up_to_hundred: cardinal FST
|
||||
"""
|
||||
numbers = cardinal_up_to_hundred @ (
|
||||
pynutil.delete(pynini.closure("0"))
|
||||
+ pynini.difference(DAMO_DIGIT, "0")
|
||||
+ pynini.closure(DAMO_DIGIT)
|
||||
)
|
||||
suffix = pynini.union("juta", "miliar", "triliun", "kuadriliun", "triliun", "sextillion")
|
||||
res = (
|
||||
pynutil.insert('integer_part: "')
|
||||
+ numbers
|
||||
+ pynutil.insert('"')
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('quantity: "')
|
||||
+ suffix
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
res |= (
|
||||
decimal
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('quantity: "')
|
||||
+ (suffix | "ribu")
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
class DecimalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying decimal
|
||||
e.g. minus twelve point five o o six billion -> decimal { negative: "true" integer_part: "12" fractional_part: "5006" quantity: "billion" }
|
||||
e.g. one billion -> decimal { integer_part: "1" quantity: "billion" }
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst):
|
||||
super().__init__(name="decimal", kind="classify")
|
||||
|
||||
cardinal_graph = cardinal.graph_no_exception
|
||||
|
||||
graph_decimal = pynini.string_file(get_abs_path("data/numbers/digit.tsv"))
|
||||
|
||||
graph_decimal |= pynini.string_file(get_abs_path("data/numbers/zero.tsv")) | pynini.cross(
|
||||
"o", "0"
|
||||
)
|
||||
|
||||
graph_decimal = pynini.closure(graph_decimal + delete_space) + graph_decimal
|
||||
self.graph = graph_decimal
|
||||
|
||||
point = pynutil.delete("point") # titik
|
||||
|
||||
optional_graph_negative = pynini.closure(
|
||||
pynutil.insert("negative: ") + pynini.cross("kurang", '"true"') + delete_extra_space,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
graph_fractional = (
|
||||
pynutil.insert('fractional_part: "') + graph_decimal + pynutil.insert('"')
|
||||
)
|
||||
graph_integer = pynutil.insert('integer_part: "') + cardinal_graph + pynutil.insert('"')
|
||||
final_graph_wo_sign = (
|
||||
pynini.closure(graph_integer + delete_extra_space, 0, 1)
|
||||
+ point
|
||||
+ delete_extra_space
|
||||
+ graph_fractional
|
||||
)
|
||||
final_graph = optional_graph_negative + final_graph_wo_sign
|
||||
|
||||
self.final_graph_wo_negative = final_graph_wo_sign | get_quantity(
|
||||
final_graph_wo_sign, cardinal.graph_hundred_component_at_least_one_none_zero_digit
|
||||
)
|
||||
final_graph |= optional_graph_negative + get_quantity(
|
||||
final_graph_wo_sign, cardinal.graph_hundred_component_at_least_one_none_zero_digit
|
||||
)
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,100 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_ALPHA,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class ElectronicFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying electronic: as URLs, email addresses, etc.
|
||||
e.g. c d f one at a b c dot e d u -> tokens { electronic { username: "cdf1" domain: "abc.edu" } }
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="electronic", kind="classify")
|
||||
|
||||
delete_extra_space = pynutil.delete(" ")
|
||||
alpha_num = (
|
||||
DAMO_ALPHA
|
||||
| pynini.string_file(get_abs_path("data/numbers/digit.tsv"))
|
||||
| pynini.string_file(get_abs_path("data/numbers/zero.tsv"))
|
||||
)
|
||||
|
||||
symbols = pynini.string_file(get_abs_path("data/electronic/symbols.tsv")).invert()
|
||||
|
||||
accepted_username = alpha_num | symbols
|
||||
process_dot = pynini.cross("dot", ".")
|
||||
username = (
|
||||
alpha_num + pynini.closure(delete_extra_space + accepted_username)
|
||||
) | pynutil.add_weight(pynini.closure(DAMO_ALPHA, 1), weight=0.0001)
|
||||
username = pynutil.insert('username: "') + username + pynutil.insert('"')
|
||||
single_alphanum = pynini.closure(alpha_num + delete_extra_space) + alpha_num
|
||||
server = single_alphanum | pynini.string_file(
|
||||
get_abs_path("data/electronic/server_name.tsv")
|
||||
)
|
||||
domain = single_alphanum | pynini.string_file(get_abs_path("data/electronic/domain.tsv"))
|
||||
domain_graph = (
|
||||
pynutil.insert('domain: "')
|
||||
+ server
|
||||
+ delete_extra_space
|
||||
+ process_dot
|
||||
+ delete_extra_space
|
||||
+ domain
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
graph = (
|
||||
username
|
||||
+ delete_extra_space
|
||||
+ pynutil.delete("at")
|
||||
+ insert_space
|
||||
+ delete_extra_space
|
||||
+ domain_graph
|
||||
)
|
||||
|
||||
############# url ###
|
||||
protocol_end = pynini.cross(pynini.union("w w w", "www"), "www")
|
||||
protocol_start = (
|
||||
pynini.cross("h t t p", "http") | pynini.cross("h t t p s", "https")
|
||||
) + pynini.cross(" colon slash slash ", "://")
|
||||
# .com,
|
||||
ending = (
|
||||
delete_extra_space
|
||||
+ symbols
|
||||
+ delete_extra_space
|
||||
+ (
|
||||
domain
|
||||
| pynini.closure(
|
||||
accepted_username + delete_extra_space,
|
||||
)
|
||||
+ accepted_username
|
||||
)
|
||||
)
|
||||
|
||||
protocol_default = (
|
||||
(
|
||||
(pynini.closure(delete_extra_space + accepted_username, 1) | server)
|
||||
| pynutil.add_weight(pynini.closure(DAMO_ALPHA, 1), weight=0.0001)
|
||||
)
|
||||
+ pynini.closure(ending, 1)
|
||||
).optimize()
|
||||
protocol = (
|
||||
pynini.closure(protocol_start, 0, 1)
|
||||
+ protocol_end
|
||||
+ delete_extra_space
|
||||
+ process_dot
|
||||
+ protocol_default
|
||||
).optimize()
|
||||
|
||||
protocol |= (
|
||||
pynini.closure(protocol_end + delete_extra_space + process_dot, 0, 1) + protocol_default
|
||||
)
|
||||
|
||||
protocol = pynutil.insert('protocol: "') + protocol.optimize() + pynutil.insert('"')
|
||||
graph |= protocol
|
||||
|
||||
final_graph = self.add_tokens(graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,11 @@
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import GraphFst
|
||||
|
||||
|
||||
class FractionFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying fraction
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="fraction", kind="classify")
|
||||
# integer_part # numerator # denominator
|
||||
@@ -0,0 +1,97 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
convert_space,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
get_singulars,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MeasureFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying measure
|
||||
e.g. minus twelve kilograms -> measure { negative: "true" cardinal { integer: "12" } units: "kg" }
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
decimal: DecimalFst
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst, decimal: GraphFst):
|
||||
super().__init__(name="measure", kind="classify")
|
||||
|
||||
cardinal_graph = cardinal.graph_no_exception
|
||||
|
||||
graph_unit = pynini.string_file(get_abs_path("data/measurements.tsv"))
|
||||
graph_unit_singular = pynini.invert(graph_unit) # singular -> abbr
|
||||
graph_unit_plural = get_singulars(graph_unit_singular) # plural -> abbr
|
||||
|
||||
optional_graph_negative = pynini.closure(
|
||||
pynutil.insert("negative: ") + pynini.cross("kurang", '"true"') + delete_extra_space,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
unit_singular = convert_space(graph_unit_singular)
|
||||
unit_plural = convert_space(graph_unit_plural)
|
||||
unit_misc = (
|
||||
pynutil.insert("/")
|
||||
+ pynutil.delete("per")
|
||||
+ delete_space
|
||||
+ convert_space(graph_unit_singular)
|
||||
)
|
||||
|
||||
unit_singular = (
|
||||
pynutil.insert('units: "')
|
||||
+ (
|
||||
unit_singular
|
||||
| unit_misc
|
||||
| pynutil.add_weight(unit_singular + delete_space + unit_misc, 0.01)
|
||||
)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
unit_plural = (
|
||||
pynutil.insert('units: "')
|
||||
+ (
|
||||
unit_plural
|
||||
| unit_misc
|
||||
| pynutil.add_weight(unit_plural + delete_space + unit_misc, 0.01)
|
||||
)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
subgraph_decimal = (
|
||||
pynutil.insert("decimal { ")
|
||||
+ optional_graph_negative
|
||||
+ decimal.final_graph_wo_negative
|
||||
+ pynutil.insert(" }")
|
||||
+ delete_extra_space
|
||||
+ unit_plural
|
||||
)
|
||||
subgraph_cardinal = (
|
||||
pynutil.insert("cardinal { ")
|
||||
+ optional_graph_negative
|
||||
+ pynutil.insert('integer: "')
|
||||
+ ((DAMO_SIGMA - "satu") @ cardinal_graph)
|
||||
+ pynutil.insert('"')
|
||||
+ pynutil.insert(" }")
|
||||
+ delete_extra_space
|
||||
+ unit_plural
|
||||
)
|
||||
subgraph_cardinal |= (
|
||||
pynutil.insert("cardinal { ")
|
||||
+ optional_graph_negative
|
||||
+ pynutil.insert('integer: "')
|
||||
+ pynini.cross("satu", "1")
|
||||
+ pynutil.insert('"')
|
||||
+ pynutil.insert(" }")
|
||||
+ delete_extra_space
|
||||
+ unit_singular
|
||||
)
|
||||
final_graph = subgraph_decimal | subgraph_cardinal
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,110 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_DIGIT,
|
||||
DAMO_NOT_SPACE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
convert_space,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
get_singulars,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MoneyFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying money
|
||||
e.g. twelve dollars and five cents -> money { integer_part: "12" fractional_part: 05 currency: "$" }
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
decimal: DecimalFst
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst, decimal: GraphFst):
|
||||
super().__init__(name="money", kind="classify")
|
||||
# quantity, integer_part, fractional_part, currency
|
||||
|
||||
cardinal_graph = cardinal.graph_no_exception
|
||||
# add support for missing hundred (only for 3 digit numbers)
|
||||
# "one fifty" -> "one hundred fifty"
|
||||
with_hundred = pynini.compose(
|
||||
pynini.closure(DAMO_NOT_SPACE)
|
||||
+ pynini.accep(" ")
|
||||
+ pynutil.insert("ratus ")
|
||||
+ DAMO_SIGMA,
|
||||
pynini.compose(cardinal_graph, DAMO_DIGIT**3),
|
||||
)
|
||||
cardinal_graph |= with_hundred
|
||||
graph_decimal_final = decimal.final_graph_wo_negative
|
||||
|
||||
unit = pynini.string_file(get_abs_path("data/currency.tsv"))
|
||||
unit_singular = pynini.invert(unit)
|
||||
unit_plural = get_singulars(unit_singular)
|
||||
|
||||
graph_unit_singular = (
|
||||
pynutil.insert('currency: "') + convert_space(unit_singular) + pynutil.insert('"')
|
||||
)
|
||||
graph_unit_plural = (
|
||||
pynutil.insert('currency: "') + convert_space(unit_plural) + pynutil.insert('"')
|
||||
)
|
||||
|
||||
add_leading_zero_to_double_digit = (DAMO_DIGIT + DAMO_DIGIT) | (
|
||||
pynutil.insert("0") + DAMO_DIGIT
|
||||
)
|
||||
# twelve dollars (and) fifty cents, zero cents
|
||||
cents_standalone = (
|
||||
pynutil.insert('fractional_part: "')
|
||||
+ pynini.union(
|
||||
pynutil.add_weight(((DAMO_SIGMA - "satu") @ cardinal_graph), -0.7)
|
||||
@ add_leading_zero_to_double_digit
|
||||
+ delete_space
|
||||
+ pynutil.delete("sen"),
|
||||
pynini.cross("satu", "01") + delete_space + pynutil.delete("sen"),
|
||||
)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
optional_cents_standalone = pynini.closure(
|
||||
delete_space
|
||||
+ pynini.closure(pynutil.delete("dan") + delete_space, 0, 1)
|
||||
+ insert_space
|
||||
+ cents_standalone,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
# twelve dollars fifty, only after integer
|
||||
optional_cents_suffix = pynini.closure(
|
||||
delete_extra_space
|
||||
+ pynutil.insert('fractional_part: "')
|
||||
+ pynutil.add_weight(cardinal_graph @ add_leading_zero_to_double_digit, -0.7)
|
||||
+ pynutil.insert('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
graph_integer = (
|
||||
pynutil.insert('integer_part: "')
|
||||
+ ((DAMO_SIGMA - "satu") @ cardinal_graph)
|
||||
+ pynutil.insert('"')
|
||||
+ delete_extra_space
|
||||
+ graph_unit_plural
|
||||
+ (optional_cents_standalone | optional_cents_suffix)
|
||||
)
|
||||
graph_integer |= (
|
||||
pynutil.insert('integer_part: "')
|
||||
+ pynini.cross("satu", "1")
|
||||
+ pynutil.insert('"')
|
||||
+ delete_extra_space
|
||||
+ graph_unit_singular
|
||||
+ (optional_cents_standalone | optional_cents_suffix)
|
||||
)
|
||||
graph_decimal = graph_decimal_final + delete_extra_space + graph_unit_plural
|
||||
graph_decimal |= pynutil.insert('currency: "$" integer_part: "0" ') + cents_standalone
|
||||
final_graph = graph_integer | graph_decimal
|
||||
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,29 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import DAMO_CHAR, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class OrdinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying ordinal
|
||||
e.g. thirteenth -> ordinal { integer: "13" }
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst):
|
||||
super().__init__(name="ordinal", kind="classify")
|
||||
|
||||
cardinal_graph = cardinal.graph_no_exception
|
||||
graph_digit = pynini.string_file(get_abs_path("data/ordinals/digit.tsv"))
|
||||
graph_teens = pynini.string_file(get_abs_path("data/ordinals/teen.tsv"))
|
||||
graph = pynini.closure(DAMO_CHAR) + pynini.union(
|
||||
graph_digit, graph_teens, pynini.cross("tieth", "ty"), pynini.cross("th", "")
|
||||
) # TODO
|
||||
|
||||
self.graph = graph @ cardinal_graph
|
||||
final_graph = pynutil.insert('integer: "') + self.graph + pynutil.insert('"')
|
||||
final_graph = self.add_tokens(final_graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,20 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class PunctuationFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying punctuation
|
||||
e.g. a, -> tokens { name: "a" } tokens { name: "," }
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="punctuation", kind="classify")
|
||||
|
||||
s = "!#$%&'()*+,-./:;<=>?@^_`{|}~"
|
||||
punct = pynini.union(*s)
|
||||
|
||||
graph = pynutil.insert('name: "') + punct + pynutil.insert('"')
|
||||
|
||||
self.fst = graph.optimize()
|
||||
@@ -0,0 +1,149 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_ALNUM,
|
||||
DAMO_ALPHA,
|
||||
DAMO_DIGIT,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
def get_serial_number(cardinal):
|
||||
"""
|
||||
any alphanumerical character sequence with at least one number with length greater equal to 3
|
||||
"""
|
||||
digit = pynini.compose(cardinal.graph_no_exception, DAMO_DIGIT)
|
||||
character = digit | DAMO_ALPHA
|
||||
sequence = character + pynini.closure(pynutil.delete(" ") + character, 2)
|
||||
sequence = sequence @ (pynini.closure(DAMO_ALNUM) + DAMO_DIGIT + pynini.closure(DAMO_ALNUM))
|
||||
return sequence.optimize()
|
||||
|
||||
|
||||
class TelephoneFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying telephone numbers, e.g.
|
||||
one two three one two three five six seven eight -> { number_part: "123-123-5678" }
|
||||
|
||||
This class also support card number and IP format.
|
||||
"one two three dot one double three dot o dot four o" -> { number_part: "123.133.0.40"}
|
||||
|
||||
"three two double seven three two one four three two one four three double zero five" ->
|
||||
{ number_part: 3277 3214 3214 3005}
|
||||
|
||||
Args:
|
||||
cardinal: CardinalFst
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal: GraphFst):
|
||||
super().__init__(name="telephone", kind="classify")
|
||||
# country code, number_part, extension
|
||||
digit_to_str = (
|
||||
pynini.invert(pynini.string_file(get_abs_path("data/numbers/digit.tsv")).optimize())
|
||||
| pynini.cross("0", pynini.union("o", "oh", "nol")).optimize()
|
||||
)
|
||||
|
||||
str_to_digit = pynini.invert(digit_to_str)
|
||||
|
||||
double_digit = pynini.union(
|
||||
*[
|
||||
pynini.cross(
|
||||
pynini.project(str(i) @ digit_to_str, "output")
|
||||
+ pynini.accep(" ")
|
||||
+ pynini.project(str(i) @ digit_to_str, "output"),
|
||||
pynutil.insert("dobel ") + pynini.project(str(i) @ digit_to_str, "output"),
|
||||
)
|
||||
for i in range(10)
|
||||
]
|
||||
)
|
||||
double_digit.invert()
|
||||
|
||||
# to handle cases like "one twenty three"
|
||||
two_digit_cardinal = pynini.compose(cardinal.graph_no_exception, DAMO_DIGIT**2)
|
||||
double_digit_to_digit = (
|
||||
pynini.compose(double_digit, str_to_digit + pynutil.delete(" ") + str_to_digit)
|
||||
| two_digit_cardinal
|
||||
)
|
||||
|
||||
single_or_double_digit = (
|
||||
pynutil.add_weight(double_digit_to_digit, -0.0001) | str_to_digit
|
||||
).optimize()
|
||||
single_or_double_digit |= (
|
||||
single_or_double_digit
|
||||
+ pynini.closure(
|
||||
pynutil.add_weight(pynutil.delete(" ") + single_or_double_digit, 0.0001)
|
||||
)
|
||||
).optimize()
|
||||
|
||||
number_part = pynini.compose(
|
||||
single_or_double_digit,
|
||||
DAMO_DIGIT**2
|
||||
+ pynutil.insert(" ")
|
||||
+ DAMO_DIGIT**4
|
||||
+ pynutil.insert("-")
|
||||
+ DAMO_DIGIT**4,
|
||||
).optimize()
|
||||
number_part = (
|
||||
pynutil.insert('number_part: "') + number_part.optimize() + pynutil.insert('"')
|
||||
)
|
||||
|
||||
cardinal_option = pynini.compose(single_or_double_digit, DAMO_DIGIT ** (2, 3))
|
||||
|
||||
country_code = (
|
||||
pynutil.insert('country_code: "')
|
||||
+ pynini.closure(pynini.cross("ditambah ", "+"), 0, 1)
|
||||
+ (
|
||||
(pynini.closure(str_to_digit + pynutil.delete(" "), 0, 2) + str_to_digit)
|
||||
| cardinal_option
|
||||
)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
optional_country_code = pynini.closure(
|
||||
country_code + pynutil.delete(" ") + insert_space, 0, 1
|
||||
).optimize()
|
||||
graph = optional_country_code + number_part
|
||||
|
||||
# credit card number
|
||||
space_four_digits = insert_space + DAMO_DIGIT**4
|
||||
credit_card_graph = pynini.compose(
|
||||
single_or_double_digit, DAMO_DIGIT**4 + space_four_digits**3
|
||||
).optimize()
|
||||
graph |= (
|
||||
pynutil.insert('number_part: "') + credit_card_graph.optimize() + pynutil.insert('"')
|
||||
)
|
||||
|
||||
# SSN
|
||||
ssn_graph = pynini.compose(
|
||||
single_or_double_digit,
|
||||
DAMO_DIGIT**3
|
||||
+ pynutil.insert("-")
|
||||
+ DAMO_DIGIT**2
|
||||
+ pynutil.insert("-")
|
||||
+ DAMO_DIGIT**4,
|
||||
).optimize()
|
||||
graph |= pynutil.insert('number_part: "') + ssn_graph.optimize() + pynutil.insert('"')
|
||||
|
||||
# ip
|
||||
digit_or_double = (
|
||||
pynini.closure(str_to_digit + pynutil.delete(" "), 0, 1) + double_digit_to_digit
|
||||
)
|
||||
digit_or_double |= double_digit_to_digit + pynini.closure(
|
||||
pynutil.delete(" ") + str_to_digit, 0, 1
|
||||
)
|
||||
digit_or_double |= str_to_digit + (pynutil.delete(" ") + str_to_digit) ** (0, 2)
|
||||
digit_or_double |= cardinal_option
|
||||
digit_or_double = digit_or_double.optimize()
|
||||
|
||||
ip_graph = digit_or_double + (pynini.cross(" dot ", ".") + digit_or_double) ** 3
|
||||
|
||||
graph |= pynutil.insert('number_part: "') + ip_graph.optimize() + pynutil.insert('"')
|
||||
graph |= (
|
||||
pynutil.insert('number_part: "')
|
||||
+ pynutil.add_weight(get_serial_number(cardinal=cardinal), weight=0.0001)
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
final_graph = self.add_tokens(graph)
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,151 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.cardinal import CardinalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path, num_to_word
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
GraphFst,
|
||||
convert_space,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TimeFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying time
|
||||
e.g. twelve thirty -> time { hours: "12" minutes: "30" }
|
||||
e.g. twelve past one -> time { minutes: "12" hours: "1" }
|
||||
e.g. two o clock a m -> time { hours: "2" suffix: "a.m." }
|
||||
e.g. quarter to two -> time { hours: "1" minutes: "45" }
|
||||
e.g. quarter past two -> time { hours: "2" minutes: "15" }
|
||||
e.g. half past two -> time { hours: "2" minutes: "30" }
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="time", kind="classify")
|
||||
# hours, minutes, seconds, suffix, zone, style, speak_period
|
||||
|
||||
suffix_graph = pynini.string_file(get_abs_path("data/time/time_suffix.tsv"))
|
||||
time_zone_graph = pynini.invert(pynini.string_file(get_abs_path("data/time/time_zone.tsv")))
|
||||
to_hour_graph = pynini.string_file(get_abs_path("data/time/to_hour.tsv"))
|
||||
minute_to_graph = pynini.string_file(get_abs_path("data/time/minute_to.tsv"))
|
||||
|
||||
cardinal = pynutil.add_weight(CardinalFst().graph_no_exception, weight=-0.7)
|
||||
|
||||
labels_hour = [
|
||||
"nol",
|
||||
"satu",
|
||||
"dua",
|
||||
"tiga",
|
||||
"empat",
|
||||
"lima",
|
||||
"enam",
|
||||
"tujuh",
|
||||
"delapan",
|
||||
"sembilan",
|
||||
"sepuluh",
|
||||
"sebelas",
|
||||
"duabelas",
|
||||
"tigabelas",
|
||||
]
|
||||
labels_minute_single = [num_to_word(x) for x in range(1, 10)]
|
||||
labels_minute_double = [num_to_word(x) for x in range(10, 60)]
|
||||
|
||||
graph_hour = pynini.union(*labels_hour) @ cardinal
|
||||
|
||||
graph_minute_single = pynini.union(*labels_minute_single) @ cardinal
|
||||
graph_minute_double = pynini.union(*labels_minute_double) @ cardinal
|
||||
graph_minute_verbose = pynini.cross("setengah", "30") | pynini.cross("seperempat", "15")
|
||||
oclock = pynini.cross(pynini.union("jam", "pukul"), "")
|
||||
|
||||
final_graph_hour = pynutil.insert('hours: "') + graph_hour + pynutil.insert('"')
|
||||
graph_minute = (
|
||||
oclock + pynutil.insert("00")
|
||||
| pynutil.delete("o") + delete_space + graph_minute_single
|
||||
| graph_minute_double
|
||||
)
|
||||
final_suffix = (
|
||||
pynutil.insert('suffix: "') + convert_space(suffix_graph) + pynutil.insert('"')
|
||||
)
|
||||
final_suffix = delete_space + insert_space + final_suffix
|
||||
final_suffix_optional = pynini.closure(final_suffix, 0, 1)
|
||||
final_time_zone_optional = pynini.closure(
|
||||
delete_space
|
||||
+ insert_space
|
||||
+ pynutil.insert('zone: "')
|
||||
+ convert_space(time_zone_graph)
|
||||
+ pynutil.insert('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
# five o' clock
|
||||
# two o eight, two thirty five (am/pm)
|
||||
# two pm/am
|
||||
graph_hm = (
|
||||
final_graph_hour
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('minutes: "')
|
||||
+ graph_minute
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
# 10 past four, quarter past four, half past four
|
||||
graph_m_past_h = (
|
||||
pynutil.insert('minutes: "')
|
||||
+ pynini.union(graph_minute_single, graph_minute_double, graph_minute_verbose)
|
||||
+ pynutil.insert('"')
|
||||
+ delete_space
|
||||
+ pynutil.delete("setengah")
|
||||
+ delete_extra_space
|
||||
+ final_graph_hour
|
||||
)
|
||||
|
||||
graph_quarter_time = (
|
||||
pynutil.insert('minutes: "')
|
||||
+ pynini.cross("seperempat", "45")
|
||||
+ pynutil.insert('"')
|
||||
+ delete_space
|
||||
+ pynutil.delete(pynini.union("to", "till"))
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('hours: "')
|
||||
+ to_hour_graph
|
||||
+ pynutil.insert('"')
|
||||
)
|
||||
|
||||
graph_m_to_h_suffix_time = (
|
||||
pynutil.insert('minutes: "')
|
||||
+ ((graph_minute_single | graph_minute_double).optimize() @ minute_to_graph)
|
||||
+ pynutil.insert('"')
|
||||
+ pynini.closure(
|
||||
delete_space + pynutil.delete(pynini.union("min", "mins", "menit")), 0, 1
|
||||
)
|
||||
+ delete_space
|
||||
+ pynutil.delete(pynini.union("sampai"))
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('hours: "')
|
||||
+ to_hour_graph
|
||||
+ pynutil.insert('"')
|
||||
+ final_suffix
|
||||
)
|
||||
|
||||
graph_h = (
|
||||
final_graph_hour
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert('minutes: "')
|
||||
+ (pynutil.insert("00") | graph_minute)
|
||||
+ pynutil.insert('"')
|
||||
+ final_suffix
|
||||
+ final_time_zone_optional
|
||||
)
|
||||
final_graph = (
|
||||
(graph_hm | graph_m_past_h | graph_quarter_time)
|
||||
+ final_suffix_optional
|
||||
+ final_time_zone_optional
|
||||
)
|
||||
final_graph |= graph_h
|
||||
final_graph |= graph_m_to_h_suffix_time
|
||||
|
||||
final_graph = self.add_tokens(final_graph.optimize())
|
||||
|
||||
self.fst = final_graph.optimize()
|
||||
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.cardinal import CardinalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.date import DateFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.decimal import DecimalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.electronic import ElectronicFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.measure import MeasureFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.money import MoneyFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.ordinal import OrdinalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.punctuation import PunctuationFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.telephone import TelephoneFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.time import TimeFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.whitelist import WhiteListFst
|
||||
from fun_text_processing.inverse_text_normalization.id.taggers.word import WordFst
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
generator_main,
|
||||
)
|
||||
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 Finate State Archiv (FAR) File.
|
||||
More details to deployment at NeMo/tools/text_processing_deployment.
|
||||
|
||||
Args:
|
||||
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, cache_dir: str = None, overwrite_cache: bool = False):
|
||||
super().__init__(name="tokenize_and_classify", kind="classify")
|
||||
|
||||
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, "_id_itn.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.")
|
||||
cardinal = CardinalFst()
|
||||
cardinal_graph = cardinal.fst
|
||||
|
||||
ordinal = OrdinalFst(cardinal)
|
||||
ordinal_graph = ordinal.fst
|
||||
|
||||
decimal = DecimalFst(cardinal)
|
||||
decimal_graph = decimal.fst
|
||||
|
||||
measure_graph = MeasureFst(cardinal=cardinal, decimal=decimal).fst
|
||||
date_graph = DateFst(ordinal=ordinal).fst
|
||||
word_graph = WordFst().fst
|
||||
time_graph = TimeFst().fst
|
||||
money_graph = MoneyFst(cardinal=cardinal, decimal=decimal).fst
|
||||
whitelist_graph = WhiteListFst().fst
|
||||
punct_graph = PunctuationFst().fst
|
||||
electronic_graph = ElectronicFst().fst
|
||||
telephone_graph = TelephoneFst(cardinal).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, 1.1)
|
||||
| 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(delete_extra_space + 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,19 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.utils import get_abs_path
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import GraphFst, convert_space
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WhiteListFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying whitelisted tokens
|
||||
e.g. misses -> tokens { name: "mrs." }
|
||||
This class has highest priority among all classifier grammars. Whitelisted tokens are defined and loaded from "data/whitelist.tsv".
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="whitelist", kind="classify")
|
||||
|
||||
whitelist = pynini.string_file(get_abs_path("data/whitelist.tsv")).invert()
|
||||
graph = pynutil.insert('name: "') + convert_space(whitelist) + pynutil.insert('"')
|
||||
self.fst = graph.optimize()
|
||||
@@ -0,0 +1,15 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import DAMO_NOT_SPACE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WordFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for classifying plain tokens, that do not belong to any special class. This can be considered as the default class.
|
||||
e.g. sleep -> tokens { name: "sleep" }
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
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,40 @@
|
||||
dua ribu dua puluh dua 2022
|
||||
nol satu dua tiga empat lima enam tujuh delapan sembilan 0123456789
|
||||
empat belas 14
|
||||
limabelas 15
|
||||
enambelas 16
|
||||
tujuh belas 17
|
||||
delapan belas 18
|
||||
sembilan belas 19
|
||||
dua puluh 20
|
||||
seratus enam 106
|
||||
enam ratus 600
|
||||
ratus 100
|
||||
seratus 100
|
||||
satu juta 1,000,000
|
||||
satu miliar 1 miliar
|
||||
seratus dua puluh tiga 123
|
||||
ratus dua puluh tiga 123
|
||||
dua puluh empat maret 24th March
|
||||
seribu dua ratus delapan puluh sembilan 1289
|
||||
lima juta tiga ribu tujuh puluh enam rupiah Rp5003076
|
||||
ribu tujuh puluh enam rupiah Rp1076
|
||||
tujuh puluh enam rupiah dollar $1076
|
||||
ditambah enam dua dua satu enam lima tiga sembilan nol enam nol lima +62 21 6539-0605
|
||||
tiga ribu 3000
|
||||
sembilan ribu sembilan ratus sembilan puluh sembilan 9999
|
||||
seribu satu 1001
|
||||
nol 0
|
||||
satu 1
|
||||
dua 2
|
||||
tiga 3
|
||||
empat 4
|
||||
lima 5
|
||||
enam 6
|
||||
tujuh 7
|
||||
delapan 8
|
||||
sembilan 9
|
||||
sepuluh 10
|
||||
sebelas 11
|
||||
dua belas 12
|
||||
tigabelas 13
|
||||
|
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
from typing import Union
|
||||
|
||||
import inflect
|
||||
|
||||
_inflect = inflect.engine()
|
||||
|
||||
|
||||
def num_to_word(x: Union[str, int]):
|
||||
"""
|
||||
converts integer to spoken representation
|
||||
|
||||
Args
|
||||
x: integer
|
||||
|
||||
Returns: spoken representation
|
||||
"""
|
||||
if isinstance(x, int):
|
||||
x = str(x)
|
||||
x = _inflect.number_to_words(str(x)).replace("-", " ").replace(",", "")
|
||||
return x
|
||||
|
||||
|
||||
def get_abs_path(rel_path):
|
||||
"""
|
||||
Get absolute path
|
||||
|
||||
Args:
|
||||
rel_path: relative path to this file
|
||||
|
||||
Returns absolute path
|
||||
"""
|
||||
return os.path.dirname(os.path.abspath(__file__)) + "/" + rel_path
|
||||
@@ -0,0 +1,38 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class CardinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing cardinal
|
||||
e.g. cardinal { integer: "23" negative: "-" } -> -23
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="cardinal", kind="verbalize")
|
||||
optional_sign = pynini.closure(
|
||||
pynutil.delete("negative:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ DAMO_NOT_QUOTE
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
graph = (
|
||||
pynutil.delete("integer:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
self.numbers = graph
|
||||
graph = optional_sign + graph
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,70 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DateFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing date, e.g.
|
||||
date { month: "january" day: "5" year: "2012" preserve_order: true } -> february 5 2012
|
||||
date { day: "5" month: "january" year: "2012" preserve_order: true } -> 5 february 2012
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="date", kind="verbalize")
|
||||
month = (
|
||||
pynutil.delete("month:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
day = (
|
||||
pynutil.delete("day:")
|
||||
+ 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('"')
|
||||
)
|
||||
|
||||
# month (day) year
|
||||
graph_mdy = (
|
||||
month
|
||||
+ pynini.closure(delete_extra_space + day, 0, 1)
|
||||
+ pynini.closure(delete_extra_space + year, 0, 1)
|
||||
)
|
||||
|
||||
# (day) month year
|
||||
graph_dmy = (
|
||||
pynini.closure(day + delete_extra_space, 0, 1)
|
||||
+ month
|
||||
+ pynini.closure(delete_extra_space + year, 0, 1)
|
||||
)
|
||||
|
||||
optional_preserve_order = pynini.closure(
|
||||
pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space
|
||||
| pynutil.delete("field_order:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ DAMO_NOT_QUOTE
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
)
|
||||
|
||||
final_graph = (graph_mdy | year | graph_dmy) + delete_space + optional_preserve_order
|
||||
|
||||
delete_tokens = self.delete_tokens(final_graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,48 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.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.
|
||||
decimal { negative: "true" integer_part: "12" fractional_part: "5006" quantity: "billion" } -> -12.5006 billion
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="decimal", kind="verbalize")
|
||||
optionl_sign = pynini.closure(pynini.cross('negative: "true"', "-") + delete_space, 0, 1)
|
||||
integer = (
|
||||
pynutil.delete("integer_part:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_integer = pynini.closure(integer + delete_space, 0, 1)
|
||||
fractional = (
|
||||
pynutil.insert(".")
|
||||
+ pynutil.delete("fractional_part:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_fractional = pynini.closure(fractional + delete_space, 0, 1)
|
||||
quantity = (
|
||||
pynutil.delete("quantity:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_quantity = pynini.closure(pynutil.insert(" ") + quantity + delete_space, 0, 1)
|
||||
graph = optional_integer + optional_fractional + optional_quantity
|
||||
self.numbers = graph
|
||||
graph = optionl_sign + graph
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,45 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class ElectronicFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing electronic
|
||||
e.g. tokens { electronic { username: "cdf1" domain: "abc.edu" } } -> cdf1@abc.edu
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="electronic", kind="verbalize")
|
||||
user_name = (
|
||||
pynutil.delete("username:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
domain = (
|
||||
pynutil.delete("domain:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
protocol = (
|
||||
pynutil.delete("protocol:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
graph = user_name + delete_space + pynutil.insert("@") + domain
|
||||
graph |= protocol
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,10 @@
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import GraphFst
|
||||
|
||||
|
||||
class FractionFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing fraction,
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="fraction", kind="verbalize")
|
||||
@@ -0,0 +1,51 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MeasureFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing measure, e.g.
|
||||
measure { negative: "true" cardinal { integer: "12" } units: "kg" } -> -12 kg
|
||||
|
||||
Args:
|
||||
decimal: DecimalFst
|
||||
cardinal: CardinalFst
|
||||
"""
|
||||
|
||||
def __init__(self, decimal: GraphFst, cardinal: GraphFst):
|
||||
super().__init__(name="measure", kind="verbalize")
|
||||
optional_sign = pynini.closure(pynini.cross('negative: "true"', "-"), 0, 1)
|
||||
unit = (
|
||||
pynutil.delete("units:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_CHAR - " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
)
|
||||
graph_decimal = (
|
||||
pynutil.delete("decimal {")
|
||||
+ delete_space
|
||||
+ optional_sign
|
||||
+ delete_space
|
||||
+ decimal.numbers
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
graph_cardinal = (
|
||||
pynutil.delete("cardinal {")
|
||||
+ delete_space
|
||||
+ optional_sign
|
||||
+ delete_space
|
||||
+ cardinal.numbers
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
graph = (graph_cardinal | graph_decimal) + delete_space + pynutil.insert(" ") + unit
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,30 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MoneyFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing money, e.g.
|
||||
money { integer_part: "12" fractional_part: "05" currency: "$" } -> $12.05
|
||||
|
||||
Args:
|
||||
decimal: DecimalFst
|
||||
"""
|
||||
|
||||
def __init__(self, decimal: GraphFst):
|
||||
super().__init__(name="money", kind="verbalize")
|
||||
unit = (
|
||||
pynutil.delete("currency:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_CHAR - " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
graph = unit + delete_space + decimal.numbers
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,48 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class OrdinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing ordinal, e.g.
|
||||
ordinal { integer: "13" } -> 13th
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="ordinal", kind="verbalize")
|
||||
graph = (
|
||||
pynutil.delete("integer:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
convert_eleven = pynini.cross("11", "11th")
|
||||
convert_twelve = pynini.cross("12", "12th")
|
||||
convert_thirteen = pynini.cross("13", "13th")
|
||||
convert_one = pynini.cross("1", "1st")
|
||||
convert_two = pynini.cross("2", "2nd")
|
||||
convert_three = pynini.cross("3", "3rd")
|
||||
convert_rest = pynutil.insert("th", weight=0.01)
|
||||
|
||||
suffix = pynini.cdrewrite(
|
||||
convert_eleven
|
||||
| convert_twelve
|
||||
| convert_thirteen
|
||||
| convert_one
|
||||
| convert_two
|
||||
| convert_three
|
||||
| convert_rest,
|
||||
"",
|
||||
"[EOS]",
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
graph = graph @ suffix
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,30 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import DAMO_NOT_QUOTE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TelephoneFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing telephone, e.g.
|
||||
telephone { number_part: "123-123-5678" }
|
||||
-> 123-123-5678
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="telephone", kind="verbalize")
|
||||
|
||||
number_part = (
|
||||
pynutil.delete('number_part: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_country_code = pynini.closure(
|
||||
pynutil.delete('country_code: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.accep(" "),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
delete_tokens = self.delete_tokens(optional_country_code + number_part)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,68 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
DAMO_DIGIT,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TimeFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing time, e.g.
|
||||
time { hours: "12" minutes: "30" } -> 12:30
|
||||
time { hours: "1" minutes: "12" } -> 01:12
|
||||
time { hours: "2" suffix: "a.m." } -> 02:00 a.m.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="time", kind="verbalize")
|
||||
add_leading_zero_to_double_digit = (DAMO_DIGIT + DAMO_DIGIT) | (
|
||||
pynutil.insert("0") + DAMO_DIGIT
|
||||
)
|
||||
hour = (
|
||||
pynutil.delete("hours:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_DIGIT, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
minute = (
|
||||
pynutil.delete("minutes:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_DIGIT, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
suffix = (
|
||||
delete_space
|
||||
+ insert_space
|
||||
+ pynutil.delete("suffix:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_CHAR - " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_suffix = pynini.closure(suffix, 0, 1)
|
||||
zone = (
|
||||
delete_space
|
||||
+ insert_space
|
||||
+ pynutil.delete("zone:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_CHAR - " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_zone = pynini.closure(zone, 0, 1)
|
||||
graph = (
|
||||
hour @ add_leading_zero_to_double_digit
|
||||
+ delete_space
|
||||
+ pynutil.insert(":")
|
||||
+ (minute @ add_leading_zero_to_double_digit)
|
||||
+ optional_suffix
|
||||
+ optional_zone
|
||||
)
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,47 @@
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.cardinal import CardinalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.date import DateFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.decimal import DecimalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.electronic import ElectronicFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.measure import MeasureFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.money import MoneyFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.ordinal import OrdinalFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.telephone import TelephoneFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.time import TimeFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.whitelist import WhiteListFst
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import GraphFst
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="verbalize", kind="verbalize")
|
||||
cardinal = CardinalFst()
|
||||
cardinal_graph = cardinal.fst
|
||||
ordinal_graph = OrdinalFst().fst
|
||||
decimal = DecimalFst()
|
||||
decimal_graph = decimal.fst
|
||||
measure_graph = MeasureFst(decimal=decimal, cardinal=cardinal).fst
|
||||
money_graph = MoneyFst(decimal=decimal).fst
|
||||
time_graph = TimeFst().fst
|
||||
date_graph = DateFst().fst
|
||||
whitelist_graph = WhiteListFst().fst
|
||||
telephone_graph = TelephoneFst().fst
|
||||
electronic_graph = ElectronicFst().fst
|
||||
graph = (
|
||||
time_graph
|
||||
| date_graph
|
||||
| money_graph
|
||||
| measure_graph
|
||||
| ordinal_graph
|
||||
| decimal_graph
|
||||
| cardinal_graph
|
||||
| whitelist_graph
|
||||
| telephone_graph
|
||||
| electronic_graph
|
||||
)
|
||||
self.fst = graph
|
||||
@@ -0,0 +1,33 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.verbalize import VerbalizeFst
|
||||
from fun_text_processing.inverse_text_normalization.id.verbalizers.word import WordFst
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="verbalize_final", kind="verbalize")
|
||||
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
|
||||
@@ -0,0 +1,27 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WhiteListFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing whitelist
|
||||
e.g. tokens { name: "mrs." } -> mrs.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="whitelist", kind="verbalize")
|
||||
graph = (
|
||||
pynutil.delete("name:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_CHAR - " ", 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
graph = graph @ pynini.cdrewrite(pynini.cross("\u00A0", " "), "", "", DAMO_SIGMA)
|
||||
self.fst = graph.optimize()
|
||||
@@ -0,0 +1,29 @@
|
||||
import pynini
|
||||
from fun_text_processing.inverse_text_normalization.id.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WordFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing plain tokens
|
||||
e.g. tokens { name: "sleep" } -> sleep
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="word", kind="verbalize")
|
||||
chars = pynini.closure(DAMO_CHAR - " ", 1)
|
||||
char = (
|
||||
pynutil.delete("name:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ chars
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
graph = char @ pynini.cdrewrite(pynini.cross("\u00A0", " "), "", "", DAMO_SIGMA)
|
||||
|
||||
self.fst = graph.optimize()
|
||||
Reference in New Issue
Block a user