Jarbas commited on
Commit
f8bb698
·
verified ·
1 Parent(s): 62a470a

CATT-EO stitched single onnx

Browse files
Files changed (1) hide show
  1. tashkeel_tokenizer_onnx.py +158 -0
tashkeel_tokenizer_onnx.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import re
3
+ import numpy as np
4
+ import bw2ar
5
+ from utils import HARAKAT_PAT
6
+
7
+
8
+ class TashkeelTokenizer:
9
+
10
+ def __init__(self):
11
+ self.letters = [' ', '$', '&', "'", '*', '<', '>', 'A', 'D', 'E', 'H', 'S', 'T', 'Y', 'Z',
12
+ 'b', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't',
13
+ 'v', 'w', 'x', 'y', 'z', '|', '}'
14
+ ]
15
+ self.letters = ['<PAD>', '<BOS>', '<EOS>'] + self.letters + ['<MASK>']
16
+
17
+ self.no_tashkeel_tag = '<NT>'
18
+ self.tashkeel_list = ['<NT>', '<SD>', '<SDD>', '<SF>', '<SFF>', '<SK>',
19
+ '<SKK>', 'F', 'K', 'N', 'a', 'i', 'o', 'u', '~']
20
+
21
+ self.tashkeel_list = ['<PAD>', '<BOS>', '<EOS>'] + self.tashkeel_list
22
+
23
+ self.tashkeel_map = {c:i for i,c in enumerate(self.tashkeel_list)}
24
+ self.letters_map = {c:i for i,c in enumerate(self.letters)}
25
+ self.inverse_tags = {
26
+ '~a': '<SF>', # shaddah and fatHa
27
+ '~u': '<SD>', # shaddah and Damma
28
+ '~i': '<SK>', # shaddah and kasra
29
+ '~F': '<SFF>', # shaddah and fatHatayn
30
+ '~N': '<SDD>', # shaddah and Dammatayn
31
+ '~K': '<SKK>' # shaddah and kasratayn
32
+ }
33
+ self.tags = {v:k for k,v in self.inverse_tags.items()}
34
+ self.shaddah_last = ['a~', 'u~', 'i~', 'F~', 'N~', 'K~']
35
+ self.shaddah_first = ['~a', '~u', '~i', '~F', '~N', '~K']
36
+ self.tahkeel_chars = ['F','N','K','a', 'u', 'i', '~', 'o']
37
+
38
+ def clean_text(self, text):
39
+ text = re.sub(u'[%s]' % u'\u0640', '', text) # strip tatweel
40
+ text = text.replace('ٱ', 'ا')
41
+ return ' '.join(re.sub(u"[^\u0621-\u063A\u0640-\u0652\u0670\u0671\ufefb\ufef7\ufef5\ufef9 ]", " ", text, flags=re.UNICODE).split())
42
+
43
+ def check_match(self, text_with_tashkeel, letter_n_tashkeel_pairs):
44
+ text_with_tashkeel = text_with_tashkeel.strip()
45
+ # test if the reconstructed text with tashkeel is the same as the original one
46
+ syn_text = self.combine_tashkeel_with_text(letter_n_tashkeel_pairs)
47
+ return syn_text == text_with_tashkeel or syn_text == self.unify_shaddah_position(text_with_tashkeel)
48
+
49
+ def unify_shaddah_position(self, text_with_tashkeel):
50
+ # unify the order of shaddah and the harakah to make shaddah always at the beginning
51
+ for i in range(len(self.shaddah_first)):
52
+ text_with_tashkeel = text_with_tashkeel.replace(self.shaddah_last[i], self.shaddah_first[i])
53
+ return text_with_tashkeel
54
+
55
+ def split_tashkeel_from_text(self, text_with_tashkeel, test_match=True):
56
+ text_with_tashkeel = self.clean_text(text_with_tashkeel)
57
+ text_with_tashkeel = bw2ar.transliterate_text(text_with_tashkeel, 'ar2bw')
58
+ text_with_tashkeel = text_with_tashkeel.replace('`', '') # remove dagger 'alif
59
+
60
+ # unify the order of shaddah and the harakah to make shaddah always at the beginning
61
+ text_with_tashkeel = self.unify_shaddah_position(text_with_tashkeel)
62
+
63
+ # remove duplicated harakat
64
+ for i in range(len(self.tahkeel_chars)):
65
+ text_with_tashkeel = text_with_tashkeel.replace(self.tahkeel_chars[i]*2, self.tahkeel_chars[i])
66
+
67
+ letter_n_tashkeel_pairs = []
68
+ for i in range(len(text_with_tashkeel)): # go over the whole text
69
+ # check if the first character is a normal letter and the second character is a tashkeel
70
+ if i < (len(text_with_tashkeel) - 1) and not text_with_tashkeel[i] in self.tashkeel_list and text_with_tashkeel[i+1] in self.tashkeel_list:
71
+ # IMPORTANT: check if tashkeel is Shaddah, then there might be another Tashkeel char associated with it. If so,
72
+ # replace both Shaddah and the Tashkeel chars with the appropriate tag
73
+ if text_with_tashkeel[i+1] == '~':
74
+ # IMPORTANT: the following if statement depends on the concept of short circuit!!
75
+ # The first condition checks if there are still more chars before it access position i+2
76
+ # "text_with_tashkeel[i+2]" since it causes "index out of range" exception. Notice that
77
+ # Shaddah here is put in the first position before the Harakah.
78
+ if i+2 < len(text_with_tashkeel) and f'~{text_with_tashkeel[i+2]}' in self.inverse_tags:
79
+ letter_n_tashkeel_pairs.append((text_with_tashkeel[i], self.inverse_tags[f'~{text_with_tashkeel[i+2]}']))
80
+ else:
81
+ # if it is only Shaddah, just add it to the list
82
+ letter_n_tashkeel_pairs.append((text_with_tashkeel[i], '~'))
83
+ else:
84
+ letter_n_tashkeel_pairs.append((text_with_tashkeel[i], text_with_tashkeel[i+1]))
85
+ # if the character at position i is a normal letter and has no Tashkeel, then add
86
+ # it with the tag "self.no_tashkeel_tag"
87
+ # IMPORTANT: this elif block ensures also that there is no two or more consecutive tashkeel other than shaddah
88
+ elif not text_with_tashkeel[i] in self.tashkeel_list:
89
+ letter_n_tashkeel_pairs.append((text_with_tashkeel[i], self.no_tashkeel_tag))
90
+
91
+ if test_match:
92
+ # test if the split is done correctly by ensuring that we can retrieve back the original text
93
+ assert self.check_match(text_with_tashkeel, letter_n_tashkeel_pairs)
94
+ return [('<BOS>', '<BOS>')] + letter_n_tashkeel_pairs + [('<EOS>', '<EOS>')]
95
+
96
+ def combine_tashkeel_with_text(self, letter_n_tashkeel_pairs):
97
+ combined_with_tashkeel = []
98
+ for letter, tashkeel in letter_n_tashkeel_pairs:
99
+ combined_with_tashkeel.append(letter)
100
+ if tashkeel in self.tags:
101
+ combined_with_tashkeel.append(self.tags[tashkeel])
102
+ elif tashkeel != self.no_tashkeel_tag:
103
+ combined_with_tashkeel.append(tashkeel)
104
+ text = ''.join(combined_with_tashkeel)
105
+ return text
106
+
107
+ def encode(self, text_with_tashkeel, test_match=True):
108
+ letter_n_tashkeel_pairs = self.split_tashkeel_from_text(text_with_tashkeel, test_match)
109
+ text, tashkeel = zip(*letter_n_tashkeel_pairs)
110
+ input_ids = [self.letters_map[c] for c in text]
111
+ target_ids = [self.tashkeel_map[c] for c in tashkeel]
112
+ return np.array(input_ids, dtype=np.int64), np.array(target_ids, dtype=np.int64)
113
+
114
+ def filter_tashkeel(self, tashkeel):
115
+ tmp = []
116
+ for i, t in enumerate(tashkeel):
117
+ if i != 0 and t == '<BOS>':
118
+ t = self.no_tashkeel_tag
119
+ elif i != (len(tashkeel) - 1) and t == '<EOS>':
120
+ t = self.no_tashkeel_tag
121
+ tmp.append(t)
122
+ tashkeel = tmp
123
+ return tashkeel
124
+
125
+ def decode(self, input_ids, target_ids):
126
+ ar_texts = []
127
+ for j in range(len(input_ids)):
128
+ letters = [self.letters[i] for i in input_ids[j]]
129
+ tashkeel = [self.tashkeel_list[i] for i in target_ids[j]]
130
+
131
+ letters = list(filter(lambda x: x != '<BOS>' and x != '<EOS>' and x != '<PAD>', letters))
132
+ tashkeel = self.filter_tashkeel(tashkeel)
133
+ tashkeel = list(filter(lambda x: x != '<BOS>' and x != '<EOS>' and x != '<PAD>', tashkeel))
134
+
135
+ # VERY IMPORTANT NOTE: zip takes min(len(letters), len(tashkeel)) and discard the reset of letters / tashkeels
136
+ letter_n_tashkeel_pairs = list(zip(letters, tashkeel))
137
+ bw_text = self.combine_tashkeel_with_text(letter_n_tashkeel_pairs)
138
+ ar_text = bw2ar.transliterate_text(bw_text, 'bw2ar')
139
+ ar_texts.append(ar_text)
140
+ return ar_texts
141
+
142
+ def get_tashkeel_with_case_ending(self, text, case_ending=True):
143
+ text_split = self.split_tashkeel_from_text(text, test_match=False)
144
+ text_spaces_indecies = [i for i, el in enumerate(text_split) if el == (' ', '<NT>')]
145
+ new_text_split = []
146
+ for i, el in enumerate(text_split):
147
+ if not case_ending and (i+1) in text_spaces_indecies:
148
+ el = (el[0], '<NT>') # no case ending
149
+ new_text_split.append(el)
150
+ letters, tashkeel = zip(*new_text_split)
151
+ return letters, tashkeel
152
+
153
+ def remove_tashkeel(self, text):
154
+ text = HARAKAT_PAT.sub('', text)
155
+ text = re.sub(u"[\u064E]", "", text, flags=re.UNICODE) # fattha
156
+ text = re.sub(u"[\u0671]", "", text, flags=re.UNICODE) # waSla
157
+ return text
158
+