1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- from pynini import closure , cross , string_file
15+ from pynini import closure , cross , string_file , union
1616from pynini .lib .pynutil import delete , insert
1717
1818from itn .english .rules .cardinal import Cardinal
1919from tn .processor import Processor
2020from tn .utils import get_abs_path
2121
2222
23+ def _num_to_word (n ):
24+ ones = ["" , "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , "nine" ,
25+ "ten" , "eleven" , "twelve" , "thirteen" , "fourteen" , "fifteen" , "sixteen" ,
26+ "seventeen" , "eighteen" , "nineteen" ]
27+ tens = ["" , "" , "twenty" , "thirty" , "forty" , "fifty" , "sixty" , "seventy" , "eighty" , "ninety" ]
28+ if n < 20 :
29+ return ones [n ]
30+ return tens [n // 10 ] + (" " + ones [n % 10 ] if n % 10 else "" )
31+
32+
2333class Time (Processor ):
2434
2535 def __init__ (self , cardinal = None ):
@@ -29,34 +39,58 @@ def __init__(self, cardinal=None):
2939 self .build_verbalizer ()
3040
3141 def build_tagger (self ):
32- digit = string_file (get_abs_path ("../itn/english/data/numbers/digit.tsv" ))
33- teen = string_file (get_abs_path ("../itn/english/data/numbers/teen.tsv" ))
34- ties = string_file (get_abs_path ("../itn/english/data/numbers/ties.tsv" ))
42+ cardinal_graph = self .cardinal .graph
3543 time_suffix = string_file (get_abs_path ("../itn/english/data/time/time_suffix.tsv" ))
3644 time_zone = string_file (get_abs_path ("../itn/english/data/time/time_zone.tsv" ))
3745 ds = delete (" " )
3846
39- hour = teen | (insert ("0" ) + digit )
40- minute = teen | (ties + (ds + digit | insert ("0" ))) | insert ("0" ) + digit
47+ # hours: 0-23, only valid hour words, with zero-padding
48+ hour_labels = [_num_to_word (x ) for x in range (0 , 24 ) if _num_to_word (x )]
49+ hour_padded = union (* [cross (_num_to_word (x ), f"{ x :02d} " ) for x in range (0 , 24 ) if _num_to_word (x )])
50+ # minutes: 1-9 (single), 10-59 (double)
51+ min_single = [_num_to_word (x ) for x in range (1 , 10 )]
52+ min_double = [_num_to_word (x ) for x in range (10 , 60 )]
53+ graph_min_single = union (* [cross (_num_to_word (x ), f"{ x :02d} " ) for x in range (1 , 10 )])
54+ graph_min_double = union (* [cross (_num_to_word (x ), str (x )) for x in range (10 , 60 )])
4155
42- # two thirty => 02:30
43- graph = insert ('hour: "' ) + hour + insert ('" ' ) + ds + insert ('minute: "' ) + minute + insert ('"' )
44- # eight oclock => 08:00
45- oclock = cross ("o'clock" , "" ) | cross ("oclock" , "" )
46- graph |= insert ('hour: "' ) + hour + insert ('" minute: "00"' ) + ds + oclock
56+ hour = insert ('hour: "' ) + hour_padded + insert ('"' )
57+ oclock = cross ("o'clock" , "" ) | cross ("oclock" , "" ) | cross ("hundred hours" , "" )
58+ minute = (
59+ oclock + insert ("00" )
60+ | delete ("o" ) + ds + graph_min_single
61+ | graph_min_double
62+ )
4763
4864 suffix = ds + insert (' noon: "' ) + time_suffix + insert ('"' )
4965 zone = ds + insert (' zone: "' ) + time_zone + insert ('"' )
50- graph += suffix .ques + zone .ques
5166
52- self .tagger = self .add_tokens (graph )
67+ # "eight oclock" (no suffix needed)
68+ graph_oclock = hour + ds + insert (' minute: "' ) + oclock + insert ('00"' )
69+ # "two o five" (no suffix needed)
70+ graph_o_min = hour + ds + insert (' minute: "' ) + delete ("o" ) + ds + graph_min_single + insert ('"' )
71+ # "two pm", "three am" (hour + suffix, minutes = 00)
72+ graph_h_suffix = hour + insert (' minute: "00"' ) + suffix + closure (zone , 0 , 1 )
73+ # "two thirty am" (hour + minute + suffix required)
74+ graph_hm_suffix = (
75+ hour + ds + insert (' minute: "' ) + graph_min_double + insert ('"' )
76+ + suffix + closure (zone , 0 , 1 )
77+ )
78+ # "half past two", "quarter past two"
79+ graph_half_quarter = (
80+ insert ('minute: "' )
81+ + (cross ("half" , "30" ) | cross ("quarter" , "15" ))
82+ + insert ('"' )
83+ + ds + delete ("past" ) + ds
84+ + hour
85+ )
86+
87+ final_graph = graph_oclock | graph_o_min | graph_h_suffix | graph_hm_suffix | graph_half_quarter
88+ self .tagger = self .add_tokens (final_graph )
5389
5490 def build_verbalizer (self ):
55- hours = delete ('hour: "' ) + self .NOT_QUOTE .plus + delete ('"' )
56- minutes = delete (' minute: "' ) + self .NOT_QUOTE .plus + delete ('"' )
57- suffix = delete (' noon: "' ) + self .NOT_QUOTE .plus + delete ('"' )
58- zone = delete (' zone: "' ) + self .NOT_QUOTE .plus + delete ('"' )
59- graph = hours + insert (":" ) + self .DELETE_SPACE + minutes
60- graph += closure (insert (" " ) + self .DELETE_SPACE + suffix , 0 , 1 )
61- graph += closure (insert (" " ) + self .DELETE_SPACE + zone , 0 , 1 )
91+ hour = delete ('hour: "' ) + self .NOT_QUOTE .plus + delete ('"' )
92+ minute = delete (' minute: "' ) + self .NOT_QUOTE .plus + delete ('"' )
93+ noon = delete (' noon: "' ) + self .NOT_QUOTE .plus + delete ('"' )
94+ graph = hour + insert (":" ) + self .DELETE_SPACE + minute
95+ graph += closure (insert (" " ) + self .DELETE_SPACE + noon , 0 , 1 )
6296 self .verbalizer = self .delete_tokens (graph )
0 commit comments