arrandi commited on
Commit
050d880
·
verified ·
1 Parent(s): 5460b8d

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -47,3 +47,6 @@ sample_maider_pozik.wav filter=lfs diff=lfs merge=lfs -text
47
  sample_maider_triste.wav filter=lfs diff=lfs merge=lfs -text
48
  step_4000000.t7 filter=lfs diff=lfs merge=lfs -text
49
  step_3580000.t7 filter=lfs diff=lfs merge=lfs -text
 
 
 
 
47
  sample_maider_triste.wav filter=lfs diff=lfs merge=lfs -text
48
  step_4000000.t7 filter=lfs diff=lfs merge=lfs -text
49
  step_3580000.t7 filter=lfs diff=lfs merge=lfs -text
50
+ phonemizer/dict/es_dicc.dic filter=lfs diff=lfs merge=lfs -text
51
+ phonemizer/dict/eu_dicc.dic filter=lfs diff=lfs merge=lfs -text
52
+ phonemizer/modulo1y2/modulo1y2 filter=lfs diff=lfs merge=lfs -text
phonemizer/__pycache__/eu_phonemizer.cpython-310.pyc ADDED
Binary file (8.14 kB). View file
 
phonemizer/__pycache__/eu_phonemizer.cpython-312.pyc ADDED
Binary file (13.1 kB). View file
 
phonemizer/__pycache__/eu_phonemizer_v2.cpython-310.pyc ADDED
Binary file (8.14 kB). View file
 
phonemizer/__pycache__/eu_phonemizer_v2.cpython-312.pyc ADDED
Binary file (13.1 kB). View file
 
phonemizer/__pycache__/eu_phonemizer_v2.cpython-38.pyc ADDED
Binary file (8.45 kB). View file
 
