Spaces:
Running on Zero
Running on Zero
Download tools/maps/utils.py from Tom-Brenner/PhonePaint: direct link, hf CLI and curl.
- Browser
- Download file 3.58 kB
-
https://huggingface.co/spaces/Tom-Brenner/PhonePaint/resolve/main/tools/maps/utils.py
- Command line
-
hf download hf://spaces/Tom-Brenner/PhonePaint/tools/maps/utils.py
-
curl -L -o utils.py https://huggingface.co/spaces/Tom-Brenner/PhonePaint/resolve/main/tools/maps/utils.py
3.58 kB
| import numpy as np | |
| import re | |
| _FOLDINGS = { | |
| 'AO': 'AA', | |
| 'AX': 'AH', | |
| 'AX-H': 'AH', | |
| 'AXR': 'ER', | |
| 'HV': 'HH', | |
| 'IX': 'IH', | |
| 'EL': 'L', | |
| 'EM': 'M', | |
| 'EN': 'N', | |
| 'NX': 'N', | |
| 'ENG': 'NG', | |
| 'PCL': 'P', | |
| 'TCL': 'T', | |
| 'KCL': 'K', | |
| 'BCL': 'B', | |
| 'DCL': 'D', | |
| 'GCL': 'G', | |
| 'H#': 'SIL', | |
| 'PAU': 'SIL', | |
| 'EPI': 'SIL', | |
| 'UX': 'UW' | |
| } | |
| def align(seq, probs): | |
| def distance(r, c): | |
| category = seq[r] | |
| timestep = c | |
| return probs[timestep, category] | |
| nrow = len(seq) | |
| ncol = probs.shape[0] # time steps | |
| M = warp(range(nrow), range(ncol), distance) | |
| alignment = traceback(M[1:, 1:], seq) | |
| return alignment, M[1:, 1:] | |
| def warp(S, T, d): | |
| nrow = len(S) | |
| ncol = len(T) | |
| M = np.full((nrow+1, ncol+1), np.inf) | |
| M[0, 0] = 0 | |
| # Some optimization is being left on the table; this should be computable | |
| # for a whole column at a time | |
| for r in range(1, nrow+1): | |
| for c in range(1, ncol+1): | |
| # need -1 offset for cost because of extra first row | |
| # and first column in M that isn't present in the | |
| # `probs` matrix | |
| cost = d(r-1, c-1) | |
| M[r, c] = cost + min(M[r, c-1], M[r-1, c-1]) | |
| return M | |
| def traceback(M, sequence): | |
| nrow, ncol = M.shape | |
| seq = [nrow-1] | |
| r = nrow-1 | |
| c = ncol-1 | |
| curr_prob = M[r, c] | |
| while c >= 0: | |
| if r == 0: | |
| seq += [0 for x in range(ncol - len(seq))] | |
| break | |
| if M[r-1, c-1] > M[r, c-1]: | |
| seq.append(r) | |
| c -= 1 | |
| else: | |
| c -= 1 | |
| r -= 1 | |
| seq.append(r) | |
| rs = seq[::-1] | |
| rs = [sequence[r] for r in rs] | |
| return rs | |
| def collapse(s): | |
| a = [s[0]] | |
| for symbol in s[1:]: | |
| if a[-1] != symbol: | |
| a.append(symbol) | |
| return a | |
| def fold_phone(p): | |
| stress_mark = re.findall(r'\d+', p) | |
| if stress_mark: | |
| stress_mark = stress_mark[0] | |
| else: | |
| stress_mark = '' | |
| phone_label = re.sub(r'\d', '', p) | |
| if phone_label in _FOLDINGS: | |
| phone_label = _FOLDINGS[phone_label] | |
| return phone_label + stress_mark | |
| def load_dictionary(dname, cmuformat=True): | |
| mapping = dict() | |
| if cmuformat: | |
| with open(dname, 'r') as d: | |
| for line in d: | |
| line = line.strip() | |
| if not line or line.startswith(';;;'): | |
| continue | |
| all_items = line.split() | |
| if len(all_items) < 2: | |
| continue | |
| word = all_items[0] | |
| word = re.sub(r'\(\d*\)', '', word) | |
| # NLTK cmudict uses ``WORD <variant_index> PHONE ...``; skip the index. | |
| pron_start = 2 if len(all_items) >= 3 and all_items[1].isdigit() else 1 | |
| pronunciation = all_items[pron_start:] | |
| pronunciation = [fold_phone(p) for p in pronunciation] | |
| if not pronunciation: | |
| continue | |
| if word not in mapping: | |
| mapping[word] = [pronunciation] | |
| else: | |
| mapping[word].append(pronunciation) | |
| mapping['sil'] = [['H#'], []] | |
| return mapping | |
| else: | |
| print('Custom dictionary formats not supported yet. Please format use CMU dict formatting and run again.') | |
| sys.exit(1) | |