chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:25:10 +08:00
commit c397331b1e
3684 changed files with 990993 additions and 0 deletions
@@ -0,0 +1,28 @@
import pynini
from fun_text_processing.text_normalization.en.graph_utils import DAMO_NOT_QUOTE, GraphFst
from pynini.lib import pynutil
class CardinalFst(GraphFst):
"""
Finite state transducer for verbalizing cardinals
e.g. cardinal { integer: "zwei" } -> "zwei"
Args:
deterministic: if True will provide a single transduction option,
for False multiple transduction are generated (used for audio-based normalization)
"""
def __init__(self, deterministic: bool = True):
super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic)
optional_sign = pynini.closure(pynini.cross('negative: "true" ', "minus "), 0, 1)
self.optional_sign = optional_sign
integer = pynini.closure(DAMO_NOT_QUOTE, 1)
self.integer = pynutil.delete(' "') + integer + pynutil.delete('"')
integer = pynutil.delete("integer:") + self.integer
self.numbers = integer
graph = optional_sign + self.numbers
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,55 @@
import pynini
from fun_text_processing.text_normalization.de.utils import get_abs_path, load_labels
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
DAMO_SIGMA,
GraphFst,
delete_preserve_order,
)
from pynini.lib import pynutil
class DateFst(GraphFst):
"""
Finite state transducer for verbalizing date, e.g.
date { day: "vier" month: "april" year: "zwei tausend zwei" } -> "vierter april zwei tausend zwei"
date { day: "vier" month: "mai" year: "zwei tausend zwei" } -> "vierter mai zwei tausend zwei"
Args:
ordinal: ordinal verbalizer GraphFst
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):
super().__init__(name="date", kind="verbalize", deterministic=deterministic)
day_cardinal = (
pynutil.delete('day: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
)
day = day_cardinal @ pynini.cdrewrite(
ordinal.ordinal_stem, "", "[EOS]", DAMO_SIGMA
) + pynutil.insert("ter")
months_names = pynini.union(
*[x[1] for x in load_labels(get_abs_path("data/months/abbr_to_name.tsv"))]
)
month = pynutil.delete('month: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
final_month = month @ months_names
final_month |= month @ pynini.difference(DAMO_SIGMA, months_names) @ pynini.cdrewrite(
ordinal.ordinal_stem, "", "[EOS]", DAMO_SIGMA
) + pynutil.insert("ter")
year = pynutil.delete('year: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
# day month year
graph_dmy = (
day + pynini.accep(" ") + final_month + pynini.closure(pynini.accep(" ") + year, 0, 1)
)
graph_dmy |= final_month + pynini.accep(" ") + year
self.graph = graph_dmy | year
final_graph = self.graph + delete_preserve_order
delete_tokens = self.delete_tokens(final_graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,57 @@
import pynini
from fun_text_processing.text_normalization.de.taggers.decimal import quantities
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
GraphFst,
delete_preserve_order,
insert_space,
)
from pynini.lib import pynutil
class DecimalFst(GraphFst):
"""
Finite state transducer for classifying decimal, e.g.
decimal { negative: "true" integer_part: "elf" fractional_part: "vier null sechs" quantity: "billionen" } -> minus elf komma vier null sechs billionen
decimal { integer_part: "eins" quantity: "billion" } -> eins billion
"""
def __init__(self, deterministic: bool = True):
super().__init__(name="decimal", kind="classify", deterministic=deterministic)
delete_space = pynutil.delete(" ")
self.optional_sign = pynini.closure(
pynini.cross('negative: "true"', "minus ") + delete_space, 0, 1
)
self.integer = (
pynutil.delete('integer_part: "')
+ pynini.closure(DAMO_NOT_QUOTE, 1)
+ pynutil.delete('"')
)
self.fractional_default = (
pynutil.delete('fractional_part: "')
+ pynini.closure(DAMO_NOT_QUOTE, 1)
+ pynutil.delete('"')
)
self.fractional = pynutil.insert(" komma ") + self.fractional_default
self.quantity = (
delete_space
+ insert_space
+ pynutil.delete('quantity: "')
+ quantities
+ pynutil.delete('"')
)
self.optional_quantity = pynini.closure(self.quantity, 0, 1)
graph = self.optional_sign + (
self.integer + self.quantity
| self.integer + delete_space + self.fractional + self.optional_quantity
)
self.numbers = graph
graph += delete_preserve_order
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,64 @@
import pynini
from fun_text_processing.text_normalization.de.utils import get_abs_path
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
DAMO_SIGMA,
GraphFst,
delete_preserve_order,
insert_space,
)
from pynini.lib import pynutil
class ElectronicFst(GraphFst):
"""
Finite state transducer for verbalizing electronic
e.g. electronic { username: "abc" domain: "hotmail.com" } -> "a b c at hotmail punkt com"
-> "a b c at h o t m a i l punkt c o m"
-> "a b c at hotmail punkt c o m"
-> "a b c at h o t m a i l punkt com"
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/numbers/digit.tsv"))
).optimize() | pynini.cross("1", "eins")
graph_zero = pynini.invert(
pynini.string_file(get_abs_path("data/numbers/zero.tsv"))
).optimize()
graph_digit = graph_digit_no_zero | graph_zero
graph_symbols = pynini.string_file(get_abs_path("data/electronic/symbols.tsv")).optimize()
server_common = pynini.string_file(get_abs_path("data/electronic/server_name.tsv"))
domain_common = pynini.string_file(get_abs_path("data/electronic/domain.tsv"))
def add_space_after_char():
return pynini.closure(DAMO_NOT_QUOTE - pynini.accep(" ") + insert_space) + (
DAMO_NOT_QUOTE - pynini.accep(" ")
)
verbalize_characters = pynini.cdrewrite(graph_symbols | graph_digit, "", "", DAMO_SIGMA)
user_name = pynutil.delete('username: "') + add_space_after_char() + pynutil.delete('"')
user_name @= verbalize_characters
convert_defaults = (
pynutil.add_weight(DAMO_NOT_QUOTE, weight=0.0001) | domain_common | server_common
)
domain = convert_defaults + pynini.closure(insert_space + convert_defaults)
domain @= verbalize_characters
domain = pynutil.delete('domain: "') + domain + pynutil.delete('"')
protocol = (
pynutil.delete('protocol: "')
+ add_space_after_char() @ pynini.cdrewrite(graph_symbols, "", "", DAMO_SIGMA)
+ pynutil.delete('"')
)
self.graph = (pynini.closure(protocol + pynini.accep(" "), 0, 1) + domain) | (
user_name + pynini.accep(" ") + pynutil.insert("at ") + domain
)
delete_tokens = self.delete_tokens(self.graph + delete_preserve_order)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,68 @@
import pynini
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
DAMO_SIGMA,
GraphFst,
delete_preserve_order,
insert_space,
)
from pynini.lib import pynutil
class FractionFst(GraphFst):
"""
Finite state transducer for verbalizing fraction
e.g. fraction { integer: "drei" numerator: "eins" denominator: "zwei" }-> drei ein halb
e.g. fraction { numerator: "vier" denominator: "zwei" } -> vier halbe
e.g. fraction { numerator: "drei" denominator: "vier" } -> drei viertel
Args:
ordinal: ordinal GraphFst
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):
super().__init__(name="fraction", kind="verbalize", deterministic=deterministic)
optional_sign = pynini.closure(
pynini.cross('negative: "true"', "minus ") + pynutil.delete(" "), 0, 1
)
change_one = pynini.cdrewrite(
pynutil.add_weight(pynini.cross("eins", "ein"), weight=-0.0001),
"[BOS]",
"[EOS]",
DAMO_SIGMA,
)
change_numerator_two = pynini.cdrewrite(
pynini.cross("zweitel", "halbe"), "[BOS]", "[EOS]", DAMO_SIGMA
)
integer = pynutil.delete('integer_part: "') + change_one + pynutil.delete('" ')
numerator = pynutil.delete('numerator: "') + change_one + pynutil.delete('" ')
denominator = (
pynutil.delete('denominator: "')
+ pynini.closure(DAMO_NOT_QUOTE)
@ (
pynini.cdrewrite(
pynini.closure(ordinal.ordinal_stem, 0, 1), "", "[EOS]", DAMO_SIGMA
)
+ pynutil.insert("tel")
)
@ change_numerator_two
+ pynutil.delete('"')
)
integer += insert_space + pynini.closure(pynutil.insert("und ", weight=0.001), 0, 1)
denominator_one_half = pynini.cdrewrite(
pynini.cross("ein halbe", "ein halb"), "[BOS]", "[EOS]", DAMO_SIGMA
)
fraction_default = (numerator + insert_space + denominator) @ denominator_one_half
self.graph = optional_sign + pynini.closure(integer, 0, 1) + fraction_default
graph = self.graph + delete_preserve_order
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,41 @@
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 MeasureFst(GraphFst):
"""
Finite state transducer for verbalizing measure, e.g.
measure { cardinal { integer: "zwei" units: "unzen" } } -> "zwei unzen"
measure { cardinal { integer_part: "zwei" quantity: "millionen" units: "unzen" } } -> "zwei millionen unzen"
Args:
decimal: decimal GraphFst
cardinal: cardinal GraphFst
fraction: fraction GraphFst
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
):
super().__init__(name="measure", kind="verbalize", deterministic=deterministic)
unit = pynutil.delete('units: "') + pynini.closure(DAMO_NOT_QUOTE) + pynutil.delete('"')
graph_decimal = decimal.fst
graph_cardinal = cardinal.fst
graph_fraction = fraction.fst
graph = (graph_cardinal | graph_decimal | graph_fraction) + pynini.accep(" ") + unit
graph |= unit + delete_extra_space + (graph_cardinal | graph_decimal)
graph += delete_preserve_order
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,77 @@
import pynini
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
GraphFst,
delete_preserve_order,
)
from pynini.lib import pynutil
class MoneyFst(GraphFst):
"""
Finite state transducer for verbalizing money, e.g.
money { currency_maj: "euro" integer_part: "ein"} -> "ein euro"
money { currency_maj: "euro" integer_part: "eins" fractional_part: "null null eins"} -> "eins komma null null eins euro"
money { integer_part: "ein" currency_maj: "pfund" fractional_part: "vierzig" preserve_order: true} -> "ein pfund vierzig"
money { integer_part: "ein" currency_maj: "pfund" fractional_part: "vierzig" currency_min: "pence" preserve_order: true} -> "ein pfund vierzig pence"
money { fractional_part: "ein" currency_min: "penny" preserve_order: true} -> "ein penny"
money { currency_maj: "pfund" integer_part: "null" fractional_part: "null eins" quantity: "million"} -> "null komma null eins million pfund"
Args:
decimal: GraphFst
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 = (
pynutil.delete('integer_part: "')
+ pynini.closure(DAMO_NOT_QUOTE, 1)
+ pynutil.delete('"')
)
optional_add_and = pynini.closure(pynutil.insert("und "), 0, 1)
# *** currency_maj
graph_integer = integer_part + keep_space + maj
# *** currency_maj + (***) | ((und) *** current_min)
graph_integer_with_minor = (
integer_part
+ keep_space
+ maj
+ keep_space
+ (fractional_part | (optional_add_and + fractional_part + keep_space + min))
+ delete_preserve_order
)
# *** komma *** currency_maj
graph_decimal = decimal.fst + keep_space + maj
# *** current_min
graph_minor = fractional_part + keep_space + min + delete_preserve_order
graph = graph_integer | graph_integer_with_minor | graph_decimal | graph_minor
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,45 @@
import pynini
from fun_text_processing.text_normalization.de.utils import get_abs_path
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
DAMO_SIGMA,
GraphFst,
)
from pynini.lib import pynutil
class OrdinalFst(GraphFst):
"""
Finite state transducer for verbalizing roman numerals
e.g. ordinal { integer: "vier" } } -> "vierter"
-> "viertes" ...
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/ordinals/digit.tsv")).invert()
graph_ties = pynini.string_file(get_abs_path("data/ordinals/ties.tsv")).invert()
graph_thousands = pynini.string_file(get_abs_path("data/ordinals/thousands.tsv")).invert()
graph = (
pynutil.delete('integer: "') + pynini.closure(DAMO_NOT_QUOTE, 1) + pynutil.delete('"')
)
suffixes = pynini.union("ten", "tem", "ter", "tes", "te")
convert_rest = pynutil.insert(suffixes, weight=0.01)
self.ordinal_stem = graph_digit | graph_ties | graph_thousands
suffix = pynini.cdrewrite(
pynini.closure(self.ordinal_stem, 0, 1) + 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,40 @@
import pynini
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_NOT_QUOTE,
GraphFst,
delete_preserve_order,
)
from pynini.lib import pynutil
class TelephoneFst(GraphFst):
"""
Finite state transducer for verbalizing telephone, e.g.
telephone { country_code: "plus neun und vierzig" number_part: "null eins eins eins null null null" }
-> "plus neun und vierzig null eins eins eins null null null"
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)
country_code = (
pynutil.delete('country_code: "')
+ pynini.closure(DAMO_NOT_QUOTE, 1)
+ pynutil.delete('"')
)
number_part = (
pynutil.delete('number_part: "')
+ pynini.closure(DAMO_NOT_QUOTE, 1)
+ pynutil.delete('"')
)
self.graph = country_code + pynini.accep(" ") + number_part
graph = self.graph + delete_preserve_order
delete_tokens = self.delete_tokens(graph)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,126 @@
import pynini
from fun_text_processing.text_normalization.de.utils import get_abs_path, load_labels
from fun_text_processing.text_normalization.en.graph_utils import (
DAMO_DIGIT,
DAMO_SIGMA,
GraphFst,
convert_space,
delete_preserve_order,
)
from pynini.lib import pynutil
class TimeFst(GraphFst):
"""
Finite state transducer for verbalizing electronic, e.g.
time { hours: "2" minutes: "15"} -> "zwei uhr fünfzehn"
time { minutes: "15" hours: "2" } -> "viertel nach zwei"
time { minutes: "15" hours: "2" } -> "fünfzehn nach zwei"
time { hours: "14" minutes: "15"} -> "vierzehn uhr fünfzehn"
time { minutes: "15" hours: "14" } -> "viertel nach zwei"
time { minutes: "15" hours: "14" } -> "fünfzehn nach drei"
time { minutes: "45" hours: "14" } -> "viertel vor drei"
Args:
cardinal_tagger: cardinal_tagger tagger GraphFst
deterministic: if True will provide a single transduction option,
for False multiple transduction are generated (used for audio-based normalization)
"""
def __init__(self, cardinal_tagger: GraphFst, deterministic: bool = True):
super().__init__(name="time", kind="verbalize", deterministic=deterministic)
# add weight so when using inverse text normalization this conversion is depriotized
night_to_early = pynutil.add_weight(
pynini.invert(
pynini.string_file(get_abs_path("data/time/hour_to_night.tsv"))
).optimize(),
weight=0.0001,
)
hour_to = pynini.invert(
pynini.string_file(get_abs_path("data/time/hour_to.tsv"))
).optimize()
minute_to = pynini.invert(
pynini.string_file(get_abs_path("data/time/minute_to.tsv"))
).optimize()
time_zone_graph = pynini.invert(
convert_space(
pynini.union(*[x[1] for x in load_labels(get_abs_path("data/time/time_zone.tsv"))])
)
)
graph_zero = pynini.invert(
pynini.string_file(get_abs_path("data/numbers/zero.tsv"))
).optimize()
number_verbalization = graph_zero | cardinal_tagger.two_digit_non_zero
hour = pynutil.delete('hours: "') + pynini.closure(DAMO_DIGIT, 1) + pynutil.delete('"')
hour_verbalized = hour @ number_verbalization @ pynini.cdrewrite(
pynini.cross("eins", "ein"), "[BOS]", "[EOS]", DAMO_SIGMA
) + pynutil.insert(" uhr")
minute = pynutil.delete('minutes: "') + pynini.closure(DAMO_DIGIT, 1) + pynutil.delete('"')
zone = pynutil.delete('zone: "') + time_zone_graph + pynutil.delete('"')
optional_zone = pynini.closure(pynini.accep(" ") + zone, 0, 1)
second = pynutil.delete('seconds: "') + pynini.closure(DAMO_DIGIT, 1) + pynutil.delete('"')
graph_hms = (
hour_verbalized
+ pynini.accep(" ")
+ minute @ number_verbalization
+ pynutil.insert(" minuten")
+ pynini.accep(" ")
+ second @ number_verbalization
+ pynutil.insert(" sekunden")
+ optional_zone
)
graph_hms @= pynini.cdrewrite(
pynini.cross("eins minuten", "eine minute")
| pynini.cross("eins sekunden", "eine sekunde"),
pynini.union(" ", "[BOS]"),
"",
DAMO_SIGMA,
)
min_30 = [str(x) for x in range(1, 31)]
min_30 = pynini.union(*min_30)
min_29 = [str(x) for x in range(1, 30)]
min_29 = pynini.union(*min_29)
graph_h = hour_verbalized
graph_hm = hour_verbalized + pynini.accep(" ") + minute @ number_verbalization
graph_m_past_h = (
minute @ min_30 @ (number_verbalization | pynini.cross("15", "viertel"))
+ pynini.accep(" ")
+ pynutil.insert("nach ")
# + hour @ number_verbalization
+ hour
@ pynini.cdrewrite(night_to_early, "[BOS]", "[EOS]", DAMO_SIGMA)
@ number_verbalization
)
graph_m30_h = (
minute @ pynini.cross("30", "halb")
+ pynini.accep(" ")
+ hour
@ pynini.cdrewrite(night_to_early, "[BOS]", "[EOS]", DAMO_SIGMA)
@ hour_to
@ number_verbalization
)
graph_m_to_h = (
minute @ minute_to @ min_29 @ (number_verbalization | pynini.cross("15", "viertel"))
+ pynini.accep(" ")
+ pynutil.insert("vor ")
+ hour
@ pynini.cdrewrite(night_to_early, "[BOS]", "[EOS]", DAMO_SIGMA)
@ hour_to
@ number_verbalization
)
self.graph = (
graph_hms
| graph_h
| graph_hm
| pynutil.add_weight(graph_m_past_h, weight=0.0001)
| pynutil.add_weight(graph_m30_h, weight=0.0001)
| pynutil.add_weight(graph_m_to_h, weight=0.0001)
) + optional_zone
delete_tokens = self.delete_tokens(self.graph + delete_preserve_order)
self.fst = delete_tokens.optimize()
@@ -0,0 +1,64 @@
from fun_text_processing.text_normalization.de.taggers.cardinal import CardinalFst as CardinalTagger
from fun_text_processing.text_normalization.de.verbalizers.cardinal import CardinalFst
from fun_text_processing.text_normalization.de.verbalizers.date import DateFst
from fun_text_processing.text_normalization.de.verbalizers.decimal import DecimalFst
from fun_text_processing.text_normalization.de.verbalizers.electronic import ElectronicFst
from fun_text_processing.text_normalization.de.verbalizers.fraction import FractionFst
from fun_text_processing.text_normalization.de.verbalizers.measure import MeasureFst
from fun_text_processing.text_normalization.de.verbalizers.money import MoneyFst
from fun_text_processing.text_normalization.de.verbalizers.ordinal import OrdinalFst
from fun_text_processing.text_normalization.de.verbalizers.telephone import TelephoneFst
from fun_text_processing.text_normalization.de.verbalizers.time import TimeFst
from fun_text_processing.text_normalization.en.graph_utils import GraphFst
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_tagger = CardinalTagger(deterministic=deterministic)
cardinal = CardinalFst(deterministic=deterministic)
cardinal_graph = cardinal.fst
ordinal = OrdinalFst(deterministic=deterministic)
ordinal_graph = ordinal.fst
decimal = DecimalFst(deterministic=deterministic)
decimal_graph = decimal.fst
fraction = FractionFst(ordinal=ordinal, deterministic=deterministic)
fraction_graph = fraction.fst
date = DateFst(ordinal=ordinal)
date_graph = date.fst
measure = MeasureFst(
cardinal=cardinal, decimal=decimal, fraction=fraction, deterministic=deterministic
)
measure_graph = measure.fst
electronic = ElectronicFst(deterministic=deterministic)
electronic_graph = electronic.fst
whitelist_graph = WhiteListFst(deterministic=deterministic).fst
money_graph = MoneyFst(decimal=decimal).fst
telephone_graph = TelephoneFst(deterministic=deterministic).fst
time_graph = TimeFst(cardinal_tagger=cardinal_tagger, deterministic=deterministic).fst
graph = (
cardinal_graph
| measure_graph
| decimal_graph
| ordinal_graph
| date_graph
| electronic_graph
| money_graph
| fraction_graph
| whitelist_graph
| telephone_graph
| time_graph
)
self.fst = graph
@@ -0,0 +1,61 @@
import os
import pynini
from fun_text_processing.text_normalization.de.verbalizers.verbalize import VerbalizeFst
from fun_text_processing.text_normalization.en.graph_utils import (
GraphFst,
delete_extra_space,
delete_space,
generator_main,
)
from fun_text_processing.text_normalization.en.verbalizers.word import WordFst
from pynini.lib import pynutil
import logging
class VerbalizeFinalFst(GraphFst):
"""
Finite state transducer that verbalizes an entire sentence
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"de_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
graph = (
pynutil.delete("tokens")
+ delete_space
+ pynutil.delete("{")
+ delete_space
+ types
+ delete_space
+ pynutil.delete("}")
)
graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space
self.fst = graph.optimize()
if far_file:
generator_main(far_file, {"verbalize": self.fst})
logging.info(f"VerbalizeFinalFst grammars are saved to {far_file}.")