phonemizer/dict/es_dicc.dic ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b1d78dc48e875858e7b65fc3df2a4ddb592bd165d1280e7c17478726cd42062f
3
+ size 124518
phonemizer/dict/eu_dicc.dic ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4a4c6553965ac7c7937b599d3e8a3d8d94df48a0bdef943a84c63f4b261172f8
3
+ size 865575
phonemizer/eu_phonemizer.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import logging
3
+ import string
4
+ from pathlib import Path
5
+ from collections import OrderedDict
6
+ from nltk.tokenize import TweetTokenizer
7
+ from typing import List, Dict, Optional
8
+ import re
9
+
10
+ # Constants
11
+ SUPPORTED_LANGUAGES = {'eu', 'es'}
12
+ SUPPORTED_SYMBOLS = {'sampa', 'ipa'}
13
+ SAMPA_TO_IPA = OrderedDict([
14
+ ("p", "p"), ("b", "b"), ("t", "t"), ("c", "c"), ("d", "d"),
15
+ ("k", "k"), ("g", "ɡ"), ("tS", "tʃ"), ("ts", "ts"), ("ts`", "tʂ"),
16
+ ("gj", "ɟ"), ("jj", "ʝ"), ("f", "f"), ("B", "β"), ("T", "θ"),
17
+ ("D", "ð"), ("s", "s"), ("s`", "ʂ"), ("S", "ʃ"), ("x", "x"),
18
+ ("G", "ɣ"), ("m", "m"), ("n", "n"), ("J", "ɲ"), ("l", "l"),
19
+ ("L", "ʎ"), ("r", "ɾ"), ("rr", "r"), ("j", "j"), ("w", "w"),
20
+ ("i", "i"), ("'i", "'i"), ("e", "e"), ("'e", "'e"), ("a", "a"),
21
+ ("'a", "'a"), ("o", "o"), ("'o", "'o"), ("u", "u"), ("'u", "'u"),
22
+ ("y", "y"), ("Z", "ʒ"), ("h", "h"), ("ph", "pʰ"), ("kh", "kʰ"),
23
+ ("th", "tʰ")
24
+ ])
25
+
26
+ MULTICHAR_TO_SINGLECHAR = {
27
+ "tʃ": "C",
28
+ "ts": "V",
29
+ "tʂ": "P",
30
+ "'i": "I",
31
+ "'e": "E",
32
+ "'a": "A",
33
+ "'o": "O",
34
+ "'u": "U",
35
+ "pʰ": "H",
36
+ "kʰ": "K",
37
+ "tʰ": "T"
38
+ }
39
+
40
+ class PhonemizerError(Exception):
41
+ """Custom exception for Phonemizer errors."""
42
+ pass
43
+
44
+ class Phonemizer:
45
+ def __init__(self, language: str = "eu", symbol: str = "sampa",
46
+ path_modulo1y2: str = "modulo1y2/modulo1y2",
47
+ path_dicts: str = "dict") -> None:
48
+ """Initialize the Phonemizer with the given language and symbol."""
49
+ if language not in SUPPORTED_LANGUAGES:
50
+ raise PhonemizerError(f"Unsupported language: {language}")
51
+ if symbol not in SUPPORTED_SYMBOLS:
52
+ raise PhonemizerError(f"Unsupported symbol type: {symbol}")
53
+
54
+ self.language = language
55
+ self.symbol = symbol
56
+ self.path_modulo1y2 = Path(path_modulo1y2)
57
+ self.path_dicts = Path(path_dicts)
58
+ self.logger = logging.getLogger(__name__)
59
+
60
+ # Initialize SAMPA to IPA dictionary
61
+ self._sampa_to_ipa_dict = SAMPA_TO_IPA
62
+
63
+ # Initialize word splitter regex
64
+ self._word_splitter = re.compile(r'\w+|[^\w\s]', re.UNICODE)
65
+
66
+ self._validate_paths()
67
+
68
+ def normalize(self, text: str) -> str:
69
+ """Normalize the given text using an external command."""
70
+ try:
71
+ command = self._build_normalization_command()
72
+ process = subprocess.Popen(
73
+ command,
74
+ stdin=subprocess.PIPE,
75
+ stdout=subprocess.PIPE,
76
+ stderr=subprocess.PIPE,
77
+ text=True,
78
+ encoding='ISO-8859-15',
79
+ shell=True
80
+ )
81
+ stdout, stderr = process.communicate(input=text)
82
+
83
+ if process.returncode != 0:
84
+ # Filter out the SetDur warning from the error message
85
+ filtered_stderr = '\n'.join(line for line in stderr.split('\n')
86
+ if 'Warning: argument not used SetDur' not in line)
87
+ if filtered_stderr.strip(): # Only raise error if there are other errors
88
+ error_msg = f"Normalization failed: {filtered_stderr}"
89
+ self.logger.error(error_msg)
90
+ raise PhonemizerError(error_msg)
91
+
92
+ return stdout.strip()
93
+
94
+ except Exception as e:
95
+ error_msg = f"Error during normalization: {str(e)}"
96
+ self.logger.error(error_msg)
97
+ return text
98
+
99
+ def getPhonemes(self, text: str, use_single_char: bool = False) -> str:
100
+ """Extract phonemes from the given text.
101
+
102
+ Args:
103
+ text (str): The input text to convert to phonemes
104
+ use_single_char (bool): If True, converts multi-character IPA phonemes to single characters
105
+ and joins them without spaces. If False, keeps phonemes separated by spaces.
106
+ Only applies when symbol="ipa". Defaults to False.
107
+
108
+ Returns:
109
+ str: The phoneme sequence with words separated by " | "
110
+ """
111
+ try:
112
+ # Pre-process text to handle dots consistently
113
+ # Replace multiple dots with a single dot to avoid issues with ellipsis
114
+ text = re.sub(r'\.{2,}', '.', text)
115
+
116
+ command = self._build_phoneme_extraction_command()
117
+ process = subprocess.Popen(
118
+ command,
119
+ stdin=subprocess.PIPE,
120
+ stdout=subprocess.PIPE,
121
+ stderr=subprocess.PIPE,
122
+ text=True,
123
+ encoding='ISO-8859-15',
124
+ shell=True
125
+ )
126
+
127
+ stdout, stderr = process.communicate(input=text)
128
+
129
+ if process.returncode != 0:
130
+ error_msg = f"Phoneme extraction failed: {stderr}"
131
+ self.logger.error(error_msg)
132
+ raise PhonemizerError(error_msg)
133
+
134
+ # Handle newlines in the raw phonemes output
135
+ # Replace newlines with underscores, similar to how other punctuation is handled
136
+ stdout = stdout.replace('\n', ' | _ | ')
137
+
138
+ # Get words and punctuation from normalized text
139
+ words = self._word_splitter.findall(text)
140
+
141
+ # Split into words and handle each separately
142
+ word_phonemes = stdout.split(" | ")
143
+ result_phonemes = []
144
+
145
+ # Clean and prepare phoneme sequences
146
+ cleaned_phonemes = []
147
+ for phoneme_seq in word_phonemes:
148
+ if not phoneme_seq.strip():
149
+ continue
150
+ # Remove underscores and clean up the sequence
151
+ if phoneme_seq.strip() == "_":
152
+ continue
153
+ cleaned_phonemes.append(phoneme_seq.strip())
154
+
155
+ # Count non-punctuation words and punctuation marks separately
156
+ non_punct_words = [w for w in words if w not in string.punctuation]
157
+ punct_marks = [w for w in words if w in string.punctuation]
158
+
159
+ # Ensure we have enough phonemes for all non-punctuation words
160
+ if len(cleaned_phonemes) < len(non_punct_words):
161
+ # If not, duplicate the last phoneme
162
+ while len(cleaned_phonemes) < len(non_punct_words):
163
+ if cleaned_phonemes:
164
+ cleaned_phonemes.append(cleaned_phonemes[-1])
165
+ else:
166
+ # If no phonemes at all, add a placeholder
167
+ cleaned_phonemes.append("a")
168
+
169
+ # Process words and phonemes together
170
+ phoneme_idx = 0
171
+ word_idx = 0
172
+
173
+ while word_idx < len(words):
174
+ word = words[word_idx]
175
+
176
+ if word in string.punctuation:
177
+ # Add punctuation mark directly
178
+ result_phonemes.append(word)
179
+ word_idx += 1
180
+ else:
181
+ # Process regular word
182
+ if phoneme_idx < len(cleaned_phonemes):
183
+ phonemes = cleaned_phonemes[phoneme_idx].split()
184
+ if self.symbol == "sampa":
185
+ # For SAMPA, join and remove hyphens
186
+ processed_phonemes = " ".join(p for p in phonemes if p != "-")
187
+ else:
188
+ # For IPA, convert and remove hyphens
189
+ ipa_phonemes = [self._sampa_to_ipa_dict.get(p, p) for p in phonemes if p != "-"]
190
+ processed_phonemes = " ".join(ipa_phonemes)
191
+ if use_single_char:
192
+ processed_phonemes = self._transform_multichar_phonemes(processed_phonemes)
193
+ # Join phonemes when use_single_char is True
194
+ processed_phonemes = processed_phonemes.replace(" ", "")
195
+
196
+ result_phonemes.append(processed_phonemes)
197
+ phoneme_idx += 1
198
+ word_idx += 1
199
+ else:
200
+ # If we run out of phonemes but still have words, skip the word
201
+ word_idx += 1
202
+
203
+ # If we have more phonemes than words, add them as is
204
+ while phoneme_idx < len(cleaned_phonemes):
205
+ phonemes = cleaned_phonemes[phoneme_idx].split()
206
+ if self.symbol == "sampa":
207
+ processed_phonemes = " ".join(p for p in phonemes if p != "-")
208
+ else:
209
+ ipa_phonemes = [self._sampa_to_ipa_dict.get(p, p) for p in phonemes if p != "-"]
210
+ processed_phonemes = " ".join(ipa_phonemes)
211
+ if use_single_char:
212
+ processed_phonemes = self._transform_multichar_phonemes(processed_phonemes)
213
+ # Join phonemes when use_single_char is True
214
+ processed_phonemes = processed_phonemes.replace(" ", "")
215
+
216
+ result_phonemes.append(processed_phonemes)
217
+ phoneme_idx += 1
218
+
219
+ return " | ".join(result_phonemes)
220
+
221
+ except Exception as e:
222
+ error_msg = f"Error in phoneme extraction: {str(e)}"
223
+ self.logger.error(error_msg)
224
+ return ""
225
+
226
+ def _build_normalization_command(self) -> str:
227
+ """Build the command string for normalization."""
228
+ modulo_path = self._get_file_path() / self.path_modulo1y2
229
+ dict_path = self._get_file_path() / self.path_dicts
230
+ dict_file = f"{self.language}_dicc"
231
+ return f'{modulo_path} -TxtMode=Word -Lang={self.language} -HDic={dict_path/dict_file}'
232
+
233
+ def _build_phoneme_extraction_command(self) -> str:
234
+ """Build the command string for phoneme extraction."""
235
+ modulo_path = self._get_file_path() / self.path_modulo1y2
236
+ dict_path = self._get_file_path() / self.path_dicts
237
+ dict_file = f"{self.language}_dicc"
238
+ return f'{modulo_path} -Lang={self.language} -HDic={dict_path/dict_file}'
239
+
240
+ def _get_file_path(self) -> Path:
241
+ return Path(__file__).parent
242
+
243
+ def _validate_paths(self) -> None:
244
+ """Validate paths with enhanced error reporting."""
245
+ try:
246
+ if not self.path_modulo1y2.exists():
247
+ raise PhonemizerError(f"Modulo1y2 executable not found at: {self.path_modulo1y2}")
248
+ if not self.path_dicts.exists():
249
+ raise PhonemizerError(f"Dictionary directory not found at: {self.path_dicts}")
250
+
251
+ # Check for both possible dictionary files
252
+ dict_file = self.path_dicts / f"{self.language}_dicc"
253
+ if not dict_file.exists():
254
+ # Try with .dic extension as fallback
255
+ dict_file_alt = self.path_dicts / f"{self.language}_dicc.dic"
256
+ if not dict_file_alt.exists():
257
+ raise PhonemizerError(f"Dictionary file not found at either {dict_file} or {dict_file_alt}")
258
+
259
+ except Exception as e:
260
+ self.logger.error(f"Path validation error: {str(e)}")
261
+ raise
262
+
263
+ def _transform_multichar_phonemes(self, phoneme_sequence: str) -> str:
264
+ """
265
+ Transform multicharacter IPA phonemes to single characters using the MULTICHAR_TO_SINGLECHAR mapping.
266
+
267
+ Args:
268
+ phoneme_sequence (str): A string containing phonemes separated by spaces
269
+
270
+ Returns:
271
+ str: The transformed phoneme sequence with multicharacter phonemes replaced by single characters
272
+ """
273
+ # Split the sequence into individual phonemes
274
+ phonemes = phoneme_sequence.split()
275
+ transformed_phonemes = []
276
+
277
+ for phoneme in phonemes:
278
+ # Check if the phoneme exists in our mapping
279
+ if phoneme in MULTICHAR_TO_SINGLECHAR:
280
+ transformed_phonemes.append(MULTICHAR_TO_SINGLECHAR[phoneme])
281
+ else:
282
+ transformed_phonemes.append(phoneme)
283
+
284
+ return " ".join(transformed_phonemes)
285
+
286
+
phonemizer/modulo1y2/modulo1y2 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c122bd6197e5e360d534957322f8d98a06cb3bcb4d412ee9978e891ae1b43e8a
3
+ size 2245952