chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_QUOTE, GraphFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class AbbreviationFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing abbreviations
|
||||
e.g. tokens { abbreviation { value: "A B C" } } -> "ABC"
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="abbreviation", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph = pynutil.delete('value: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,35 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.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 { negative: "true" integer: "23" } -> minus twenty three
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
self.optional_sign = pynini.cross('negative: "true"', "minus ")
|
||||
if not deterministic:
|
||||
self.optional_sign |= pynini.cross('negative: "true"', "negative ")
|
||||
self.optional_sign = pynini.closure(self.optional_sign + delete_space, 0, 1)
|
||||
|
||||
integer = pynini.closure(DAMO_NOT_QUOTE)
|
||||
|
||||
self.integer = delete_space + pynutil.delete('"') + integer + pynutil.delete('"')
|
||||
integer = pynutil.delete("integer:") + self.integer
|
||||
|
||||
self.numbers = self.optional_sign + integer
|
||||
delete_tokens = self.delete_tokens(self.numbers)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,100 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.examples import plurals
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DateFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing date, e.g.
|
||||
date { month: "february" day: "five" year: "twenty twelve" preserve_order: true } -> february fifth twenty twelve
|
||||
date { day: "five" month: "february" year: "twenty twelve" preserve_order: true } -> the fifth of february twenty twelve
|
||||
|
||||
Args:
|
||||
ordinal: OrdinalFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, ordinal: GraphFst, deterministic: bool = True, lm: bool = False):
|
||||
super().__init__(name="date", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
month = pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
day_cardinal = (
|
||||
pynutil.delete("day:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
day = day_cardinal @ ordinal.suffix
|
||||
|
||||
month = (
|
||||
pynutil.delete("month:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ month
|
||||
+ 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)
|
||||
)
|
||||
# may 5 -> may five
|
||||
if not deterministic and not lm:
|
||||
graph_mdy |= (
|
||||
month
|
||||
+ pynini.closure(delete_extra_space + day_cardinal, 0, 1)
|
||||
+ pynini.closure(delete_extra_space + year, 0, 1)
|
||||
)
|
||||
|
||||
# day month year
|
||||
graph_dmy = (
|
||||
pynutil.insert("the ")
|
||||
+ day
|
||||
+ delete_extra_space
|
||||
+ pynutil.insert("of ")
|
||||
+ 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 = (
|
||||
(
|
||||
plurals._priority_union(
|
||||
graph_mdy, pynutil.add_weight(graph_dmy, 0.0001), DAMO_SIGMA
|
||||
)
|
||||
| year
|
||||
)
|
||||
+ delete_space
|
||||
+ optional_preserve_order
|
||||
)
|
||||
delete_tokens = self.delete_tokens(final_graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,58 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class DecimalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing decimal, e.g.
|
||||
decimal { negative: "true" integer_part: "twelve" fractional_part: "five o o six" quantity: "billion" } -> minus twelve point five o o six billion
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, cardinal, deterministic: bool = True):
|
||||
super().__init__(name="decimal", kind="verbalize", deterministic=deterministic)
|
||||
self.optional_sign = pynini.cross('negative: "true"', "minus ")
|
||||
if not deterministic:
|
||||
self.optional_sign |= pynini.cross('negative: "true"', "negative ")
|
||||
self.optional_sign = pynini.closure(self.optional_sign + delete_space, 0, 1)
|
||||
self.integer = pynutil.delete("integer_part:") + cardinal.integer
|
||||
self.optional_integer = pynini.closure(self.integer + delete_space + insert_space, 0, 1)
|
||||
self.fractional_default = (
|
||||
pynutil.delete("fractional_part:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
self.fractional = pynutil.insert("point ") + self.fractional_default
|
||||
|
||||
self.quantity = (
|
||||
delete_space
|
||||
+ insert_space
|
||||
+ pynutil.delete("quantity:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
self.optional_quantity = pynini.closure(self.quantity, 0, 1)
|
||||
|
||||
graph = self.optional_sign + (
|
||||
self.integer
|
||||
| (self.integer + self.quantity)
|
||||
| (self.optional_integer + self.fractional + self.optional_quantity)
|
||||
)
|
||||
|
||||
self.numbers = graph
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,95 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_NOT_SPACE,
|
||||
DAMO_SIGMA,
|
||||
TO_UPPER,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.utils import get_abs_path
|
||||
from pynini.examples import plurals
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class ElectronicFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing electronic
|
||||
e.g. tokens { electronic { username: "cdf1" domain: "abc.edu" } } -> c d f one at a b c dot e d u
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="electronic", kind="verbalize", deterministic=deterministic)
|
||||
graph_digit_no_zero = pynini.invert(
|
||||
pynini.string_file(get_abs_path("data/number/digit.tsv"))
|
||||
).optimize()
|
||||
graph_zero = pynini.cross("0", "zero")
|
||||
|
||||
if not deterministic:
|
||||
graph_zero |= pynini.cross("0", "o") | pynini.cross("0", "oh")
|
||||
|
||||
graph_digit = graph_digit_no_zero | graph_zero
|
||||
graph_symbols = pynini.string_file(get_abs_path("data/electronic/symbol.tsv")).optimize()
|
||||
|
||||
default_chars_symbols = pynini.cdrewrite(
|
||||
pynutil.insert(" ") + (graph_symbols | graph_digit) + pynutil.insert(" "),
|
||||
"",
|
||||
"",
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
default_chars_symbols = pynini.compose(
|
||||
pynini.closure(DAMO_NOT_SPACE), default_chars_symbols.optimize()
|
||||
).optimize()
|
||||
|
||||
user_name = (
|
||||
pynutil.delete("username:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ default_chars_symbols
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
domain_common = pynini.string_file(get_abs_path("data/electronic/domain.tsv"))
|
||||
|
||||
domain = (
|
||||
default_chars_symbols
|
||||
+ insert_space
|
||||
+ plurals._priority_union(
|
||||
domain_common,
|
||||
pynutil.add_weight(pynini.cross(".", "dot"), weight=0.0001),
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
+ pynini.closure(
|
||||
insert_space
|
||||
+ (pynini.cdrewrite(TO_UPPER, "", "", DAMO_SIGMA) @ default_chars_symbols),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
)
|
||||
domain = (
|
||||
pynutil.delete("domain:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ domain
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
).optimize()
|
||||
|
||||
protocol = (
|
||||
pynutil.delete('protocol: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
|
||||
)
|
||||
graph = (
|
||||
pynini.closure(protocol + delete_space, 0, 1)
|
||||
+ pynini.closure(user_name + delete_space + pynutil.insert(" at ") + delete_space, 0, 1)
|
||||
+ domain
|
||||
+ delete_space
|
||||
).optimize() @ pynini.cdrewrite(delete_extra_space, "", "", DAMO_SIGMA)
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,94 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
insert_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.verbalizers.ordinal import OrdinalFst
|
||||
from pynini.examples import plurals
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class FractionFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing fraction
|
||||
e.g. tokens { fraction { integer: "twenty three" numerator: "four" denominator: "five" } } ->
|
||||
twenty three and four fifth
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True, lm: bool = False):
|
||||
super().__init__(name="fraction", kind="verbalize", deterministic=deterministic)
|
||||
suffix = OrdinalFst().suffix
|
||||
|
||||
integer = (
|
||||
pynutil.delete('integer_part: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE)
|
||||
+ pynutil.delete('" ')
|
||||
)
|
||||
denominator_one = pynini.cross('denominator: "one"', "over one")
|
||||
denominator_half = pynini.cross('denominator: "two"', "half")
|
||||
denominator_quarter = pynini.cross('denominator: "four"', "quarter")
|
||||
|
||||
denominator_rest = (
|
||||
pynutil.delete('denominator: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE) @ suffix
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
denominators = plurals._priority_union(
|
||||
denominator_one,
|
||||
plurals._priority_union(
|
||||
denominator_half,
|
||||
plurals._priority_union(denominator_quarter, denominator_rest, DAMO_SIGMA),
|
||||
DAMO_SIGMA,
|
||||
),
|
||||
DAMO_SIGMA,
|
||||
).optimize()
|
||||
if not deterministic:
|
||||
denominators |= (
|
||||
pynutil.delete('denominator: "')
|
||||
+ (pynini.accep("four") @ suffix)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
numerator_one = pynutil.delete('numerator: "') + pynini.accep("one") + pynutil.delete('" ')
|
||||
numerator_one = numerator_one + insert_space + denominators
|
||||
numerator_rest = (
|
||||
pynutil.delete('numerator: "')
|
||||
+ (pynini.closure(DAMO_NOT_QUOTE) - pynini.accep("one"))
|
||||
+ pynutil.delete('" ')
|
||||
)
|
||||
numerator_rest = numerator_rest + insert_space + denominators
|
||||
numerator_rest @= pynini.cdrewrite(
|
||||
plurals._priority_union(
|
||||
pynini.cross("half", "halves"), pynutil.insert("s"), DAMO_SIGMA
|
||||
),
|
||||
"",
|
||||
"[EOS]",
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
|
||||
graph = numerator_one | numerator_rest
|
||||
|
||||
conjunction = pynutil.insert("and ")
|
||||
if not deterministic and not lm:
|
||||
conjunction = pynini.closure(conjunction, 0, 1)
|
||||
|
||||
integer = pynini.closure(integer + insert_space + conjunction, 0, 1)
|
||||
|
||||
graph = integer + graph
|
||||
graph @= pynini.cdrewrite(
|
||||
pynini.cross("and one half", "and a half") | pynini.cross("over ones", "over one"),
|
||||
"",
|
||||
"[EOS]",
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
|
||||
self.graph = graph
|
||||
delete_tokens = self.delete_tokens(self.graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,109 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MeasureFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing measure, e.g.
|
||||
measure { negative: "true" cardinal { integer: "twelve" } units: "kilograms" } -> minus twelve kilograms
|
||||
measure { decimal { integer_part: "twelve" fractional_part: "five" } units: "kilograms" } -> twelve point five kilograms
|
||||
tokens { measure { units: "covid" decimal { integer_part: "nineteen" fractional_part: "five" } } } -> covid nineteen point five
|
||||
|
||||
Args:
|
||||
decimal: DecimalFst
|
||||
cardinal: CardinalFst
|
||||
fraction: FractionFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, decimal: GraphFst, cardinal: GraphFst, fraction: GraphFst, deterministic: bool = True
|
||||
):
|
||||
super().__init__(name="measure", kind="verbalize", deterministic=deterministic)
|
||||
optional_sign = cardinal.optional_sign
|
||||
unit = (
|
||||
pynutil.delete('units: "')
|
||||
+ pynini.difference(pynini.closure(DAMO_NOT_QUOTE, 1), pynini.union("address", "math"))
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
)
|
||||
|
||||
if not deterministic:
|
||||
unit |= pynini.compose(unit, pynini.cross(pynini.union("inch", "inches"), '"'))
|
||||
|
||||
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_fraction = (
|
||||
pynutil.delete("fraction {")
|
||||
+ delete_space
|
||||
+ fraction.graph
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
|
||||
graph = (
|
||||
(graph_cardinal | graph_decimal | graph_fraction) + delete_space + insert_space + unit
|
||||
)
|
||||
|
||||
# SH adds "preserve_order: true" by default
|
||||
preserve_order = (
|
||||
pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space
|
||||
)
|
||||
graph |= (
|
||||
unit
|
||||
+ insert_space
|
||||
+ (graph_cardinal | graph_decimal)
|
||||
+ delete_space
|
||||
+ pynini.closure(preserve_order)
|
||||
)
|
||||
# for only unit
|
||||
graph |= (
|
||||
pynutil.delete('cardinal { integer: "-"')
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
+ delete_space
|
||||
+ unit
|
||||
+ pynini.closure(preserve_order)
|
||||
)
|
||||
address = (
|
||||
pynutil.delete('units: "address" ')
|
||||
+ delete_space
|
||||
+ graph_cardinal
|
||||
+ delete_space
|
||||
+ pynini.closure(preserve_order)
|
||||
)
|
||||
math = (
|
||||
pynutil.delete('units: "math" ')
|
||||
+ delete_space
|
||||
+ graph_cardinal
|
||||
+ delete_space
|
||||
+ pynini.closure(preserve_order)
|
||||
)
|
||||
graph |= address | math
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,69 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_preserve_order,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class MoneyFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing money, e.g.
|
||||
money { integer_part: "twelve" fractional_part: "o five" currency: "dollars" } -> twelve o five dollars
|
||||
|
||||
Args:
|
||||
decimal: DecimalFst
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, decimal: GraphFst, deterministic: bool = True):
|
||||
super().__init__(name="money", kind="verbalize", deterministic=deterministic)
|
||||
keep_space = pynini.accep(" ")
|
||||
maj = (
|
||||
pynutil.delete('currency_maj: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
min = (
|
||||
pynutil.delete('currency_min: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
fractional_part = (
|
||||
pynutil.delete('fractional_part: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
integer_part = decimal.integer
|
||||
|
||||
# *** currency_maj
|
||||
graph_integer = integer_part + keep_space + maj
|
||||
|
||||
# *** currency_maj + (***) | ((and) *** current_min)
|
||||
fractional = fractional_part + delete_extra_space + min
|
||||
|
||||
if not deterministic:
|
||||
fractional |= pynutil.insert("and ") + fractional
|
||||
|
||||
graph_integer_with_minor = (
|
||||
integer_part + keep_space + maj + keep_space + fractional + delete_preserve_order
|
||||
)
|
||||
|
||||
# *** point *** currency_maj
|
||||
graph_decimal = decimal.numbers + keep_space + maj
|
||||
|
||||
# *** current_min
|
||||
graph_minor = fractional_part + delete_extra_space + min + delete_preserve_order
|
||||
|
||||
graph = graph_integer | graph_integer_with_minor | graph_decimal | graph_minor
|
||||
|
||||
if not deterministic:
|
||||
graph |= graph_integer + delete_preserve_order
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,46 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.utils import get_abs_path
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class OrdinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing ordinal, e.g.
|
||||
ordinal { integer: "thirteen" } } -> thirteenth
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="ordinal", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
graph_digit = pynini.string_file(get_abs_path("data/ordinal/digit.tsv")).invert()
|
||||
graph_teens = pynini.string_file(get_abs_path("data/ordinal/teen.tsv")).invert()
|
||||
|
||||
graph = (
|
||||
pynutil.delete("integer:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
convert_rest = pynutil.insert("th")
|
||||
|
||||
suffix = pynini.cdrewrite(
|
||||
graph_digit | graph_teens | pynini.cross("ty", "tieth") | convert_rest,
|
||||
"",
|
||||
"[EOS]",
|
||||
DAMO_SIGMA,
|
||||
).optimize()
|
||||
self.graph = pynini.compose(graph, suffix)
|
||||
self.suffix = suffix
|
||||
delete_tokens = self.delete_tokens(self.graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,178 @@
|
||||
import os
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
MIN_NEG_WEIGHT,
|
||||
DAMO_ALPHA,
|
||||
DAMO_CHAR,
|
||||
DAMO_SIGMA,
|
||||
DAMO_SPACE,
|
||||
generator_main,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.taggers.punctuation import PunctuationFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class PostProcessingFst:
|
||||
"""
|
||||
Finite state transducer that post-processing an entire sentence after verbalization is complete, e.g.
|
||||
removes extra spaces around punctuation marks " ( one hundred and twenty three ) " -> "(one hundred and twenty three)"
|
||||
|
||||
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):
|
||||
|
||||
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, "en_tn_post_processing.far")
|
||||
if not overwrite_cache and far_file and os.path.exists(far_file):
|
||||
self.fst = pynini.Far(far_file, mode="r")["post_process_graph"]
|
||||
logging.info(f"Post processing graph was restored from {far_file}.")
|
||||
else:
|
||||
self.set_punct_dict()
|
||||
self.fst = self.get_punct_postprocess_graph()
|
||||
|
||||
if far_file:
|
||||
generator_main(far_file, {"post_process_graph": self.fst})
|
||||
|
||||
def set_punct_dict(self):
|
||||
self.punct_marks = {
|
||||
"'": [
|
||||
"'",
|
||||
"´",
|
||||
"ʹ",
|
||||
"ʻ",
|
||||
"ʼ",
|
||||
"ʽ",
|
||||
"ʾ",
|
||||
"ˈ",
|
||||
"ˊ",
|
||||
"ˋ",
|
||||
"˴",
|
||||
"ʹ",
|
||||
"΄",
|
||||
"՚",
|
||||
"՝",
|
||||
"י",
|
||||
"׳",
|
||||
"ߴ",
|
||||
"ߵ",
|
||||
"ᑊ",
|
||||
"ᛌ",
|
||||
"᾽",
|
||||
"᾿",
|
||||
"`",
|
||||
"´",
|
||||
"῾",
|
||||
"‘",
|
||||
"’",
|
||||
"‛",
|
||||
"′",
|
||||
"‵",
|
||||
"ꞌ",
|
||||
"'",
|
||||
"`",
|
||||
"𖽑",
|
||||
"𖽒",
|
||||
],
|
||||
}
|
||||
|
||||
def get_punct_postprocess_graph(self):
|
||||
"""
|
||||
Returns graph to post process punctuation marks.
|
||||
|
||||
{``} quotes are converted to {"}. Note, if there are spaces around single quote {'}, they will be kept.
|
||||
By default, a space is added after a punctuation mark, and spaces are removed before punctuation marks.
|
||||
"""
|
||||
punct_marks_all = PunctuationFst().punct_marks
|
||||
|
||||
# no_space_before_punct assume no space before them
|
||||
quotes = ["'", '"', "``", "«"]
|
||||
dashes = ["-", "—"]
|
||||
brackets = ["<", "{", "("]
|
||||
open_close_single_quotes = [
|
||||
("`", "`"),
|
||||
]
|
||||
|
||||
open_close_double_quotes = [('"', '"'), ("``", "``"), ("“", "”")]
|
||||
open_close_symbols = open_close_single_quotes + open_close_double_quotes
|
||||
allow_space_before_punct = (
|
||||
["&"] + quotes + dashes + brackets + [k[0] for k in open_close_symbols]
|
||||
)
|
||||
|
||||
no_space_before_punct = [m for m in punct_marks_all if m not in allow_space_before_punct]
|
||||
no_space_before_punct = pynini.union(*no_space_before_punct)
|
||||
no_space_after_punct = pynini.union(*brackets)
|
||||
delete_space = pynutil.delete(" ")
|
||||
delete_space_optional = pynini.closure(delete_space, 0, 1)
|
||||
|
||||
# non_punct allows space
|
||||
# delete space before no_space_before_punct marks, if present
|
||||
non_punct = pynini.difference(DAMO_CHAR, no_space_before_punct).optimize()
|
||||
graph = (
|
||||
pynini.closure(non_punct)
|
||||
+ pynini.closure(
|
||||
no_space_before_punct
|
||||
| pynutil.add_weight(delete_space + no_space_before_punct, MIN_NEG_WEIGHT)
|
||||
)
|
||||
+ pynini.closure(non_punct)
|
||||
)
|
||||
graph = pynini.closure(graph).optimize()
|
||||
graph = pynini.compose(
|
||||
graph, pynini.cdrewrite(pynini.cross("``", '"'), "", "", DAMO_SIGMA).optimize()
|
||||
).optimize()
|
||||
|
||||
# remove space after no_space_after_punct (even if there are no matching closing brackets)
|
||||
no_space_after_punct = pynini.cdrewrite(
|
||||
delete_space, no_space_after_punct, DAMO_SIGMA, DAMO_SIGMA
|
||||
).optimize()
|
||||
graph = pynini.compose(graph, no_space_after_punct).optimize()
|
||||
|
||||
# remove space around text in quotes
|
||||
single_quote = pynutil.add_weight(pynini.accep("`"), MIN_NEG_WEIGHT)
|
||||
double_quotes = pynutil.add_weight(pynini.accep('"'), MIN_NEG_WEIGHT)
|
||||
quotes_graph = (
|
||||
single_quote
|
||||
+ delete_space_optional
|
||||
+ DAMO_ALPHA
|
||||
+ DAMO_SIGMA
|
||||
+ delete_space_optional
|
||||
+ single_quote
|
||||
).optimize()
|
||||
|
||||
# this is to make sure multiple quotes are tagged from right to left without skipping any quotes in the left
|
||||
not_alpha = pynini.difference(DAMO_CHAR, DAMO_ALPHA).optimize() | pynutil.add_weight(
|
||||
DAMO_SPACE, MIN_NEG_WEIGHT
|
||||
)
|
||||
end = pynini.closure(pynutil.add_weight(not_alpha, MIN_NEG_WEIGHT))
|
||||
quotes_graph |= (
|
||||
double_quotes
|
||||
+ delete_space_optional
|
||||
+ DAMO_ALPHA
|
||||
+ DAMO_SIGMA
|
||||
+ delete_space_optional
|
||||
+ double_quotes
|
||||
+ end
|
||||
)
|
||||
|
||||
quotes_graph = pynutil.add_weight(quotes_graph, MIN_NEG_WEIGHT)
|
||||
quotes_graph = DAMO_SIGMA + pynini.closure(DAMO_SIGMA + quotes_graph + DAMO_SIGMA)
|
||||
|
||||
graph = pynini.compose(graph, quotes_graph).optimize()
|
||||
|
||||
# remove space between a word and a single quote followed by s
|
||||
remove_space_around_single_quote = pynini.cdrewrite(
|
||||
delete_space_optional + pynini.union(*self.punct_marks["'"]) + delete_space,
|
||||
DAMO_ALPHA,
|
||||
pynini.union("s ", "s[EOS]"),
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
|
||||
graph = pynini.compose(graph, remove_space_around_single_quote).optimize()
|
||||
return graph
|
||||
@@ -0,0 +1,56 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_QUOTE, GraphFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.ordinal import OrdinalFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class RomanFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing roman numerals
|
||||
e.g. tokens { roman { integer: "one" } } -> one
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="roman", kind="verbalize", deterministic=deterministic)
|
||||
suffix = OrdinalFst().suffix
|
||||
|
||||
cardinal = pynini.closure(DAMO_NOT_QUOTE)
|
||||
ordinal = pynini.compose(cardinal, suffix)
|
||||
|
||||
graph = (
|
||||
pynutil.delete('key_cardinal: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.accep(" ")
|
||||
+ pynutil.delete('integer: "')
|
||||
+ cardinal
|
||||
+ pynutil.delete('"')
|
||||
).optimize()
|
||||
|
||||
graph |= (
|
||||
pynutil.delete('default_cardinal: "default" integer: "')
|
||||
+ cardinal
|
||||
+ pynutil.delete('"')
|
||||
).optimize()
|
||||
|
||||
graph |= (
|
||||
pynutil.delete('default_ordinal: "default" integer: "') + ordinal + pynutil.delete('"')
|
||||
).optimize()
|
||||
|
||||
graph |= (
|
||||
pynutil.delete('key_the_ordinal: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.accep(" ")
|
||||
+ pynutil.delete('integer: "')
|
||||
+ pynini.closure(pynutil.insert("the "), 0, 1)
|
||||
+ ordinal
|
||||
+ pynutil.delete('"')
|
||||
).optimize()
|
||||
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,54 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TelephoneFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing telephone numbers, e.g.
|
||||
telephone { country_code: "one" number_part: "one two three, one two three, five six seven eight" extension: "one" }
|
||||
-> one, one two three, one two three, five six seven eight, one
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="telephone", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
optional_country_code = pynini.closure(
|
||||
pynutil.delete('country_code: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
+ delete_space
|
||||
+ insert_space,
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
number_part = (
|
||||
pynutil.delete('number_part: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynini.closure(pynutil.add_weight(pynutil.delete(" "), -0.0001), 0, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
|
||||
optional_extension = pynini.closure(
|
||||
delete_space
|
||||
+ insert_space
|
||||
+ pynutil.delete('extension: "')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"'),
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
||||
graph = optional_country_code + number_part + optional_extension
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,88 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_NOT_QUOTE,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
insert_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class TimeFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing time, e.g.
|
||||
time { hours: "twelve" minutes: "thirty" suffix: "a m" zone: "e s t" } -> twelve thirty a m e s t
|
||||
time { hours: "twelve" } -> twelve o'clock
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="time", kind="verbalize", deterministic=deterministic)
|
||||
hour = (
|
||||
pynutil.delete("hours:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
minute = (
|
||||
pynutil.delete("minutes:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
suffix = (
|
||||
pynutil.delete("suffix:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_suffix = pynini.closure(delete_space + insert_space + suffix, 0, 1)
|
||||
zone = (
|
||||
pynutil.delete("zone:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
optional_zone = pynini.closure(delete_space + insert_space + zone, 0, 1)
|
||||
second = (
|
||||
pynutil.delete("seconds:")
|
||||
+ delete_space
|
||||
+ pynutil.delete('"')
|
||||
+ pynini.closure(DAMO_NOT_QUOTE, 1)
|
||||
+ pynutil.delete('"')
|
||||
)
|
||||
graph_hms = (
|
||||
hour
|
||||
+ pynutil.insert(" hours ")
|
||||
+ delete_space
|
||||
+ minute
|
||||
+ pynutil.insert(" minutes and ")
|
||||
+ delete_space
|
||||
+ second
|
||||
+ pynutil.insert(" seconds")
|
||||
+ optional_suffix
|
||||
+ optional_zone
|
||||
)
|
||||
graph_hms @= pynini.cdrewrite(
|
||||
pynutil.delete("o ")
|
||||
| pynini.cross("one minutes", "one minute")
|
||||
| pynini.cross("one seconds", "one second")
|
||||
| pynini.cross("one hours", "one hour"),
|
||||
pynini.union(" ", "[BOS]"),
|
||||
"",
|
||||
DAMO_SIGMA,
|
||||
)
|
||||
graph = hour + delete_space + insert_space + minute + optional_suffix + optional_zone
|
||||
graph |= hour + insert_space + pynutil.insert("o'clock") + optional_zone
|
||||
graph |= hour + delete_space + insert_space + suffix + optional_zone
|
||||
graph |= graph_hms
|
||||
delete_tokens = self.delete_tokens(graph)
|
||||
self.fst = delete_tokens.optimize()
|
||||
@@ -0,0 +1,70 @@
|
||||
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.abbreviation import AbbreviationFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.cardinal import CardinalFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.date import DateFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.decimal import DecimalFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.electronic import ElectronicFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.fraction import FractionFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.measure import MeasureFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.money import MoneyFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.ordinal import OrdinalFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.roman import RomanFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.telephone import TelephoneFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.time import TimeFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.whitelist import WhiteListFst
|
||||
|
||||
|
||||
class VerbalizeFst(GraphFst):
|
||||
"""
|
||||
Composes other verbalizer grammars.
|
||||
For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File.
|
||||
More details to deployment at NeMo/tools/text_processing_deployment.
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="verbalize", kind="verbalize", deterministic=deterministic)
|
||||
cardinal = CardinalFst(deterministic=deterministic)
|
||||
cardinal_graph = cardinal.fst
|
||||
decimal = DecimalFst(cardinal=cardinal, deterministic=deterministic)
|
||||
decimal_graph = decimal.fst
|
||||
ordinal = OrdinalFst(deterministic=deterministic)
|
||||
ordinal_graph = ordinal.fst
|
||||
fraction = FractionFst(deterministic=deterministic)
|
||||
fraction_graph = fraction.fst
|
||||
telephone_graph = TelephoneFst(deterministic=deterministic).fst
|
||||
electronic_graph = ElectronicFst(deterministic=deterministic).fst
|
||||
measure = MeasureFst(
|
||||
decimal=decimal, cardinal=cardinal, fraction=fraction, deterministic=deterministic
|
||||
)
|
||||
measure_graph = measure.fst
|
||||
time_graph = TimeFst(deterministic=deterministic).fst
|
||||
date_graph = DateFst(ordinal=ordinal, deterministic=deterministic).fst
|
||||
money_graph = MoneyFst(decimal=decimal, deterministic=deterministic).fst
|
||||
whitelist_graph = WhiteListFst(deterministic=deterministic).fst
|
||||
|
||||
graph = (
|
||||
time_graph
|
||||
| date_graph
|
||||
| money_graph
|
||||
| measure_graph
|
||||
| ordinal_graph
|
||||
| decimal_graph
|
||||
| cardinal_graph
|
||||
| telephone_graph
|
||||
| electronic_graph
|
||||
| fraction_graph
|
||||
| whitelist_graph
|
||||
)
|
||||
|
||||
roman_graph = RomanFst(deterministic=deterministic).fst
|
||||
graph |= roman_graph
|
||||
|
||||
if not deterministic:
|
||||
abbreviation_graph = AbbreviationFst(deterministic=deterministic).fst
|
||||
graph |= abbreviation_graph
|
||||
|
||||
self.fst = graph
|
||||
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
GraphFst,
|
||||
delete_extra_space,
|
||||
delete_space,
|
||||
generator_main,
|
||||
)
|
||||
from fun_text_processing.text_normalization.en.verbalizers.verbalize import VerbalizeFst
|
||||
from fun_text_processing.text_normalization.en.verbalizers.word import WordFst
|
||||
from pynini.lib import pynutil
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class VerbalizeFinalFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer that verbalizes an entire sentence, e.g.
|
||||
tokens { name: "its" } tokens { time { hours: "twelve" minutes: "thirty" } } tokens { name: "now" } tokens { name: "." } -> its twelve thirty now .
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple options (used for audio-based normalization)
|
||||
cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache.
|
||||
overwrite_cache: set to True to overwrite .far files
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, deterministic: bool = True, cache_dir: str = None, overwrite_cache: bool = False
|
||||
):
|
||||
super().__init__(name="verbalize_final", kind="verbalize", deterministic=deterministic)
|
||||
|
||||
far_file = None
|
||||
if cache_dir is not None and cache_dir != "None":
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
far_file = os.path.join(
|
||||
cache_dir, f"en_tn_{deterministic}_deterministic_verbalizer.far"
|
||||
)
|
||||
if not overwrite_cache and far_file and os.path.exists(far_file):
|
||||
self.fst = pynini.Far(far_file, mode="r")["verbalize"]
|
||||
logging.info(f"VerbalizeFinalFst graph was restored from {far_file}.")
|
||||
else:
|
||||
verbalize = VerbalizeFst(deterministic=deterministic).fst
|
||||
word = WordFst(deterministic=deterministic).fst
|
||||
types = verbalize | word
|
||||
|
||||
if deterministic:
|
||||
graph = (
|
||||
pynutil.delete("tokens")
|
||||
+ delete_space
|
||||
+ pynutil.delete("{")
|
||||
+ delete_space
|
||||
+ types
|
||||
+ delete_space
|
||||
+ pynutil.delete("}")
|
||||
)
|
||||
else:
|
||||
graph = delete_space + types + delete_space
|
||||
|
||||
graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space
|
||||
|
||||
self.fst = graph.optimize()
|
||||
if far_file:
|
||||
generator_main(far_file, {"verbalize": self.fst})
|
||||
logging.info(f"VerbalizeFinalFst grammars are saved to {far_file}.")
|
||||
@@ -0,0 +1,31 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.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: "misses" } } -> misses
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="whitelist", kind="verbalize", deterministic=deterministic)
|
||||
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,33 @@
|
||||
import pynini
|
||||
from fun_text_processing.text_normalization.en.graph_utils import (
|
||||
DAMO_CHAR,
|
||||
DAMO_SIGMA,
|
||||
GraphFst,
|
||||
delete_space,
|
||||
)
|
||||
from pynini.lib import pynutil
|
||||
|
||||
|
||||
class WordFst(GraphFst):
|
||||
"""
|
||||
Finite state transducer for verbalizing word
|
||||
e.g. tokens { name: "sleep" } -> sleep
|
||||
|
||||
Args:
|
||||
deterministic: if True will provide a single transduction option,
|
||||
for False multiple transduction are generated (used for audio-based normalization)
|
||||
"""
|
||||
|
||||
def __init__(self, deterministic: bool = True):
|
||||
super().__init__(name="word", kind="verbalize", deterministic=deterministic)
|
||||
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