namkuner commited on
Commit
ddd337d
1 Parent(s): d29da97

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +2 -1
  2. .idea/.gitignore +8 -0
  3. .idea/Generate Audio Data.iml +10 -0
  4. .idea/inspectionProfiles/Project_Default.xml +40 -0
  5. .idea/inspectionProfiles/profiles_settings.xml +6 -0
  6. .idea/misc.xml +7 -0
  7. .idea/modules.xml +8 -0
  8. .idea/vcs.xml +6 -0
  9. .idea/workspace.xml +98 -0
  10. __pycache__/gemini_normalize.cpython-310.pyc +0 -0
  11. __pycache__/text_nomalize.cpython-310.pyc +0 -0
  12. converters/Cardinal.py +189 -0
  13. converters/Date.py +107 -0
  14. converters/Decimal.py +86 -0
  15. converters/Digit.py +62 -0
  16. converters/Fraction.py +110 -0
  17. converters/Meansure.py +473 -0
  18. converters/Money.py +155 -0
  19. converters/Ordinal.py +74 -0
  20. converters/Range.py +36 -0
  21. converters/Roman.py +88 -0
  22. converters/Telephone.py +90 -0
  23. converters/Time.py +100 -0
  24. converters/__init__.py +0 -0
  25. converters/__pycache__/Cardinal.cpython-310.pyc +0 -0
  26. converters/__pycache__/Date.cpython-310.pyc +0 -0
  27. converters/__pycache__/Decimal.cpython-310.pyc +0 -0
  28. converters/__pycache__/Digit.cpython-310.pyc +0 -0
  29. converters/__pycache__/Fraction.cpython-310.pyc +0 -0
  30. converters/__pycache__/Meansure.cpython-310.pyc +0 -0
  31. converters/__pycache__/Money.cpython-310.pyc +0 -0
  32. converters/__pycache__/Range.cpython-310.pyc +0 -0
  33. converters/__pycache__/Roman.cpython-310.pyc +0 -0
  34. converters/__pycache__/Telephone.cpython-310.pyc +0 -0
  35. converters/__pycache__/Time.cpython-310.pyc +0 -0
  36. converters/__pycache__/__init__.cpython-310.pyc +0 -0
  37. download.sh +8 -0
  38. train_list.txt +0 -0
  39. val_list.txt +68 -0
  40. whisperx/SubtitlesProcessor.py +227 -0
  41. whisperx/__init__.py +4 -0
  42. whisperx/__main__.py +4 -0
  43. whisperx/__pycache__/__init__.cpython-310.pyc +0 -0
  44. whisperx/__pycache__/alignment.cpython-310.pyc +0 -0
  45. whisperx/__pycache__/asr.cpython-310.pyc +0 -0
  46. whisperx/__pycache__/audio.cpython-310.pyc +0 -0
  47. whisperx/__pycache__/diarize.cpython-310.pyc +0 -0
  48. whisperx/__pycache__/transcribe.cpython-310.pyc +0 -0
  49. whisperx/__pycache__/types.cpython-310.pyc +0 -0
  50. whisperx/__pycache__/utils.cpython-310.pyc +0 -0
.gitignore CHANGED
@@ -2,4 +2,5 @@
2
  downloaded_audio/
3
  figures/
4
  audio_cut/
5
- audio_cut.zip
 
 
2
  downloaded_audio/
3
  figures/
4
  audio_cut/
5
+ audio_cut.zip
6
+ dataset/
.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
.idea/Generate Audio Data.iml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
+ </content>
7
+ <orderEntry type="jdk" jdkName="Python 3.10 (Explanation)" jdkType="Python SDK" />
8
+ <orderEntry type="sourceFolder" forTests="false" />
9
+ </component>
10
+ </module>
.idea/inspectionProfiles/Project_Default.xml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
6
+ <option name="ignoredPackages">
7
+ <value>
8
+ <list size="26">
9
+ <item index="0" class="java.lang.String" itemvalue="torch" />
10
+ <item index="1" class="java.lang.String" itemvalue="torchvision" />
11
+ <item index="2" class="java.lang.String" itemvalue="timm" />
12
+ <item index="3" class="java.lang.String" itemvalue="ellzaf_ml" />
13
+ <item index="4" class="java.lang.String" itemvalue="scipy" />
14
+ <item index="5" class="java.lang.String" itemvalue="scikit_learn" />
15
+ <item index="6" class="java.lang.String" itemvalue="matplotlib" />
16
+ <item index="7" class="java.lang.String" itemvalue="opencv_contrib_python" />
17
+ <item index="8" class="java.lang.String" itemvalue="model" />
18
+ <item index="9" class="java.lang.String" itemvalue="opencv_python" />
19
+ <item index="10" class="java.lang.String" itemvalue="Pillow" />
20
+ <item index="11" class="java.lang.String" itemvalue="pydriver" />
21
+ <item index="12" class="java.lang.String" itemvalue="pytest-pylint" />
22
+ <item index="13" class="java.lang.String" itemvalue="opencv-python" />
23
+ <item index="14" class="java.lang.String" itemvalue="pytest" />
24
+ <item index="15" class="java.lang.String" itemvalue="sklearn" />
25
+ <item index="16" class="java.lang.String" itemvalue="attrdict" />
26
+ <item index="17" class="java.lang.String" itemvalue="numpy" />
27
+ <item index="18" class="java.lang.String" itemvalue="albumentations" />
28
+ <item index="19" class="java.lang.String" itemvalue="pandas" />
29
+ <item index="20" class="java.lang.String" itemvalue="tqdm" />
30
+ <item index="21" class="java.lang.String" itemvalue="tensorboard" />
31
+ <item index="22" class="java.lang.String" itemvalue="pylint" />
32
+ <item index="23" class="java.lang.String" itemvalue="onnx" />
33
+ <item index="24" class="java.lang.String" itemvalue="opencv_python_headless" />
34
+ <item index="25" class="java.lang.String" itemvalue="PyQt5" />
35
+ </list>
36
+ </value>
37
+ </option>
38
+ </inspection_tool>
39
+ </profile>
40
+ </component>
.idea/inspectionProfiles/profiles_settings.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
.idea/misc.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="Python 3.10 (Explanation)" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (Explanation)" project-jdk-type="Python SDK" />
7
+ </project>
.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/Generate Audio Data.iml" filepath="$PROJECT_DIR$/.idea/Generate Audio Data.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
.idea/workspace.xml ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="ChangeListManager">
7
+ <list default="true" id="6348f10b-d99d-4a46-ac7b-9eed28d7fa2a" name="Changes" comment="" />
8
+ <option name="SHOW_DIALOG" value="false" />
9
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
10
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
11
+ <option name="LAST_RESOLUTION" value="IGNORE" />
12
+ </component>
13
+ <component name="FileTemplateManagerImpl">
14
+ <option name="RECENT_TEMPLATES">
15
+ <list>
16
+ <option value="Python Script" />
17
+ </list>
18
+ </option>
19
+ </component>
20
+ <component name="Git.Settings">
21
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
22
+ </component>
23
+ <component name="ProjectColorInfo">{
24
+ &quot;associatedIndex&quot;: 6
25
+ }</component>
26
+ <component name="ProjectId" id="2mZJfy2ux2nxKThwMyI4nltiFiJ" />
27
+ <component name="ProjectViewState">
28
+ <option name="hideEmptyMiddlePackages" value="true" />
29
+ <option name="showLibraryContents" value="true" />
30
+ </component>
31
+ <component name="PropertiesComponent"><![CDATA[{
32
+ "keyToString": {
33
+ "Python.download_audio.executor": "Run",
34
+ "Python.gen_dataset.executor": "Run",
35
+ "Python.main.executor": "Run",
36
+ "Python.separate.executor": "Run",
37
+ "Python.test_dataset.executor": "Run",
38
+ "Python.upload_huggingface.executor": "Run",
39
+ "RunOnceActivity.ShowReadmeOnStart": "true",
40
+ "git-widget-placeholder": "master",
41
+ "last_opened_file_path": "E:/AI/Generate Audio Data",
42
+ "node.js.detected.package.eslint": "true",
43
+ "node.js.detected.package.tslint": "true",
44
+ "node.js.selected.package.eslint": "(autodetect)",
45
+ "node.js.selected.package.tslint": "(autodetect)",
46
+ "nodejs_package_manager_path": "npm",
47
+ "settings.editor.selected.configurable": "project.propVCSSupport.DirectoryMappings",
48
+ "vue.rearranger.settings.migration": "true"
49
+ }
50
+ }]]></component>
51
+ <component name="RecentsManager">
52
+ <key name="CopyFile.RECENT_KEYS">
53
+ <recent name="E:\AI\Generate Audio Data" />
54
+ <recent name="E:\AI\Generate Audio Data\dataset" />
55
+ </key>
56
+ </component>
57
+ <component name="SharedIndexes">
58
+ <attachedChunks>
59
+ <set>
60
+ <option value="bundled-js-predefined-1d06a55b98c1-91d5c284f522-JavaScript-PY-241.15989.155" />
61
+ <option value="bundled-python-sdk-babbdf50b680-7c6932dee5e4-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-241.15989.155" />
62
+ </set>
63
+ </attachedChunks>
64
+ </component>
65
+ <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
66
+ <component name="TaskManager">
67
+ <task active="true" id="Default" summary="Default task">
68
+ <changelist id="6348f10b-d99d-4a46-ac7b-9eed28d7fa2a" name="Changes" comment="" />
69
+ <created>1727278271929</created>
70
+ <option name="number" value="Default" />
71
+ <option name="presentableId" value="Default" />
72
+ <updated>1727278271929</updated>
73
+ <workItem from="1727278276767" duration="149000" />
74
+ <workItem from="1727309175324" duration="14258000" />
75
+ <workItem from="1727340993328" duration="20898000" />
76
+ <workItem from="1727430990250" duration="574000" />
77
+ <workItem from="1727528882113" duration="16350000" />
78
+ <workItem from="1727755697813" duration="11670000" />
79
+ <workItem from="1727846631606" duration="10850000" />
80
+ <workItem from="1727864061128" duration="1144000" />
81
+ <workItem from="1727865356249" duration="3690000" />
82
+ <workItem from="1727870630865" duration="7260000" />
83
+ <workItem from="1727879789158" duration="302000" />
84
+ </task>
85
+ <servers />
86
+ </component>
87
+ <component name="TypeScriptGeneratedFilesManager">
88
+ <option name="version" value="3" />
89
+ </component>
90
+ <component name="com.intellij.coverage.CoverageDataManagerImpl">
91
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$gen_dataset.coverage" NAME="gen_dataset Coverage Results" MODIFIED="1727855498024" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
92
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$download_audio.coverage" NAME="download_audio Coverage Results" MODIFIED="1727855814027" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
93
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$separate.coverage" NAME="separate Coverage Results" MODIFIED="1727772728510" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
94
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$main.coverage" NAME="main Coverage Results" MODIFIED="1727532107608" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
95
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$test_dataset.coverage" NAME="test_dataset Coverage Results" MODIFIED="1727356745919" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
96
+ <SUITE FILE_PATH="coverage/Generate_Audio_Data$upload_huggingface.coverage" NAME="upload_huggingface Coverage Results" MODIFIED="1727878833042" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
97
+ </component>
98
+ </project>
__pycache__/gemini_normalize.cpython-310.pyc ADDED
Binary file (9.31 kB). View file
 
__pycache__/text_nomalize.cpython-310.pyc ADDED
Binary file (3.83 kB). View file
 
converters/Cardinal.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+
3
+ from singleton_decorator import singleton
4
+ import re
5
+ from .Roman import RomanVietnamese
6
+
7
+
8
+ @singleton
9
+ class CardinalVietnamese:
10
+ """
11
+ Các bước:
12
+ - 1 Loại bỏ dấu chấm
13
+ - 2 Kiểm tra xem có phải là số La Mã không
14
+ - 3 Nếu đúng, chuyển đổi số La Mã lớn nhất tìm thấy thành số nguyên, sau đó thành chuỗi đại diện cho số nguyên đó
15
+ - 4 Nếu đúng, kiểm tra xem có nên thêm hậu tố "'s" không (xem trường hợp đặc biệt)
16
+ - 5 Lọc bỏ các ký tự không phải số, trừ "-"
17
+ - 6 Kiểm tra xem có nên sử dụng tiền tố "âm" không
18
+ - 7 Loại bỏ tất cả các ký tự "-" còn lại
19
+ - 8 Nếu là "0", thêm "không" vào danh sách đầu ra
20
+ - 9 Nếu không phải "0", chia chuỗi thành các phần tối đa 3 chữ số, sao cho phần nhỏ nhất bao gồm các ký tự ngoài cùng bên trái
21
+ - 10 Chia mỗi phần thành `trăm` và `phần còn lại`
22
+ - 11 Thêm "x trăm" nếu `trăm` > 0
23
+ - 12 Thêm giá trị văn bản đại diện cho `phần còn lại`
24
+ - 13 Thêm hậu tố cho phần, ví dụ: triệu, tỷ, v.v.
25
+ - 14 Thêm đầu ra cho phần vào tổng đầu ra
26
+ - 15 Kết hợp danh sách đầu ra tổng thành một chuỗi
27
+ - 16 Thêm tiền tố và/hoặc hậu tố
28
+
29
+ Trường hợp đặc biệt:
30
+ II -> hai
31
+ -2 -> âm hai
32
+ I. -> một
33
+ IV's -> bốn's
34
+
35
+ Ghi chú:
36
+ - Không có "và" hoặc dấu gạch ngang trong kết quả, ví dụ: không có "hai mươi mốt" hoặc "một trăm lẻ một"
37
+ """
38
+
39
+ def __init__(self):
40
+ super().__init__()
41
+ self.filter_regex = re.compile("[^0-9\-]")
42
+ self.filter_strict_regex = re.compile("[^0-9]")
43
+ self.dot_filter_regex = re.compile("[.]")
44
+
45
+ self.scale_suffixes = [
46
+ "nghìn",
47
+ "triệu",
48
+ "tỷ",
49
+ "nghìn tỷ",
50
+ "triệu tỷ",
51
+ "tỷ tỷ"
52
+ ]
53
+
54
+ self.small_trans_dict = {
55
+ "1": "một",
56
+ "2": "hai",
57
+ "3": "ba",
58
+ "4": "bốn",
59
+ "5": "năm",
60
+ "6": "sáu",
61
+ "7": "bảy",
62
+ "8": "tám",
63
+ "9": "chín",
64
+ }
65
+
66
+ self.tens_trans_dict = {
67
+ "1": "mười",
68
+ "2": "hai mươi",
69
+ "3": "ba mươi",
70
+ "4": "bốn mươi",
71
+ "5": "năm mươi",
72
+ "6": "sáu mươi",
73
+ "7": "bảy mươi",
74
+ "8": "tám mươi",
75
+ "9": "chín mươi",
76
+ }
77
+
78
+ self.special_trans_dict = {
79
+ 11: "mười một",
80
+ 12: "mười hai",
81
+ 13: "mười ba",
82
+ 14: "mười bốn",
83
+ 15: "mười lăm",
84
+ 16: "mười sáu",
85
+ 17: "mười bảy",
86
+ 18: "mười tám",
87
+ 19: "mười chín"
88
+ }
89
+
90
+ self.roman = RomanVietnamese()
91
+
92
+ def _give_chunk(self, num_str: str, size: int = 3) -> str:
93
+ while num_str:
94
+ yield num_str[-size:]
95
+ num_str = num_str[:-size]
96
+
97
+ def convert(self, token: str) -> str:
98
+ token = self.dot_filter_regex.sub("", token)
99
+
100
+ suffix = ""
101
+ if self.roman.check_if_roman(token):
102
+ token, suffix = self.roman.convert(token)
103
+
104
+ token = self.filter_regex.sub("", token)
105
+
106
+ prefix = ""
107
+ while len(token) > 0 and token[0] == "-":
108
+ token = token[1:]
109
+ prefix = "âm" if prefix == "" else ""
110
+
111
+ token = self.filter_strict_regex.sub("", token)
112
+
113
+ if token == len(token) * "0":
114
+ return "không"
115
+
116
+ chunks = list(self._give_chunk(token))
117
+ text_list = []
118
+
119
+ for depth, chunk in enumerate(chunks):
120
+ chunk_text = self._convert_chunk(chunk, depth == len(chunks) - 1)
121
+ if chunk_text:
122
+ if depth > 0:
123
+ chunk_text.append(self.scale_suffixes[depth - 1])
124
+ text_list = chunk_text + text_list
125
+
126
+ result = " ".join(text_list)
127
+
128
+ if prefix:
129
+ result = f"{prefix} {result}"
130
+ if suffix:
131
+ result = f"{result}{suffix}"
132
+
133
+ return result
134
+
135
+ def _convert_chunk(self, chunk: str, is_last_chunk: bool) -> List[str]:
136
+ chunk_text = []
137
+ length = len(chunk)
138
+
139
+ # Xử lý hàng trăm
140
+ if length == 3:
141
+ if chunk[0] != '0':
142
+ chunk_text.append(self.small_trans_dict[chunk[0]])
143
+ chunk_text.append("trăm")
144
+ elif not is_last_chunk and (chunk[1] != '0' or chunk[2] != '0'):
145
+ chunk_text.append("không trăm")
146
+
147
+ # Xử lý hàng chục và đơn vị
148
+ if length >= 2:
149
+ if chunk[-2:] in self.special_trans_dict:
150
+ chunk_text.append(self.special_trans_dict[chunk[-2:]])
151
+ else:
152
+ if chunk[-2] != '0':
153
+ chunk_text.append(self.tens_trans_dict[chunk[-2]])
154
+ if chunk[-1] != '0':
155
+ if chunk[-1] == '1' and chunk[-2] != '1':
156
+ chunk_text.append("mốt")
157
+ else:
158
+ chunk_text.append(self.small_trans_dict[chunk[-1]])
159
+ elif chunk[-1] != '0':
160
+ if len(chunk_text) > 0 or not is_last_chunk:
161
+ chunk_text.append("lẻ")
162
+ chunk_text.append(self.small_trans_dict[chunk[-1]])
163
+ elif length == 1 and chunk != '0':
164
+ chunk_text.append(self.small_trans_dict[chunk])
165
+
166
+ return chunk_text
167
+
168
+ if __name__ == "__main__":
169
+ cardinal_converter = CardinalVietnamese()
170
+
171
+ # Ví dụ 1
172
+ example1 = "20211231"
173
+ result1 = cardinal_converter.convert(example1)
174
+ print(f"Số: {example1}")
175
+ print(f"Chuyển đổi: {result1}")
176
+ print()
177
+
178
+ # Ví dụ 2
179
+ example2 = "-5678213"
180
+ result2 = cardinal_converter.convert(example2)
181
+ print(f"Số: {example2}")
182
+ print(f"Chuyển đổi: {result2}")
183
+ print()
184
+
185
+ # Ví dụ 3
186
+ example3 = "1000000"
187
+ result3 = cardinal_converter.convert(example3)
188
+ print(f"Số: {example3}")
189
+ print(f"Chuyển đổi: {result3}")
converters/Date.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from singleton_decorator import singleton
3
+ import re
4
+ from .Cardinal import CardinalVietnamese
5
+ import re
6
+
7
+ @singleton
8
+ class DateVietnamese:
9
+ """
10
+ Chuyển đổi ngày tháng từ dạng số sang dạng chữ tiếng Việt.
11
+ Hỗ trợ các định dạng: "DD/MM/YYYY", "DD-MM-YYYY", "DD.MM.YYYY".
12
+ Ví dụ: "25/12/2023", "01-01-2024", "10.05.2023"
13
+ """
14
+
15
+ def __init__(self):
16
+ self.day_trans_dict = {
17
+ "1": "một",
18
+ "2": "hai",
19
+ "3": "ba",
20
+ "4": "bốn",
21
+ "5": "năm",
22
+ "6": "sáu",
23
+ "7": "bảy",
24
+ "8": "tám",
25
+ "9": "chín",
26
+ "10": "mười",
27
+ "11": "mười một",
28
+ "12": "mười hai",
29
+ "13": "mười ba",
30
+ "14": "mười bốn",
31
+ "15": "mười lăm",
32
+ "16": "mười sáu",
33
+ "17": "mười bảy",
34
+ "18": "mười tám",
35
+ "19": "mười chín",
36
+ "20": "hai mươi",
37
+ "21": "hai mươi mốt",
38
+ "22": "hai mươi hai",
39
+ "23": "hai mươi ba",
40
+ "24": "hai mươi bốn",
41
+ "25": "hai mươi lăm",
42
+ "26": "hai mươi sáu",
43
+ "27": "hai mươi bảy",
44
+ "28": "hai mươi tám",
45
+ "29": "hai mươi chín",
46
+ "30": "ba mươi",
47
+ "31": "ba mươi mốt"
48
+ }
49
+
50
+ self.month_trans_dict = {
51
+ "1": "một",
52
+ "2": "hai",
53
+ "3": "ba",
54
+ "4": "tư",
55
+ "5": "năm",
56
+ "6": "sáu",
57
+ "7": "bảy",
58
+ "8": "tám",
59
+ "9": "chín",
60
+ "10": "mười",
61
+ "11": "mười một",
62
+ "12": "mười hai"
63
+ }
64
+
65
+ def convert_year(self, year: str) -> str:
66
+ cardinal_converter = CardinalVietnamese()
67
+ return cardinal_converter.convert(year)
68
+
69
+ def convert_date(self, date: str) -> str:
70
+ # Tìm và tách ngày, tháng, năm dựa trên dấu phân cách
71
+ date_parts = re.split(r"[\/\-\.\s]", date)
72
+ if len(date_parts) ==3 :
73
+ day, month, year = date_parts[0], date_parts[1], date_parts[2]
74
+
75
+ day_text = f"ngày {self.day_trans_dict[day.lstrip('0')]}"
76
+ month_text = f"tháng {self.month_trans_dict[month.lstrip('0')]}"
77
+ year_text = f"năm {self.convert_year(year)}"
78
+
79
+ return f"{day_text} {month_text} {year_text}"
80
+ else:
81
+ month, year = date_parts[0], date_parts[1],
82
+ month_text = f"tháng {self.month_trans_dict[month.lstrip('0')]}"
83
+ year_text = f"năm {self.convert_year(year)}"
84
+ return f"{month_text} {year_text}"
85
+ if __name__ == "__main__":
86
+ date_converter = DateVietnamese()
87
+
88
+ # Ví dụ 1
89
+ example1 = "25/12/1990"
90
+ result1 = date_converter.convert_date(example1)
91
+ print(f"Ngày tháng: {example1}")
92
+ print(f"Chuyển đổi: {result1}")
93
+ print()
94
+
95
+ # Ví dụ 2
96
+ example2 = "01-01-1991"
97
+ result2 = date_converter.convert_date(example2)
98
+ print(f"Ngày tháng: {example2}")
99
+ print(f"Chuyển đổi: {result2}")
100
+ print()
101
+
102
+ # Ví dụ 3
103
+ example3 = "10.05.2023"
104
+ result3 = date_converter.convert_date(example3)
105
+ print(f"Ngày tháng: {example3}")
106
+ print(f"Chuyển đổi: {result3}")
107
+
converters/Decimal.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .Digit import DigitVietnamese
2
+ from .Cardinal import CardinalVietnamese
3
+ import re
4
+ from singleton_decorator import singleton
5
+ @singleton
6
+ class Decimal:
7
+ def __init__(self):
8
+ super().__init__()
9
+ self.decimal_regex = re.compile(r"(-?\d*)\.(\d+)(.*)")
10
+ self.number_regex = re.compile(r"(-?\d+)(.*)")
11
+ self.filter_regex = re.compile(r"[,]")
12
+ self.cardinal = CardinalVietnamese()
13
+ self.digit = DigitVietnamese()
14
+ self.suffixes = [
15
+ "nghìn",
16
+ "triệu",
17
+ "tỷ",
18
+ "nghìn tỷ",
19
+ "triệu tỷ",
20
+ "tỷ tỷ"
21
+ ]
22
+ self.suffix_regex = re.compile(f" *({'|'.join(self.suffixes)})")
23
+ self.e_suffix_regex = re.compile(r" *E(-?\d+)")
24
+
25
+ def convert(self, token: str) -> str:
26
+ token = self.filter_regex.sub("", token)
27
+
28
+ number = ""
29
+ decimal = ""
30
+
31
+ match = self.decimal_regex.match(token)
32
+ if match:
33
+ number = match.group(1)
34
+ decimal = match.group(2)
35
+ token = match.group(3)
36
+ else:
37
+ match = self.number_regex.match(token)
38
+ if match:
39
+ number = match.group(1)
40
+ token = match.group(2)
41
+
42
+ match = self.suffix_regex.match(token)
43
+ suffix = ""
44
+ if match:
45
+ suffix = match.group(1)
46
+ else:
47
+ match = self.e_suffix_regex.match(token)
48
+ if match:
49
+ suffix = f"nhân mười mũ {self.cardinal.convert(match.group(1))}"
50
+
51
+ result_list = []
52
+ if len(decimal) > 0:
53
+ result_list.append("phẩy")
54
+ result_list.append(self.digit.convert(decimal))
55
+
56
+ if number:
57
+ result_list.insert(0, self.cardinal.convert(number))
58
+
59
+ if suffix:
60
+ result_list.append(suffix)
61
+
62
+ result = " ".join(result_list)
63
+
64
+ return result
65
+
66
+ if __name__ == "__main__":
67
+ decimal = Decimal()
68
+
69
+ test_cases = [
70
+ "123,456.789",
71
+ "0.5",
72
+ "1000000",
73
+ "3.14",
74
+ "2.718E3",
75
+ "1.23E-5",
76
+ "9.99999",
77
+ "1234.5678 tỷ",
78
+ "0.000001",
79
+ "1000000.000001",
80
+ ]
81
+
82
+ for case in test_cases:
83
+ result = decimal.convert(case)
84
+ print(f"Số: {case}")
85
+ print(f"Chuyển đổi: {result}")
86
+ print()
converters/Digit.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+
4
+ @singleton
5
+ class DigitVietnamese:
6
+ """
7
+ Các bước:
8
+ - 1 Lọc bỏ tất cả các ký tự không phải số
9
+ - 2 Kiểm tra trường hợp đặc biệt
10
+ - 3 Chuyển đổi mỗi chữ số thành văn bản tiếng Việt
11
+ - 4 Thêm khoảng trắng giữa các từ
12
+ Trường hợp đặc biệt:
13
+ 007 -> không không bảy
14
+ trong khi 003 -> không không ba
15
+ """
16
+ def __init__(self):
17
+ super().__init__()
18
+ # Regex để lọc bỏ các ký tự không phải số
19
+ self.filter_regex = re.compile("[^0-9]")
20
+ # Từ điển chuyển đổi chữ số sang chữ tiếng Việt
21
+ self.trans_dict = {
22
+ "0": "không",
23
+ "1": "một",
24
+ "2": "hai",
25
+ "3": "ba",
26
+ "4": "bốn",
27
+ "5": "năm",
28
+ "6": "sáu",
29
+ "7": "bảy",
30
+ "8": "tám",
31
+ "9": "chín"
32
+ }
33
+
34
+ def convert(self, token: str) -> str:
35
+ # 1 Lọc bỏ tất cả các ký tự không phải số
36
+ token = self.filter_regex.sub("", token)
37
+ # 2 Kiểm tra trường hợp đặc biệt
38
+ if token == "007":
39
+ return "không không bảy"
40
+ # 3 & 4 Chuyển đổi mỗi chữ số thành văn bản và thêm khoảng trắng
41
+ token = " ".join([self.trans_dict[c] for c in token])
42
+ return token
43
+ if __name__ == "__main__":
44
+ # Tạo một thể hiện của lớp DigitVietnamese
45
+ digit_converter = DigitVietnamese()
46
+
47
+ # Ví dụ 1: Số điện thoại
48
+ phone_number = "0912345678"
49
+ print(f"Số điện thoại: {phone_number}")
50
+ print(f"Chuyển đổi: {digit_converter.convert(phone_number)}")
51
+ print()
52
+
53
+ # Ví dụ 2: Mã số sinh viên
54
+ student_id = "SV20210001"
55
+ print(f"Mã số sinh viên: {student_id}")
56
+ print(f"Chuyển đổi: {digit_converter.convert(student_id)}")
57
+ print()
58
+
59
+ # Ví dụ 3: Trường hợp đặc biệt
60
+ special_case = "007"
61
+ print(f"Số đặc biệt: {special_case}")
62
+ print(f"Chuyển đổi: {digit_converter.convert(special_case)}")
converters/Fraction.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .Cardinal import CardinalVietnamese
2
+ import re
3
+ from singleton_decorator import singleton
4
+
5
+ @singleton
6
+ class Fraction:
7
+ def __init__(self):
8
+ super().__init__()
9
+ self.filter_regex = re.compile(",")
10
+ self.space_filter_regex = re.compile(" ")
11
+ self.trans_dict = {
12
+ "½": {"prepended": "một", "single": "một", "text": "phần hai"},
13
+ "⅓": {"prepended": "một", "single": "một", "text": "phần ba"},
14
+ "⅔": {"prepended": "hai", "single": "hai", "text": "phần ba"},
15
+ "¼": {"prepended": "một", "single": "một", "text": "phần tư"},
16
+ "¾": {"prepended": "ba", "single": "ba", "text": "phần tư"},
17
+ "⅕": {"prepended": "một", "single": "một", "text": "phần năm"},
18
+ "⅖": {"prepended": "hai", "single": "hai", "text": "phần năm"},
19
+ "⅗": {"prepended": "ba", "single": "ba", "text": "phần năm"},
20
+ "⅘": {"prepended": "bốn", "single": "bốn", "text": "phần năm"},
21
+ "⅙": {"prepended": "một", "single": "một", "text": "phần sáu"},
22
+ "⅚": {"prepended": "năm", "single": "năm", "text": "phần sáu"},
23
+ "⅐": {"prepended": "một", "single": "một", "text": "phần bảy"},
24
+ "⅛": {"prepended": "một", "single": "một", "text": "phần tám"},
25
+ "⅜": {"prepended": "ba", "single": "ba", "text": "phần tám"},
26
+ "⅝": {"prepended": "năm", "single": "năm", "text": "phần tám"},
27
+ "⅞": {"prepended": "bảy", "single": "bảy", "text": "phần tám"},
28
+ "⅑": {"prepended": "một", "single": "một", "text": "phần chín"},
29
+ "⅒": {"prepended": "một", "single": "một", "text": "phần mười"}
30
+ }
31
+ self.special_regex = re.compile(f"({'|'.join(self.trans_dict.keys())})")
32
+ self.cardinal = CardinalVietnamese()
33
+ self.slash_regex = re.compile(r"(-?\d{1,3}( \d{3})+|-?\d+) *\/ *(-?\d{1,3}( \d{3})+|-?\d+)")
34
+
35
+ # Không cần chuyển đổi từ Cardinal sang Ordinal trong tiếng Việt
36
+ self.trans_denominator = {}
37
+
38
+ self.edge_dict = {
39
+ "1": {"singular": "trên một", "plural": "trên một"},
40
+ "2": {"singular": "phần hai", "plural": "phần hai"},
41
+ "4": {"singular": "phần tư", "plural": "phần tư"}
42
+ }
43
+
44
+ def convert(self, token: str) -> str:
45
+ token = self.filter_regex.sub("", token)
46
+ match = self.special_regex.search(token)
47
+ if match:
48
+ frac = match.group(1)
49
+ frac_dict = self.trans_dict[frac]
50
+
51
+ remainder = self.special_regex.sub("", token)
52
+ if remainder:
53
+ prefix = self.cardinal.convert(remainder)
54
+ result = f"{prefix} và {frac_dict['prepended']} {frac_dict['text']}"
55
+ else:
56
+ result = f"{frac_dict['single']} {frac_dict['text']}"
57
+
58
+ else:
59
+ match = self.slash_regex.search(token)
60
+ if match:
61
+ numerator = match.group(1)
62
+ denominator = match.group(3)
63
+
64
+ numerator = self.space_filter_regex.sub("", numerator)
65
+ denominator = self.space_filter_regex.sub("", denominator)
66
+
67
+ numerator_text = self.cardinal.convert(numerator)
68
+
69
+ if denominator in self.edge_dict:
70
+ result = f"{numerator_text} {self.edge_dict[denominator]['singular']}"
71
+
72
+ else:
73
+ denominator_text = self.cardinal.convert(denominator)
74
+ result = f"{numerator_text} phần {denominator_text}"
75
+
76
+ remainder = self.slash_regex.sub("", token)
77
+ if remainder:
78
+ remainder_text = self.cardinal.convert(remainder)
79
+ result = f"{remainder_text} và {result}"
80
+
81
+ else:
82
+ result = token
83
+
84
+ return result
85
+
86
+ if __name__ == "__main__":
87
+ fraction = Fraction()
88
+
89
+ test_cases = [
90
+ "½",
91
+ "1½",
92
+ "2¼",
93
+ "3⅔",
94
+ "1/4",
95
+ "3/4",
96
+ "5/8",
97
+ "10/3",
98
+ "100/25",
99
+ "1000/999",
100
+ "2 1/2",
101
+ "3 3/4",
102
+ "5 2/3",
103
+ "100 1/100",
104
+ ]
105
+
106
+ for case in test_cases:
107
+ result = fraction.convert(case)
108
+ print(f"Phân số: {case}")
109
+ print(f"Chuyển đổi: {result}")
110
+ print()
converters/Meansure.py ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+
3
+ import re
4
+
5
+ from .Decimal import Decimal
6
+ from .Fraction import Fraction
7
+
8
+
9
+ @singleton
10
+ class Measure:
11
+ def __init__(self):
12
+ super().__init__()
13
+ # Regex để phát hiện phân số
14
+ self.fraction_regex = re.compile(
15
+ r"(((?:-?\d* )?-?\d+ *\/ *-? *\d+)|(-?\d* *(?:½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒)))")
16
+ # Regex để phát hiện xem có nên sử dụng "của một" hay không
17
+ self.of_a_regex = re.compile(r"(-?\d+ -?\d+ *\/ *-? *\d+)|(-?\d+ *(?:½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒))")
18
+ # Regex để phát hiện đầu vào để chuyển đổi số, bao gồm cả hậu tố triệu/tỷ tiềm năng
19
+ self.value_regex = re.compile(r"(-?(?: |\d)*\.?\d+ *(?:nghìn|triệu|tỷ|nghìn tỷ|triệu tỷ|tỷ tỷ)?)")
20
+ # Regex để lọc bỏ dấu phẩy
21
+ self.filter_regex = re.compile(r"[,]")
22
+ # Regex để lọc bỏ khoảng trắng
23
+ self.filter_space_regex = re.compile(r"[ ]")
24
+ # Regex để lọc bỏ chữ cái
25
+ self.letter_filter_regex = re.compile(r"[^0-9\-\.]")
26
+
27
+ # Từ điển tiền tố cho 10^i với i > 0
28
+ self.prefix_dict = {
29
+ "Y": "yotta",
30
+ "Z": "zetta",
31
+ "E": "exa",
32
+ "P": "peta",
33
+ "T": "tera",
34
+ "G": "giga",
35
+ "M": "mega",
36
+ "k": "kilo",
37
+ "h": "hecto",
38
+ "da": "deca",
39
+ "d": "deci",
40
+ "c": "centi",
41
+ "m": "milli",
42
+ "μ": "micro",
43
+ "µ": "micro",
44
+ "n": "nano",
45
+ "p": "pico",
46
+ "f": "femto",
47
+ "a": "atto",
48
+ "z": "zepto",
49
+ "y": "yocto"
50
+ }
51
+
52
+ # Từ điển dịch cho các loại đơn vị có thể thêm tiền tố
53
+ self.prefixable_trans_dict = {
54
+ "m": {
55
+ "singular": "mét",
56
+ "plural": "mét"
57
+ },
58
+ "b": {
59
+ "singular": "bit",
60
+ "plural": "bit"
61
+ },
62
+ "B": {
63
+ "singular": "byte",
64
+ "plural": "byte"
65
+ },
66
+ "bps": {
67
+ "singular": "bit trên giây",
68
+ "plural": "bit trên giây"
69
+ },
70
+ "Bps": {
71
+ "singular": "byte trên giây",
72
+ "plural": "byte trên giây"
73
+ },
74
+ "g": {
75
+ "singular": "gram",
76
+ "plural": "gram"
77
+ },
78
+ "gf": {
79
+ "singular": "gram lực",
80
+ "plural": "gram lực"
81
+ },
82
+ "W": {
83
+ "singular": "oát",
84
+ "plural": "oát"
85
+ },
86
+ "Wh": {
87
+ "singular": "oát giờ",
88
+ "plural": "oát giờ"
89
+ },
90
+ "Hz": {
91
+ "singular": "héc",
92
+ "plural": "héc"
93
+ },
94
+ "J": {
95
+ "singular": "jun",
96
+ "plural": "jun"
97
+ },
98
+ "L": {
99
+ "singular": "lít",
100
+ "plural": "lít"
101
+ },
102
+ "V": {
103
+ "singular": "vôn",
104
+ "plural": "vôn"
105
+ },
106
+ "f": {
107
+ "singular": "fara",
108
+ "plural": "fara"
109
+ },
110
+ "s": {
111
+ "singular": "giây",
112
+ "plural": "giây"
113
+ },
114
+ "A": {
115
+ "singular": "ampe",
116
+ "plural": "ampe"
117
+ },
118
+ "Ah": {
119
+ "singular": "ampe giờ",
120
+ "plural": "ampe giờ"
121
+ },
122
+ "Pa": {
123
+ "singular": "pascal",
124
+ "plural": "pascal"
125
+ },
126
+ "C": {
127
+ "singular": "culông",
128
+ "plural": "culông"
129
+ },
130
+ "Bq": {
131
+ "singular": "becquerel",
132
+ "plural": "becquerel"
133
+ },
134
+ "N": {
135
+ "singular": "niutơn",
136
+ "plural": "niutơn"
137
+ },
138
+ "bar": {
139
+ "singular": "bar",
140
+ "plural": "bar"
141
+ },
142
+ "lm": {
143
+ "singular": "lumen",
144
+ "plural": "lumen"
145
+ },
146
+ "cal": {
147
+ "singular": "calo",
148
+ "plural": "calo"
149
+ },
150
+ }
151
+
152
+ # Từ điển đã được biến đổi sử dụng self.prefixable_trans_dict và từ điển tiền tố
153
+ self.prefixed_dict = {
154
+ prefix + prefixed: {"singular": self.prefix_dict[prefix] + self.prefixable_trans_dict[prefixed]["singular"],
155
+ "plural": self.prefix_dict[prefix] + self.prefixable_trans_dict[prefixed]["plural"]} for
156
+ prefixed in self.prefixable_trans_dict for prefix in self.prefix_dict}
157
+ self.prefixed_dict = {**self.prefixed_dict, **self.prefixable_trans_dict}
158
+
159
+ # Từ điển dịch cho các loại đơn vị không có tiền tố
160
+ self.custom_dict = {
161
+ "%": {
162
+ "singular": "phần trăm",
163
+ "plural": "phần trăm"
164
+ },
165
+ "pc": {
166
+ "singular": "phần trăm",
167
+ "plural": "phần trăm"
168
+ },
169
+ "ft": {
170
+ "singular": "foot",
171
+ "plural": "foot"
172
+ },
173
+ "mi": {
174
+ "singular": "dặm",
175
+ "plural": "dặm"
176
+ },
177
+ "mb": {
178
+ "singular": "megabyte",
179
+ "plural": "megabyte"
180
+ },
181
+ "ha": {
182
+ "singular": "hecta",
183
+ "plural": "hecta"
184
+ },
185
+ "\"": {
186
+ "singular": "inch",
187
+ "plural": "inch"
188
+ },
189
+ "in": {
190
+ "singular": "inch",
191
+ "plural": "inch"
192
+ },
193
+ "\'": {
194
+ "singular": "foot",
195
+ "plural": "foot"
196
+ },
197
+ "rpm": {
198
+ "singular": "vòng trên phút",
199
+ "plural": "vòng trên phút"
200
+ },
201
+ "hp": {
202
+ "singular": "mã lực",
203
+ "plural": "mã lực"
204
+ },
205
+ "cc": {
206
+ "singular": "xăng-ti-mét khối",
207
+ "plural": "xăng-ti-mét khối"
208
+ },
209
+ "oz": {
210
+ "singular": "aoxơ",
211
+ "plural": "aoxơ",
212
+ },
213
+ "mph": {
214
+ "singular": "dặm trên giờ",
215
+ "plural": "dặm trên giờ"
216
+ },
217
+ "lb": {
218
+ "singular": "pao",
219
+ "plural": "pao"
220
+ },
221
+ "lbs": {
222
+ "singular": "pao",
223
+ "plural": "pao"
224
+ },
225
+ "kt": {
226
+ "singular": "nút",
227
+ "plural": "nút"
228
+ },
229
+ "dB": {
230
+ "singular": "đề-xi-ben",
231
+ "plural": "đề-xi-ben"
232
+ },
233
+ "AU": {
234
+ "singular": "đơn vị thiên văn",
235
+ "plural": "đơn vị thiên văn"
236
+ },
237
+ "st": {
238
+ "singular": "stone",
239
+ "plural": "stone"
240
+ },
241
+ "yd": {
242
+ "singular": "yard",
243
+ "plural": "yard"
244
+ },
245
+ "yr": {
246
+ "singular": "năm",
247
+ "plural": "năm"
248
+ },
249
+ "yrs": {
250
+ "singular": "năm",
251
+ "plural": "năm"
252
+ },
253
+ "eV": {
254
+ "singular": "electron vôn",
255
+ "plural": "electron vôn"
256
+ },
257
+ "/": {
258
+ "singular": "trên",
259
+ "plural": "trên"
260
+ },
261
+ "sq": {
262
+ "singular": "vuông",
263
+ "plural": "vuông"
264
+ },
265
+ "2": {
266
+ "singular": "vuông",
267
+ "plural": "vuông"
268
+ },
269
+ "²": {
270
+ "singular": "vuông",
271
+ "plural": "vuông"
272
+ },
273
+ "3": {
274
+ "singular": "khối",
275
+ "plural": "khối"
276
+ },
277
+ "³": {
278
+ "singular": "khối",
279
+ "plural": "khối"
280
+ },
281
+ "h": {
282
+ "singular": "giờ",
283
+ "plural": "giờ"
284
+ },
285
+ "hr": {
286
+ "singular": "giờ",
287
+ "plural": "giờ"
288
+ },
289
+ "hrs": {
290
+ "singular": "giờ",
291
+ "plural": "giờ"
292
+ },
293
+ "ch": {
294
+ "singular": "chain",
295
+ "plural": "chain"
296
+ },
297
+ "KiB": {
298
+ "singular": "kibibyte",
299
+ "plural": "kibibyte"
300
+ },
301
+ "MiB": {
302
+ "singular": "mebibyte",
303
+ "plural": "mebibyte"
304
+ },
305
+ "GiB": {
306
+ "singular": "gibibyte",
307
+ "plural": "gibibyte"
308
+ },
309
+ "pH": {
310
+ "singular": "pH",
311
+ "plural": "pH"
312
+ },
313
+ "kph": {
314
+ "singular": "kilômét trên giờ",
315
+ "plural": "kilômét trên giờ"
316
+ },
317
+ "Da": {
318
+ "singular": "đalton",
319
+ "plural": "đalton"
320
+ },
321
+ "cwt": {
322
+ "singular": "hundredweight",
323
+ "plural": "hundredweight"
324
+ },
325
+ "Sv": {
326
+ "singular": "sievert",
327
+ "plural": "sievert",
328
+ },
329
+ "C": {
330
+ "singular": "độ xen-xi-út",
331
+ "plural": "độ xen-xi-út"
332
+ },
333
+ "degrees": {
334
+ "singular": "độ",
335
+ "plural": "độ"
336
+ },
337
+ "degree": {
338
+ "singular": "độ",
339
+ "plural": "độ"
340
+ },
341
+ "atm": {
342
+ "singular": "át-mốt-phê",
343
+ "plural": "át-mốt-phê"
344
+ },
345
+ "min": {
346
+ "singular": "phút",
347
+ "plural": "phút"
348
+ },
349
+ "cd": {
350
+ "singular": "can-đê-la",
351
+ "plural": "can-đê-la"
352
+ },
353
+ "ly": {
354
+ "singular": "năm ánh sáng",
355
+ "plural": "năm ánh sáng"
356
+ },
357
+ "kts": {
358
+ "singular": "nút",
359
+ "plural": "nút"
360
+ },
361
+ "mol": {
362
+ "singular": "mol",
363
+ "plural": "mol"
364
+ },
365
+ "Nm": {
366
+ "singular": "niutơn mét",
367
+ "plural": "niutơn mét"
368
+ },
369
+ "Ω": {
370
+ "singular": "ôm",
371
+ "plural": "ôm"
372
+ },
373
+ "bbl": {
374
+ "singular": "thùng",
375
+ "plural": "thùng"
376
+ },
377
+ "gal": {
378
+ "singular": "gallon",
379
+ "plural": "gallon"
380
+ },
381
+ "cal": {
382
+ "singular": "cỡ nòng",
383
+ "plural": "cỡ nòng"
384
+ }
385
+ }
386
+
387
+ # Ghi đè và thêm giá trị từ custom_dict vào prefixed_dict
388
+ self.prefixed_dict = {**self.prefixed_dict, **self.custom_dict}
389
+
390
+ # Phiên bản viết thường của self.prefixed_dict
391
+ self.lower_prefixed_dict = {key.lower(): self.prefixed_dict[key] for key in self.prefixed_dict}
392
+
393
+ # Hậu tố đặc biệt mà tổng hậu tố nên được tách ra
394
+ self.special_suffixes = re.compile(r"(\/|trên(?!trăm)|vuông|2|²|3|³)")
395
+
396
+ # Chuyển đổi Decimal và Fraction
397
+ self.decimal = Decimal()
398
+ self.fraction = Fraction()
399
+
400
+
401
+ def convert(self, token: str) -> str:
402
+ # 1 Lọc bỏ dấu phẩy
403
+ token = self.filter_regex.sub("", token)
404
+
405
+ result_list = []
406
+
407
+ # Số nhiều mặc định là false, vì "/s" nên là "trên giây"
408
+ plural = False
409
+
410
+ # 2 Thử khớp với một phân số
411
+ match = self.fraction_regex.match(token)
412
+ if match:
413
+ # 2.1 Nếu tồn tại, chuyển đổi thành văn bản sử dụng bộ chuyển đổi Fraction
414
+ result_list.append(self.fraction.convert(match.group(0)))
415
+ # Chuyển token thành phần còn lại. Vì sử dụng match thay vì search,
416
+ # phần đầu của dòng tiếp theo có thể không cần thiết
417
+ token = token[:match.span()[0]] + token[match.span()[1]:]
418
+
419
+ # Lọc bỏ khoảng trắng
420
+ token = self.filter_space_regex.sub("", token)
421
+
422
+ # Nếu có một số trước phân số, ví dụ "8 1/2" hoặc "8 ½", thì chúng ta thêm "của một", và giữ nguyên số ít
423
+ # Ngược lại, chúng ta chuyển sang số nhiều
424
+ if self.of_a_regex.match(match.group(0)):
425
+ plural = True
426
+ else:
427
+ result_list.append("của một")
428
+
429
+ else:
430
+ # 3 Thử khớp với "x,y" hoặc "x"
431
+ match = self.value_regex.match(token)
432
+ if match:
433
+ # 3.1 Chuyển không có khoảng trắng cho bộ chuyển đổi decimal
434
+ result_list.append(self.decimal.convert(self.filter_space_regex.sub("", match.group(1))))
435
+ token = token[:match.span()[0]] + token[match.span()[1]:]
436
+ # Số nhiều là False khi giá trị tuyệt đối của số thập phân là 1, và giá trị thập phân không có dạng "1,x"
437
+ # Ngược lại là True
438
+ if abs(float(self.letter_filter_regex.sub("", match.group(1)))) != 1 or "," in match.group(1):
439
+ plural = True
440
+
441
+ # Biến chỉ ra liệu từ "trên" vừa được sử dụng
442
+ # Điều này được sử dụng để phát hiện số nhiều
443
+ per = False
444
+ # 4 Lặp qua phần còn lại của token
445
+ for split_token in token.split(" "):
446
+ for i, token in enumerate(self.split_token(split_token)):
447
+ # Thêm tên thích hợp của hậu tố nếu tồn tại
448
+ # Thử không phân biệt chữ hoa chữ thường nếu lần trước thất bại
449
+ if token in self.prefixed_dict:
450
+ result_list.append(self.prefixed_dict[token]["plural" if plural and not per else "singular"])
451
+ elif token.lower() in self.lower_prefixed_dict:
452
+ result_list.append(
453
+ self.lower_prefixed_dict[token.lower()]["plural" if plural and not per else "singular"])
454
+ else:
455
+ result_list.append(token)
456
+
457
+ # Nếu kết quả trước đó là "trên", đặt per thành True để sử dụng "singular" cho từ tiếp theo.
458
+ # Nhưng chỉ khi "trên" không phải là hậu tố đầu tiên. Ví dụ: "5/km2" là "năm trên kilômét vuông"
459
+ if result_list[-1] == "trên" and i != 0:
460
+ per = True
461
+
462
+ # Nếu từ cuối cùng không phải là "trên", và không phải "vuông" hoặc "khối", đặt lại per thành False.
463
+ # Nếu "trên" được sử dụng, tiếp theo là "vuông" hoặc "khối", chúng ta muốn giữ "singular" cho
464
+ # từ sắp tới
465
+ elif result_list[-1] not in ("vuông", "khối"):
466
+ per = False
467
+
468
+ result = " ".join(result_list)
469
+
470
+ # 5 Xử lý trường hợp đặc biệt: xentimét khối -> xăng-ti-mét khối
471
+ result = re.sub(r"xentimét khối", "xăng-ti-mét khối", result)
472
+
473
+ return result
converters/Money.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re, os
3
+ from .Cardinal import CardinalVietnamese
4
+ from .Digit import DigitVietnamese
5
+
6
+
7
+ @singleton
8
+ class Money:
9
+ def __init__(self):
10
+ super().__init__()
11
+ self.decimal_regex = re.compile(r"(.*?)(-?\d*)\.(\d+)(.*)")
12
+ self.number_regex = re.compile(r"(.*?)(-?\d+)(.*)")
13
+ self.filter_regex = re.compile(r"[, ]")
14
+
15
+ self.currencies = {
16
+ "đ": {
17
+ "number": {
18
+ "singular": "đồng",
19
+ "plural": "đồng"
20
+ },
21
+ "decimal": {
22
+ "singular": "xu",
23
+ "plural": "xu"
24
+ }
25
+ },
26
+ "vnd": {
27
+ "number": {
28
+ "singular": "đồng Việt Nam",
29
+ "plural": "đồng Việt Nam"
30
+ },
31
+ "decimal": {
32
+ "singular": "xu",
33
+ "plural": "xu"
34
+ }
35
+ }
36
+ }
37
+
38
+ self.suffixes = [
39
+ "nghìn",
40
+ "triệu",
41
+ "tỷ",
42
+ "nghìn tỷ",
43
+ "triệu tỷ",
44
+ "tỷ tỷ"
45
+ ]
46
+
47
+ self.abbr_suffixes = {
48
+ "k": "nghìn",
49
+ "tr": "triệu",
50
+ "t": "tỷ"
51
+ }
52
+
53
+ self.suffix_regex = re.compile(
54
+ f"({'|'.join(sorted(self.suffixes + list(self.abbr_suffixes.keys()), key=len, reverse=True))})(.*)",
55
+ flags=re.I)
56
+
57
+ self.currency_regex = re.compile(r"(.*?)(đồng|vnd|đ)(.*?)", flags=re.I)
58
+
59
+ self.cardinal = CardinalVietnamese() # Giả sử đã có lớp Cardinal cho tiếng Việt
60
+ self.digit = DigitVietnamese() # Giả sử đã có lớp Digit cho tiếng Việt
61
+
62
+ def convert(self, token: str) -> str:
63
+ token = self.filter_regex.sub("", token)
64
+
65
+ before = ""
66
+ after = ""
67
+ currency = None
68
+ number = ""
69
+ decimal = ""
70
+ scale = ""
71
+
72
+ match = self.decimal_regex.search(token[::-1])
73
+ if match:
74
+ before = match.group(4)[::-1]
75
+ number = match.group(3)[::-1]
76
+ decimal = match.group(2)[::-1]
77
+ after = match.group(1)[::-1]
78
+ else:
79
+ match = self.number_regex.search(token)
80
+ if match:
81
+ before = match.group(1)
82
+ number = match.group(2)
83
+ after = match.group(3)
84
+
85
+ if before:
86
+ before = before.lower()
87
+ if before in self.currencies:
88
+ currency = self.currencies[before]
89
+ elif before[-1] in self.currencies:
90
+ currency = self.currencies[before[-1]]
91
+
92
+ if after:
93
+ match = self.suffix_regex.match(after)
94
+ if match:
95
+ scale = match.group(1).lower()
96
+ scale = self.abbr_suffixes[scale] if scale in self.abbr_suffixes else scale
97
+ after = match.group(2)
98
+
99
+ if after.lower() in self.currencies:
100
+ currency = self.currencies[after.lower()]
101
+ after = ""
102
+
103
+ decimal_support = currency and "number" in currency
104
+
105
+ result_list = []
106
+ if decimal_support and not scale:
107
+ if number and (number != "0" or not decimal):
108
+ result_list.append(self.cardinal.convert(number))
109
+ result_list.append(currency["number"]["singular"])
110
+ if decimal and decimal != "0" * len(decimal):
111
+ result_list.append("và")
112
+ if decimal and decimal != "0" * len(decimal):
113
+ decimal = f"{decimal:0<2}"
114
+ result_list.append(self.cardinal.convert(decimal))
115
+ result_list.append(currency["decimal"]["singular"])
116
+ else:
117
+ if number:
118
+ result_list.append(self.cardinal.convert(number))
119
+ if decimal and decimal != "0" * len(decimal):
120
+ result_list.append("phẩy")
121
+ result_list.append(self.digit.convert(decimal))
122
+ if scale:
123
+ result_list.append(scale)
124
+ if currency:
125
+ if decimal_support:
126
+ currency = currency["number"]
127
+ result_list.append(currency["singular"])
128
+
129
+ if after:
130
+ result_list.append(after.lower())
131
+
132
+ result = " ".join(result_list)
133
+ return result
134
+
135
+
136
+ if __name__ == "__main__":
137
+ money = Money()
138
+
139
+ # Ví dụ 1: Số tiền đơn giản
140
+ print(money.convert("15000đ")) # Kết quả mong đợi: mười lăm nghìn đồng
141
+
142
+ # Ví dụ 2: Số tiền có phần thập phân
143
+ print(money.convert("1500.50đ")) # Kết quả mong đợi: một nghìn năm trăm đồng và năm mươi xu
144
+
145
+ # Ví dụ 3: Số tiền lớn
146
+ print(money.convert("1000000000đ")) # Kết quả mong đợi: một tỷ đồng
147
+
148
+ # Ví dụ 4: Sử dụng VND
149
+ print(money.convert("5000000VND")) # Kết quả mong đợi: năm triệu đồng Việt Nam
150
+
151
+ # Ví dụ 5: Sử dụng hậu tố
152
+ print(money.convert("2tr đồng")) # Kết quả mong đợi: hai triệu đồng
153
+
154
+ # Ví dụ 6: Số tiền rất lớn
155
+ print(money.convert("1000000000000đ")) # Kết quả mong đợi: một nghìn tỷ đồng
converters/Ordinal.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+ from Roman import RomanVietnamese
4
+ from Cardinal import CardinalVietnamese
5
+
6
+
7
+ @singleton
8
+ class OrdinalVietnamese:
9
+ """
10
+ Các bước:
11
+ - 1 Lọc bỏ dấu phẩy và khoảng trắng
12
+ - 2 Kiểm tra số La Mã và chuyển đổi thành chuỗi số nguyên nếu có
13
+ - 3 Nếu là số La Mã, đặt tiền tố là "thứ"
14
+ - 4 Nếu không, kiểm tra xem có phải là số thứ tự tiếng Việt không (ví dụ: "thứ nhất", "thứ 2", "thứ ba")
15
+ - 5 Chuyển đổi chuỗi số còn lại thành Cardinal, và thêm "thứ" vào trước
16
+ - 6 Áp dụng các quy tắc đặc biệt cho số thứ tự tiếng Việt
17
+ """
18
+
19
+ def __init__(self):
20
+ super().__init__()
21
+ self.filter_regex = re.compile(r"[, ]")
22
+ self.vietnamese_ordinal_regex = re.compile(r"(?i)(thứ\s*)?(\d+|nhất|nhì|hai|ba|tư|năm|sáu|bảy|tám|chín|mười)")
23
+ self.roman = RomanVietnamese()
24
+ self.cardinal = CardinalVietnamese()
25
+
26
+ self.special_cases = {
27
+ "nhất": "thứ nhất",
28
+ "nhì": "thứ nhì",
29
+ "hai": "thứ hai",
30
+ "ba": "thứ ba",
31
+ "tư": "thứ tư",
32
+ "năm": "thứ năm",
33
+ "sáu": "thứ sáu",
34
+ "bảy": "thứ bảy",
35
+ "tám": "thứ tám",
36
+ "chín": "thứ chín",
37
+ "mười": "thứ mười"
38
+ }
39
+
40
+ def convert(self, token: str) -> str:
41
+ token = self.filter_regex.sub("", token)
42
+
43
+ if self.roman.check_if_roman(token):
44
+ number, _ = self.roman.convert(token)
45
+
46
+ return f"thứ {number}"
47
+
48
+ match = self.vietnamese_ordinal_regex.fullmatch(token)
49
+ if match:
50
+ prefix = match.group(1) or ""
51
+ number = match.group(2)
52
+
53
+ if number.lower() in self.special_cases:
54
+ return self.special_cases[number.lower()]
55
+
56
+ if number.isdigit():
57
+ cardinal = self.cardinal.convert(number)
58
+ return f"thứ {cardinal}"
59
+
60
+ return f"{prefix}{number}"
61
+
62
+ return f"thứ {self.cardinal.convert(token)}"
63
+
64
+
65
+ if __name__ == "__main__":
66
+ ordinal_converter = OrdinalVietnamese()
67
+
68
+ examples = ["nhất", "thứ nhì", "thứ 3", "thứ tư", "thứ năm", "thứ 10", "21", "100", "1000", "II", "IV"]
69
+
70
+ for example in examples:
71
+ result = ordinal_converter.convert(example)
72
+ print(f"Số thứ tự: {example}")
73
+ print(f"Chuyển đổi: {result}")
74
+ print()
converters/Range.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+ from .Cardinal import CardinalVietnamese
4
+
5
+
6
+ @singleton
7
+ class Range:
8
+ """
9
+ Steps:
10
+ - Check for - splitting numbers
11
+
12
+ Note:
13
+ Punctuation always stays the same
14
+ """
15
+
16
+ def __init__(self):
17
+ super().__init__()
18
+ self.cardinal = CardinalVietnamese()
19
+
20
+ def convert(self, token: str) -> str:
21
+ numbers = re.split('-', token)
22
+ if len(numbers) == 1:
23
+ token = self.cardinal.convert(numbers[0])
24
+ elif len(numbers) == 2:
25
+
26
+ token = self.cardinal.convert(numbers[0])
27
+ token += ' đến '
28
+ token += self.cardinal.convert(numbers[1])
29
+
30
+ else:
31
+ token = ''
32
+ for number in numbers:
33
+ token += self.cardinal.convert(number)
34
+ token += ' '
35
+
36
+ return token
converters/Roman.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+
4
+
5
+ @singleton
6
+ class RomanVietnamese:
7
+ """
8
+ Các bước:
9
+ - 1 Lấy phần lớn nhất
10
+ - 2 Kiểm tra hậu tố 's'
11
+ - 3 Áp dụng lọc nghiêm ngặt
12
+ - 4 Tính tổng giá trị của chữ số La Mã bằng số nguyên
13
+ - 5 Trả về biểu diễn chuỗi của tổng, cùng với hậu tố
14
+ Trường hợp đặc biệt:
15
+ II I -> hai
16
+ IIs -> hai's
17
+ II. -> hai
18
+ """
19
+
20
+ def __init__(self):
21
+ super().__init__()
22
+ # Regex để lọc bỏ các ký tự không phải chữ số La Mã
23
+ self.roman_filter_strict_regex = re.compile("[^IVXLCDM]")
24
+ # Regex để phát hiện chữ số La Mã
25
+ self.roman_filter_regex = re.compile(r"[.IVXLCDM]+(th|nd|st|rd|'s|s)?")
26
+
27
+ # Từ điển giá trị chữ số La Mã
28
+ self.roman_numerals = {
29
+ "I": 1,
30
+ "V": 5,
31
+ "X": 10,
32
+ "L": 50,
33
+ "C": 100,
34
+ "D": 500,
35
+ "M": 1000
36
+ }
37
+
38
+
39
+
40
+ def convert(self, token: str) -> (str, str):
41
+ # 1 Tách token thành các phần và làm việc với phần lớn nhất, trong trường hợp đầu vào là "I II"
42
+ token = max(token.split(" "), key=len)
43
+ # 2 Kiểm tra xem có cần sử dụng hậu tố "'s" không
44
+ suffix = ""
45
+ if token[-1:] == "s":
46
+ suffix = "'s"
47
+
48
+ # 3 Áp dụng lọc nghiêm ngặt để loại bỏ ".", "'" và "s"
49
+ token = self.roman_filter_strict_regex.sub("", token)
50
+ # 4 Chúng ta lặp qua token theo chiều ngược lại, liên tục cộng hoặc trừ giá trị được biểu diễn
51
+ # bởi ký tự, dựa trên các token trước đó.
52
+ total = 0
53
+ prev = 0
54
+ for c in reversed(token):
55
+ cur = self.roman_numerals[c]
56
+ total += cur if cur >= prev else -cur
57
+ prev = cur
58
+
59
+ return (str(total), suffix)
60
+
61
+
62
+ def check_if_roman(self, token: str) -> bool:
63
+ # Kiểm tra xem phần lớn nhất của token có được coi là chữ số La Mã hay không
64
+ return self.roman_filter_regex.fullmatch(max(token.split(" "), key=len)) != None
65
+
66
+
67
+ if __name__ == "__main__":
68
+ roman_converter = RomanVietnamese()
69
+
70
+ # Ví dụ 1
71
+ example1 = "XIV"
72
+ result1, suffix1 = roman_converter.convert(example1)
73
+ print(f"Chữ số La Mã: {example1}")
74
+ print(f"Chuyển đổi: {result1}{suffix1}")
75
+ print()
76
+
77
+ # Ví dụ 2
78
+ example2 = "MCMLIV"
79
+ result2, suffix2 = roman_converter.convert(example2)
80
+ print(f"Chữ số La Mã: {example2}")
81
+ print(f"Chuyển đổi: {result2}{suffix2}")
82
+ print()
83
+
84
+ # Ví dụ 3
85
+ example3 = "IIs"
86
+ result3, suffix3 = roman_converter.convert(example3)
87
+ print(f"Chữ số La Mã: {example3}")
88
+ print(f"Chuyển đổi: {result3}{suffix3}")
converters/Telephone.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+
4
+
5
+ @singleton
6
+ class TelephoneVietnamese:
7
+ """
8
+ Các bước:
9
+ - 1 Chuyển đổi thành chữ thường và thay thế dấu ngoặc đơn bằng dấu gạch ngang
10
+ - 2 Chuyển đổi từng ký tự trong token
11
+ - 3 Loại bỏ nhiều "ngat" liên tiếp. Đồng thời loại bỏ "ngat" ở đầu.
12
+ - 4 Thay thế các "khong" liên tiếp bằng "tram" hoặc "nghin" khi thích hợp
13
+ Lưu ý:
14
+ Số điện thoại chứa 0-9, "-", a-z, A-Z, " ", "(", ")"
15
+ """
16
+
17
+ def __init__(self):
18
+ super().__init__()
19
+ # Từ điển dịch
20
+ self.tu_dien_dich = {
21
+ " ": "ngat",
22
+ "-": "ngat",
23
+ "x": "may_nhanh",
24
+ "0": "không",
25
+ "1": "môt",
26
+ "2": "hai",
27
+ "3": "ba",
28
+ "4": "bốn",
29
+ "5": "năm",
30
+ "6": "sáu",
31
+ "7": "bảy",
32
+ "8": "tám",
33
+ "9": "chín",
34
+ }
35
+ # Regex để lọc dấu ngoặc đơn
36
+ self.regex_loc = re.compile(r"[()]")
37
+
38
+ def convert(self, token: str) -> str:
39
+ # 1 Chuyển đổi thành chữ thường và thay thế dấu ngoặc đơn bằng dấu gạch ngang
40
+ token = self.regex_loc.sub("-", token.lower())
41
+
42
+ # 2 Chuyển đổi danh sách các ký tự
43
+ danh_sach_ket_qua = [self.tu_dien_dich[c] if c in self.tu_dien_dich else c for c in token]
44
+
45
+ # 3 Loại bỏ nhiều "ngat" liên tiếp. Đồng thời loại bỏ "ngat" ở đầu.
46
+ danh_sach_ket_qua = [phan for i, phan in enumerate(danh_sach_ket_qua) if
47
+ phan != "ngat" or (i - 1 >= 0 and danh_sach_ket_qua[i - 1] != "ngat")]
48
+
49
+ # 4 Lặp qua danh_sach_ket_qua và thay thế nhiều "khong" liên tiếp bằng "tram" hoặc "nghin",
50
+ # nhưng chỉ khi đứng trước là thứ khác ngoài "khong" hoặc "ngat", và đứng sau là "ngat" hoặc kết thúc danh sách.
51
+ i = 0
52
+ while i < len(danh_sach_ket_qua):
53
+ do_lech = 0
54
+ while i + do_lech < len(danh_sach_ket_qua) and danh_sach_ket_qua[i + do_lech] == "khong":
55
+ do_lech += 1
56
+ if (i + do_lech >= len(danh_sach_ket_qua) or danh_sach_ket_qua[i + do_lech] == "ngat") and (
57
+ i - 1 < 0 or danh_sach_ket_qua[i - 1] not in ("khong", "ngat")) and do_lech in (2, 3):
58
+ danh_sach_ket_qua[i: do_lech + i] = ["tram"] if do_lech == 2 else ["nghin"]
59
+ i += 1
60
+
61
+ return " ".join(danh_sach_ket_qua)
62
+
63
+
64
+ def main():
65
+ so_dien_thoai = TelephoneVietnamese()
66
+
67
+ # Ví dụ sử dụng
68
+ cac_vi_du = [
69
+ "0123-456-789",
70
+ "(098) 765-4321",
71
+ "0909 333 222",
72
+ "1800 1560",
73
+ "19001560",
74
+ "0336444027",
75
+ "+84-912345678",
76
+ ]
77
+
78
+ print("Ví dụ chuyển đổi số điện thoại:")
79
+ for vi_du in cac_vi_du:
80
+ ket_qua = so_dien_thoai.convert(vi_du)
81
+ print(f"Gốc: {vi_du}")
82
+ print(f"Kết quả: {ket_qua}")
83
+ print()
84
+
85
+
86
+ if __name__ == "__main__":
87
+ # main()
88
+ x ="027321"
89
+ if x.startswith(("19", "18", "0")):
90
+ print(1)
converters/Time.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from singleton_decorator import singleton
2
+ import re
3
+ from .Cardinal import CardinalVietnamese
4
+
5
+
6
+ @singleton
7
+ class Time:
8
+ def __init__(self):
9
+ super().__init__()
10
+
11
+ self.filter_regex = re.compile(r"[. ]")
12
+ self.time_regex = re.compile(r"^(?P<hour>\d{1,2}) *((?::|.) *(?P<minute>\d{1,2}))? *(?P<suffix>[a-zA-Z\. ]*)$",
13
+ flags=re.I)
14
+ self.full_time_regex = re.compile(
15
+ r"^(?:(?P<hour>\d{1,2}) *:)? *(?P<minute>\d{1,2})(?: *: *(?P<seconds>\d{1,2})(?: *. *(?P<milliseconds>\d{1,3}))?)? *(?P<suffix>[a-zA-Z\. ]*)$",
16
+ flags=re.I)
17
+ self.ampm_time_regex = re.compile(r"^(?P<suffix>[a-zA-Z\. ]*)(?P<hour>\d{1,2})", flags=re.I)
18
+
19
+ self.cardinal = CardinalVietnamese()
20
+
21
+ def convert(self, token: str) -> str:
22
+ token = token.strip()
23
+ result_list = []
24
+
25
+ match = self.time_regex.match(token)
26
+ if match:
27
+ hour, minute, suffix = match.group("hour"), match.group("minute"), match.group("suffix")
28
+
29
+ result_list.append(self.cardinal.convert(hour))
30
+ result_list.append("giờ")
31
+
32
+ if minute and minute != "00":
33
+ result_list.append(self.cardinal.convert(minute))
34
+ result_list.append("phút")
35
+
36
+ if suffix:
37
+ suffix = self.filter_regex.sub("", suffix).lower()
38
+ if suffix == "sa":
39
+ result_list.append("sáng")
40
+ elif suffix == "ch":
41
+ result_list.append("chiều")
42
+
43
+ return " ".join(result_list)
44
+
45
+ match = self.full_time_regex.match(token)
46
+ if match:
47
+ hour, minute, seconds, milliseconds, suffix = match.group("hour"), match.group("minute"), match.group(
48
+ "seconds"), match.group("milliseconds"), match.group("suffix")
49
+
50
+ if hour:
51
+ result_list.append(self.cardinal.convert(hour))
52
+ result_list.append("giờ")
53
+ if minute:
54
+ result_list.append(self.cardinal.convert(minute))
55
+ result_list.append("phút")
56
+ if seconds:
57
+ result_list.append(self.cardinal.convert(seconds))
58
+ result_list.append("giây")
59
+ if milliseconds:
60
+ result_list.append(self.cardinal.convert(milliseconds))
61
+ result_list.append("phần nghìn giây")
62
+
63
+ if suffix:
64
+ suffix = self.filter_regex.sub("", suffix).lower()
65
+ if suffix == "sa":
66
+ result_list.append("sáng")
67
+ elif suffix == "ch":
68
+ result_list.append("chiều")
69
+
70
+ return " ".join(result_list)
71
+
72
+ match = self.ampm_time_regex.match(token)
73
+ if match:
74
+ hour, suffix = match.group("hour"), match.group("suffix")
75
+
76
+ result_list.append(self.cardinal.convert(hour))
77
+ result_list.append("giờ")
78
+
79
+ suffix = self.filter_regex.sub("", suffix).lower()
80
+ if suffix == "sa":
81
+ result_list.append("sáng")
82
+ elif suffix == "ch":
83
+ result_list.append("chiều")
84
+
85
+ return " ".join(result_list)
86
+
87
+ return token
88
+
89
+
90
+ if __name__ == "__main__":
91
+ time = Time()
92
+
93
+ print(time.convert("7:30")) # Kết quả mong đợi: bảy giờ ba mươi phút
94
+ print(time.convert("8:00 SA")) # Kết quả mong đợi: tám giờ sáng
95
+ print(time.convert("3:00 CH")) # Kết quả mong đợi: ba giờ chiều
96
+ print(time.convert(
97
+ "11:59:59.999")) # Kết quả mong đợi: mười một giờ năm mươi chín phút năm mươi chín giây chín trăm chín mươi chín phần nghìn giây
98
+ print(time.convert("SA7")) # Kết quả mong đợi: bảy giờ sáng
99
+ print(time.convert("CH5")) # Kết quả mong đợi: năm giờ chiều
100
+ print(time.convert("9:30:21")) # Kết quả mong đợi: năm giờ chiều
converters/__init__.py ADDED
File without changes
converters/__pycache__/Cardinal.cpython-310.pyc ADDED
Binary file (5.14 kB). View file
 
converters/__pycache__/Date.cpython-310.pyc ADDED
Binary file (2.92 kB). View file
 
converters/__pycache__/Decimal.cpython-310.pyc ADDED
Binary file (1.99 kB). View file
 
converters/__pycache__/Digit.cpython-310.pyc ADDED
Binary file (1.97 kB). View file
 
converters/__pycache__/Fraction.cpython-310.pyc ADDED
Binary file (2.77 kB). View file
 
converters/__pycache__/Meansure.cpython-310.pyc ADDED
Binary file (6.16 kB). View file
 
converters/__pycache__/Money.cpython-310.pyc ADDED
Binary file (2.86 kB). View file
 
converters/__pycache__/Range.cpython-310.pyc ADDED
Binary file (1.12 kB). View file
 
converters/__pycache__/Roman.cpython-310.pyc ADDED
Binary file (2.22 kB). View file
 
converters/__pycache__/Telephone.cpython-310.pyc ADDED
Binary file (2.8 kB). View file
 
converters/__pycache__/Time.cpython-310.pyc ADDED
Binary file (2.4 kB). View file
 
converters/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (141 Bytes). View file
 
download.sh ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ if [ ! -f uvr5_weights/2_HP-UVR.pth ]; then
4
+ echo "Download the model weights"
5
+ wget -q -O uvr5_weights/2_HP-UVR.pth 2_HP-UVR.pth https://huggingface.co/fastrolling/uvr/resolve/main/Main_Models/2_HP-UVR.pth
6
+ fi
7
+
8
+ echo "The model weights have been downloaded"
train_list.txt ADDED
The diff for this file is too large to render. See raw diff
 
val_list.txt ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset/Xanh24h/speaker_0/3000.wav|tʃˈuə2ŋ tʃˈaː6j tʃˌɔ ɣˈaː2 kˈi2 lˈən bˈaːw ɣˈo2m kˌaːɜc xˈu vˈy6c sˈaw . |0
2
+ dataset/Xanh24h/speaker_0/3001.wav|ɗˈo2ŋ tˈəː2j , tʃˈuɜŋ kˈu5ŋ lˌaː2 tˈy6c fˈə4m xˌoŋ bˌi6 lˈə5n kˌaːɜc t0ˈaː6p tʃˈəɜt0 ɲˌy kˈim lwˈaː6j , twˈi4 t0ˈiɲ , kˌaːɜc vˈə6t0 kˈyɜŋ xˈaːɜc . |0
3
+ dataset/Xanh24h/speaker_0/3002.wav|ɗˈo2ŋ tˈəː2j , mˈuə sˈaɜm tʃˈy6c t0wˈiɛɜn kˌɔ2n lwˈaː6j bˈɔ4 ɲˈu kˈə2w zˈi tʃwˈiɛ4n ɗˌeɜn kˈyə4 hˈaː2ŋ vˈə6t0 lˈiɜ , zˈuɜp t0ˈiɛɜt0 kˈiɛ6m tˈəː2j zˈaːn vˌaː2 t0ˈiɛ2n bˈaː6c . |0
4
+ dataset/Xanh24h/speaker_0/3003.wav|kˈɔɜ hˈaːj mˈo hˈi2ɲ vˈyə2n ˈyəm ɗˌyə6c ɲˈiɛ2w ŋˈyə2j lˈyə6 tʃˈɔ6n xˌi xˈəː4j ŋˈiɛ6p lˌaː2 vˈyə2n ˈyəm kˈoɜ ɗˈi6ɲ vˌaː2 vˈyə2n ˈyəm t0ˈaː6m tˈəː2j . |0
5
+ dataset/Xanh24h/speaker_0/3004.wav|hˈɔ6k vˈiɛn kˈɔɜ tˈe4 hˈɔ6k mˌɔ6j lˌuɜc mˌɔ6j nˈəːj , xˌoŋ kˈə2n fˌaː4j ɗˌeɜn lˈəːɜp hˈɔ6k tʃˈy6c t0ˈiɛɜp . |0
6
+ dataset/Xanh24h/speaker_0/3005.wav|xˌi lˈyə6 tʃˈɔ6n mˈa6t0 hˈaː2ŋ kwˈaː4 bˈiɛɜw t0ˈeɜt0 , kˈə2n lˈiw ˈiɜ mˈo6t0 sˈoɜ vˈəɜn ɗˈe2 sˈaw . |0
7
+ dataset/Xanh24h/speaker_0/3006.wav|vˈəɪ6 nˌen , ɲˌy5ŋ ŋˈyə2j kˈɔɜ tˈu ɲˈə6p ˈəː4 mˈyɜc tʃˈuŋ bˈi2ɲ xˈaːɜ kˈu5ŋ sˈa5n sˈaː2ŋ bˈɔ4 zˈaː mˈo6t0 xwˈaː4n t0ˈiɛ2n ɗˌe4 tʃˈi tʃˈaː4 tʃˌɔ kˌaːɜc lwˈaː6j tˈy6c fˈə4m tʃˈyɜc nˈaŋ hˈo5 tʃˈəː6 sˈyɜc xwˈɛ4 tʃˌɔ kˈəː tˈe4 . |0
8
+ dataset/Xanh24h/speaker_0/3007.wav|tʃˈɔŋ tʃˈyə2ŋ hˈəː6p tʃˈɔ6n bˈe-ɜɲ zˈaːɜn mˈa6n , hˈa5j ɗˈaː4m bˈaː4w tʃwˈə4n bˌi6 nˈyəɜc tʃˈəɜm ŋˈɔn mˈiɛ6ŋ . |0
9
+ dataset/Xanh24h/speaker_0/3008.wav|mˈa6c zˌu2 t0ˈen ɣˈɔ6j kˌuə4 nˈɔɜ lˌaː2 bˈe-ɜɲ ɲˈaː5n , ɲˌyŋ tˈy6c t0ˈeɜ xˌoŋ sˈy4 zˈu6ŋ ɲˈaː5n t0ˈyəj lˈaː2m ŋwˈiɛn lˈiɛ6w tʃˈiɜɲ . |0
10
+ dataset/Xanh24h/speaker_0/3009.wav|zˈyəɜj zˈoɜŋ kˈə2n kˈɔɜ tˈən hˈi2ɲ kˈən ɗˈoɜj , lˈo2ŋ mˈyə6t0 , mˈaɜt0 sˈaːɜŋ , mˈu5j sˈe-6c , xˌoŋ bˌi6 tˈyəŋ t0ˈiɜc . |0
11
+ dataset/Xanh24h/speaker_0/3010.wav|bˈe-ɜɲ ŋˈɔ6t0 sˈyɜc xwˈɛ4 vˌaː2 tʃˈeɜ bˈiɛɜn lˈe-2ɲ mˈe-6ɲ . |0
12
+ dataset/Xanh24h/speaker_0/3011.wav|kˈiɲ zwˈe-ɲ kwˈə2n ˈaːɜw sˈɛkənd hˈand ɗˌaːŋ lˌaː2 mˈo6t0 sˈu hˈyəɜŋ ɗˌyə6c ɲˈiɛ2w ŋˈyə2j lˈyə6 tʃˈɔ6n bˌəː4j vˈoɜn ɗˈə2w t0ˈy bˈaːn ɗˈə2w xˌoŋ kwˈaːɜ lˈəːɜn , mˈa6t0 hˈaː2ŋ ɗˈaː zˈaː6ŋ vˌaː2 kˈɔɜ ɲˈiɛ2w t0ˈiɛ2m nˈaŋ fˈaːɜt0 tʃˈiɛ4n . |0
13
+ dataset/Xanh24h/speaker_0/3012.wav|ˈəː4 nˈyəɜc t0ˈaː tˌi2 kˈɔɜ zˈəɜt0 ɲˈiɛ2w zˈoɜŋ ɣˈaː2 ɲˌyŋ ɗˌe4 tʃˈan nˈuəj ɣˈaː2 tˈaː4 vˈyə2n tˈɛw hˈyəɜŋ ˈaːn t0wˈaː2n sˈiɲ hˈɔ6k bˈa2ŋ vˈiɛ6c nˈuəj ɣˈaː2 tˈaː4w zˈyə6c tˌi2 tʃˈuɜŋ t0ˈaː lˈyə6 tʃˈɔ6n zˈoɜŋ ɣˈaː2 zˈi . |0
14
+ dataset/Xanh24h/speaker_0/3013.wav|ŋwˈaː2j tʃˈi fˈiɜ twˈe mˈa6t0 bˈa2ŋ vˌaː2 ɲˈə6p hˈaː2ŋ , bˈaː6n kˈu5ŋ kˈə2n ɗˈə2w t0ˈy vˈaː2w kˌaːɜc tˈiɛɜt0 bˌi6 kˈə2n tˈiɛɜt0 , ɗˌe4 kˈiɲ zwˈe-ɲ kwˈə2n ˈaːɜw tʃˈɛ4 ˈɛm . |0
15
+ dataset/Xanh24h/speaker_0/3014.wav|ˈoŋ ɗwˈaː2n tˈe-ɲ t0ˈu2ŋ , ˈəɜp mˈyə2j t0ˈaːɜm , sˈaː5 fˈɔŋ tˈe-6ɲ ˈaː , tˈi6 sˈaː5 zˈaːɜ zˈaːj tʃˈiə sˈɛ4 , vˈaː2w xwˌaː4ŋ nˈam hˈaːj ŋˈi2n mˈyə2j bˈaː ɗˌeɜn nˈam hˈaːj ŋˈi2n mˈyə2j lˈam , tʃˈyə2ŋ ɗˈaː6j hˈɔ6k kˈə2n tˈəː kˈɔɜ hˈo5 tʃˈəː6 tˈy6c hˈiɛ6n zˈy6 ˈaːɜn mˈo hˈi2ɲ lˈuəɜ t0ˈom tʃˈɔŋ ˈo ɗˈe2 bˈaː2w xˈɛɜp kˈiɜn ˈəː4 tˈi6 sˈaː5 zˈaːɜ zˈaːj . |0
16
+ dataset/Xanh24h/speaker_0/3015.wav|ɗˌe4 tˈy6c hˈiɛ6n ɗˈiɛ2w nˈa2j , tʃˈu4 kˈyə4 hˈaː2ŋ nˌen ɗˈə2w t0ˈy vˈaː2w vˈiɛ6c t0ˈaː6w zˈaː mˈo6t0 tʃˈaːŋ wˈɛb tʃˌɔ kˈyə4 hˈaː2ŋ , tˈiɛɜt0 lˈə6p zˈaːn hˈaː2ŋ tʃˈen kˌaːɜc nˈe2n t0ˈaː4ŋ tˈyəŋ mˈaː6j ɗˈiɛ6n t0ˈy4 ɲˌy ʃˈəʊpiː , lazˈɑːdə , tˈɪk tˈɒk hwˌa6c sˈy4 zˈu6ŋ kˌaːɜc mˈaː6ŋ sˈaː5 hˈo6j ɲˌy fˈeɪsbʊk , ˈɪnstɐɡɹˌam , zˈɑːləʊ . |0
17
+ dataset/Xanh24h/speaker_0/3016.wav|kˈɔɜ tˈe4 bˈaː6n kˈə2n bˈaɜt0 tʃˈa6j lˈen ɲˈaː2 kˈiɜɲ zˈuɜp ŋˈan kˈɔ4 zˈaː6j tʃˌɔ kˈəɪ tʃˈo2ŋ tʃˈɔŋ ɲˈaː2 kˈiɜɲ hwˌa6c ɲˈaː2 zˈyə lˈyəɜj kˌuə4 bˈaː6n . |0
18
+ dataset/Xanh24h/speaker_0/3018.wav|nˈam hˈaːj ŋˈi2n mˈyə2j bˈoɜn , ˈe-ɲ kwˈiɛɜt0 t0ˈəm tˈɛw ɗˈuə4j nˈiɛ2m ɗˈaːm mˈe kˈiɲ zwˈe-ɲ tˈe4 tˈaːw . |0
19
+ dataset/Xanh24h/speaker_0/3019.wav|vˈəɪ6 kˌaːɜc bˈaː6n kˈɔɜ tˈaɜc mˈaɜc , tˈy6c sˈy6 ɲˈaː2 lˈe-5ɲ ɗˈaː6w hˈɔ6 kˈim zˈa2w kˈɔɜ t0ˌəːɜj mˈyɜc nˈaː2w ? |0
20
+ dataset/Xanh24h/speaker_0/3020.wav|tʃwˈiɛn zˈaː tʃˈuɜŋ t0ˈoj sˌɛ5 lˈiɛn hˈe6 vˌaː2 zˈaː4j ɗˈaːɜp tˈaɜc mˈaɜc . |0
21
+ dataset/Xanh24h/speaker_0/3022.wav|ŋwˈaː2j fˈaːɜt0 tʃˈiɛ4n kˈiɲ t0ˈeɜ , zˈaː ɗˈi2ɲ ˈoŋ fˈu2ŋ swˈən hwˈaː6t0 lˈuən ɣˈə2n mˈə5w tʃˈɔŋ vˈiɛ6c tˈy6c hˈiɛ6n tʃˈu4 tʃˈyəŋ kˌuə4 ɗˈaː4ŋ , tʃˈiɜɲ sˈe-ɜc , fˈaːɜp lwˈə6t0 kˌuə4 ɲˈaː2 nˈyəɜc vˌaː2 kˌaːɜc kwˈi ɗˈi6ɲ kˌuə4 ɗˈiə6 fˈyəŋ . |0
22
+ dataset/Xanh24h/speaker_0/3023.wav|t0wˈi ɲˈiɛn , tʃˈɔŋ tˈi6 tʃˈyə2ŋ kˈe-6ɲ tʃˈe-ɲ , ɗˌe4 tˈe-2ɲ kˈoŋ bˈaː6n kˈə2n fˌaː4j kˈɔɜ bˈiɜ kwˈiɛɜt0 kˈiɲ zwˈe-ɲ zˈiɛŋ kˌuə4 mˈi2ɲ . |0
23
+ dataset/Xanh24h/speaker_0/3024.wav|kˈo6ŋ vˌəːɜj t0ˈy zwˈi tʃˈiɛɜn lˈyə6c vˌaː2 sˈy6 tʃˈaː4j ŋˈiɛ6m , ˈe-ɲ ɗˌaː5 tˈe-2ɲ kˈoŋ vˌaː2 ɗˌyə6c ɲˈiɛ2w xˈe-ɜc hˈaː2ŋ ɗˈɔɜn ɲˈə6n , vˌaː2 kˈɔɜ ɗˌyə6c tˈe-2ɲ kˈoŋ sˈyɜŋ ɗˈaːɜŋ . |0
24
+ dataset/Xanh24h/speaker_0/3025.wav|tˈyɜ hˈaːj , ɲˈu kˈə2w t0ˈiɛw tˈu6 sˈiɛn kwˈɛ nˈyəɜŋ zˈəɜt0 lˈəːɜn , ɗˈa6c bˈiɛ6t0 lˌaː2 tʃˈɔŋ kˌaːɜc xˈu vˈy6c ɗˈoŋ zˈən kˈy ɣˈə2n tʃˈyə2ŋ hˈɔ6k , xˈu kˈoŋ ŋˈiɛ6p . |0
25
+ dataset/Xanh24h/speaker_0/3026.wav|bˈaː6n kˈɔɜ tˈe4 bˈaːɜn hwˈaː xˈo tʃˈy6c t0ˈiɛɜp tʃˌɔ xˈe-ɜc hˈaː2ŋ hwˌa6c bˈaːɜn bˈuən tʃˌɔ kˌaːɜc ɲˈaː2 bˈaːɜn lˈɛ4 . |0
26
+ dataset/Xanh24h/speaker_0/3027.wav|kˈɔɜ ɲˌy vˈəɪ6 tˌi2 tʃˈɛw tʃˈɛw mˈəːɜj hˈaː6n tʃˈeɜ ɗˌyə6c bˈe6ɲ t0ˈə6t0 vˌaː2 sˈiɲ tʃˈyə4ŋ xwˈɛ4 mˈe-6ɲ . |0
27
+ dataset/Xanh24h/speaker_0/3028.wav|nˌeɜw lˌaː2 zˈɔ2ŋ kˈaːɜ ɲˈə6p xˈə4w tˌi2 zˈaːɜ tˈe-2ɲ zˈəɜt0 ɗˈaɜt0 ɗˈɔ4 , xˌoŋ fˌaː4j ˈaːj kˈu5ŋ kˈɔɜ ɗˈiɛ2w kˈiɛ6n mˈuə . |0
28
+ dataset/Xanh24h/speaker_0/3029.wav|lˈaɜp ɗˈa6t0 hˈe6 tˈoɜŋ ɗˈiɛ6n , nˈyəɜc , tˈoɜŋ zˈɔɜ , twˈaːɜt0 nˈyəɜc . |0
29
+ dataset/Xanh24h/speaker_0/3032.wav|bˈaː6n kˈɔɜ tˈe4 kˈiɲ zwˈe-ɲ kˌaːɜc sˈaː4n fˈə4m mˈəːɜj zˈaː mˈaɜt0 , sˈaː4n fˈə4m lˈiɛn kwˈaːn ɗˌeɜn kˌaːɜc zˈy6 kˈiɛ6n nˈo4j bˈə6t0 . |0
30
+ dataset/Xanh24h/speaker_0/3033.wav|vˌəːɜj lˈyə6ŋ ŋˈyə2j zˈu2ŋ ɗˈoŋ ɗˈaː4w vˌaː2 ɗˈaː zˈaː6ŋ , tˈɪk tˈɒk lˌaː2 mˈo6t0 kˈeɲ t0ˈiɛɜp tˈi6 hˈiɛ6w kwˈaː4 ɗˌe4 t0ˈiɛɜp kˈə6n vˌəːɜj ɗˈoŋ ɗˈaː4w xˈe-ɜc hˈaː2ŋ t0ˈiɛ2m nˈaŋ . |0
31
+ dataset/Xanh24h/speaker_0/3035.wav|ɗˈaː2w tˈeɜ kˈɔɜ tˈe4 kˈɔɜ zˈaːɜŋ tʃˈy6c , zˈaːɜŋ hwˈe-2ɲ , zˈaːɜŋ t0ˈaːm ɗˈaː , zˈaːɜŋ hˈaː6c mˈaːj . |0
32
+ dataset/Xanh24h/speaker_0/3036.wav|tˈɛw t0ˈəː2 ʒˈɔŋˈaːn ˈɪnbəʊ kˌuə4 hˈaː2n kˈuəɜc tʃˌɔ bˈiɛɜt0 , tʃˈɔŋ sˈoɜ kˌaːɜc mˈa6t0 hˈaː2ŋ sˈaː sˈi4 mˌaː2 tʃˈiɛ2w t0ˈiɛn mˈuə , tˈiɛɜt0 bˌi6 ɗˈiɛ6n t0ˈy4 ɗˈyɜŋ ɗˈə2w vˌaː2 tʃˈiɛɜm t0ˌəːɜj bˈoɜn mˈyəj tʃˈiɜn fˈə2n tʃˈam lˈyə6ŋ t0ˈiɛw tˈu6 hˈaː2ŋ sˈaː sˈi4 kˌuə4 kˈim ʒˈɔŋˈun . |0
33
+ dataset/Xanh24h/speaker_0/3037.wav|tˈəː2j zˈaːn sˈaw ɗˈɔɜ , ˈe-ɲ lˈaː2m tˈem ɲˈiɛ2w ŋˈe2 xˈaːɜc ɲˈaw ɲˌy fˈu6c vˈu6 , lˈe5 t0ˈən , bˈoɜk vˈaːɜc ɗˌe4 lˈəɪɜ vˈoɜn mˈuə tˈem hˈaː2ŋ . |0
34
+ dataset/Xanh24h/speaker_0/3038.wav|tˈəː2j ɗˈiɛ4m tˈu hwˈe-6c lˌaː2 xˌi tʃˈaː6c tˈyɜ hˈaːj vˈyə2 ɲˈuɜ lˈen . |0
35
+ dataset/Xanh24h/speaker_0/3039.wav|bˈaː6n kˈɔɜ tˈe4 bˈaːɜn ɗˈo2 tʃˈaːŋ tʃˈiɜ t0ˈeɜt0 ŋwˈiɛn ɗˈaːɜn hˈandmeɪd tʃˈy6c t0ˈiɛɜp tʃˌɔ ŋˈyə2j t0ˈiɛw zˈu2ŋ hwˌa6c tˈoŋ kwˈaː kˌaːɜc ɲˈaː2 bˈaːɜn lˈɛ4 . |0
36
+ dataset/Xanh24h/speaker_0/3041.wav|tʃˈɔŋ t0ˈi2ɲ hˈi2ɲ tˈi6 tʃˈyə2ŋ hˈiɛ6n nˈaj , tˈy6c fˈə4m vˌə5n lˌaː2 ŋˈe-2ɲ hˈaː2ŋ ɗˈyɜŋ ɗˈə2w vˈe2 lˈəː6j ɲwˈə6n tʃˌɔ ɲˌy5ŋ ɲˈaː2 ɗˈə2w t0ˈy tˈoŋ tˈaːɜj . |0
37
+ dataset/Xanh24h/speaker_0/3042.wav|tˈyɜc ˈan kˌuə4 tʃˈuɜŋ bˈaːw ɣˈo2m tˈɔɜk vˌaː2 kˌaːɜc lwˈaː6j zˈaw . |0
38
+ dataset/Xanh24h/speaker_0/3043.wav|lwˈaː2j tʃˈɛw tʃˈɛw kˈɔɜ kˈiɜc tˈyəɜc xˈaːɜ xˈiɛm t0ˈoɜn , vˌəːɜj tʃˈiɛ2w zˈaː2j tˈən ɗˌeɜn ɗˈə2w lˌaː2 bˈoɜn mˈyəj hˈaːj ɗˌeɜn bˈoɜn mˈyəj t0ˈaːɜm sˈaŋt0ˈimˈɛɜt0 , tʃˈɔŋ xˌi tʃˈɔ6ŋ lˈyə6ŋ kˌuə4 tʃˈuɜŋ tʃˈi4 t0ˌy2 xˌoŋ fˈəɪ4 bˈa4j ɗˌeɜn hˈaːj kˈilˈoɣˈaːm , lˈoŋ tʃˈen tˈən kˈɔɜ mˈa2w nˈə1w vˌaː2 zˈyəɜj bˈu6ŋ kˈɔɜ mˈa2w tʃˈaɜŋ hwˌa6c vˈaː2ŋ ɲˈaː6t0 . |0
39
+ dataset/Xanh24h/speaker_0/3044.wav|kˌaːɜc bˈyəɜc tˈy6c hˈiɛ6n mˈo6t0 . ŋˈiɛn kˈiɜw tˈi6 tʃˈyə2ŋ . |0
40
+ dataset/Xanh24h/speaker_0/3046.wav|ɗˈiɛ2w kwˈaːn tʃˈɔ6ŋ lˌaː2 fˌaː4j tʃˈɔ6n kˈaːɜ kˈɔɜ tˈi6t0 sˈan tʃˈaɜc . |0
41
+ dataset/Xanh24h/speaker_0/3047.wav|kˌaːɜc mˈa6t0 hˈaː2ŋ ˈəː4 ɗˈəɪ ɗˌyə6c tʃˈɔ6n lˈɔ6k bˌəː4j ɲˌy5ŋ ŋˈyə2j kˈiɲ zwˈe-ɲ kˈɔɜ kˈiɲ ŋˈiɛ6m , ɗˈaː4m bˈaː4w tʃˈəɜt0 lˈyə6ŋ vˌaː2 ɗˈaː zˈaː6ŋ vˈe2 mˈə5w mˈaː5 . |0
42
+ dataset/Xanh24h/speaker_0/3048.wav|t0ˈiɛɜp tˈi6 kwˈaː ˈiːmeɪl lˌaː2 mˈo6t0 kˈe-ɜc hˈiɛ6w kwˈaː4 ɗˌe4 t0ˈiɛɜp kˈə6n xˈe-ɜc hˈaː2ŋ ɗˌaː5 ɗˈaŋ kˈiɜ ɲˈə6n tˈoŋ t0ˈin t0ˌy2 bˈaː6n . |0
43
+ dataset/Xanh24h/speaker_0/3049.wav|zˈaː ɗˈi2ɲ ˈe-ɲ ɗˌaː5 tˈiɛɜt0 lˈə6p mˈo6t0 tʃˈaːŋ tʃˈaː6j nˈuəj tˈɔ4 tˈyəŋ fˈə4m . |0
44
+ dataset/Xanh24h/speaker_0/3050.wav|vˈe2 sˈaw , mˈɔɜn ˈan ɗˌyə6c mˌɔ6j ŋˈyə2j xˈɛn ŋˈɔn , ɲˈiɛ2w ŋˈyə2j ɲˈə6n sˈɛɜt0 fˈu2 hˈəː6p vˌəːɜj sˈu hˈyəɜŋ tˈy6c fˈə4m zˈyə5 mˈuə2 zˈi6c . |0
45
+ dataset/Xanh24h/speaker_0/3051.wav|tˈiɛɜt0 kˈeɜ vˌaː2 tʃˈaːŋ tʃˈiɜ nˈo6j tˈəɜt0 tʃˌɔ kˈyə4 hˈaː2ŋ . |0
46
+ dataset/Xanh24h/speaker_0/3052.wav|hˈɔ6 ˈyə tʃˈuə6ŋ ɲˌy5ŋ lwˈaː6j hˈaː4j sˈaː4n nˈaː2w vˌaː2 mˈyɜc zˈaːɜ mˌaː2 hˈɔ6 sˈa5n lˈɔ2ŋ tʃˈi tʃˈaː4 lˌaː2 bˈaːw ɲˈiɛw . |0
47
+ dataset/Xanh24h/speaker_0/3053.wav|tˈi6t0 ɣˈaː2 kˈi2 lˈən kˈɔɜ zˈaːɜ tʃˈi6 kˈaːw , ɗˌyə6c ɲˈiɛ2w ŋˈyə2j ˈyə tʃˈuə6ŋ . |0
48
+ dataset/Xanh24h/speaker_0/3054.wav|vˌaː2 vˈu6 tˈu t0ˌy2 tˈaːɜŋ bˈa4j ɗˌeɜn tˈaːɜŋ tʃˈiɜn . |0
49
+ dataset/Xanh24h/speaker_0/3055.wav|ɗˈəɪ kˈu5ŋ lˌaː2 t0ˈiɛ2n ɗˈe2 tˈuɜc ɗˈəɪ4 ɲˈiɛ2w ŋˈyə2j tʃˈɔ6n , ɲˌy lˌaː2 mˈo6t0 kˈoŋ vˈiɛ6c bˈaːɜn hˈaː2ŋ ŋˈaɜn hˈaː6n ɗˌe4 kˈiɛɜm tˈem tˈu ɲˈə6p . |0
50
+ dataset/Xanh24h/speaker_0/3056.wav|bˈaː6n nˌen lˈyə6 tʃˈɔ6n ŋwˈiɛn lˈiɛ6w tʃˈəɜt0 lˈyə6ŋ , ɗˈaː zˈaː6ŋ , ɗˈaː4m bˈaː4w vˈe6 sˈiɲ ˈaːn t0wˈaː2n tˈy6c fˈə4m ɗˌe4 t0ˈaː6w zˈaː ɲˌy5ŋ sˈaː4n fˈə4m tˈəːm ŋˈɔn , hˈəɜp zˈə5n . |0
51
+ dataset/Xanh24h/speaker_0/3057.wav|bˈen kˈe-6ɲ ɗˈɔɜ , kˌɔ2n t0ˈi2m hˈiɛ4w tˈem ɲˌy5ŋ kˈiɛɜn tˈyɜc vˌaː2 kˈi5 twˈə6t0 tʃˈan nˈuəj tʃˈen sˈe-ɜc bˈaːɜw tˌevˈe . |0
52
+ dataset/Xanh24h/speaker_0/3058.wav|ɗˌeɜn vˌəːɜj vˈɪdɪəʊ nˈa2j , t0ˈaː2j tʃˈiɜɲ kˈiɲ zwˈe-ɲ sˈin ɣˈy4j ɗˌeɜn kˌaːɜc bˈaː6n kˈə1w tʃwˈiɛ6n vˈe2 tʃˈaː2ŋ tʃˈaːj bˈɔ4 ŋˈe2 kˈi5 sˈy kˈiɛɜm t0ˈiɛ2n t0ˈi4 mˌo5j nˈam ɲˈəː2 ŋˈe2 nˈuəj kˈaːɜ kˈe-4ɲ ˈiɜt0 vˈoɜn . |0
53
+ dataset/Xanh24h/speaker_0/3059.wav|ɲˈiɛ2w xˌi sˈyɜc xwˈɛ4 kˈiɛ6t0 kwˈe6 t0ˌəːɜj mˈyɜc ˈe-ɲ fˌaː4j ɲˈə6p vˈiɛ6n , ɗˈiɛ2w tʃˈi6 zˈɔ swˈi ɲˈyə6c , lˈaːw lˈy6c ɗˌeɜn ɗˈo6 tˈo4 hwˈiɛɜt0 . |0
54
+ dataset/Xanh24h/speaker_0/3060.wav|kˈiɲ zwˈe-ɲ ɗˈo2ŋ hˈo2 kˈu5 lˌaː2 mˈo hˈi2ɲ kˈiɲ zwˈe-ɲ ɗˌyə6c ɲˈiɛ2w ŋˈyə2j kwˈaːn t0ˈəm , ɗˈa6c bˈiɛ6t0 lˌaː2 ɲˌy5ŋ ŋˈyə2j ˈiɛw tˈiɜc sˈiw t0ˈə2m ɗˈo2ŋ hˈo2 . |0
55
+ dataset/Xanh24h/speaker_0/3061.wav|lˈyə6ŋ t0ˈom nˈuəj tʃˈɔŋ zˈuə6ŋ lˈuəɜ kˈə2n ɗˌyə6c kˈiɛ4m swˈaːɜt0 tʃˈa6t0 tʃˈɛ5 ɗˌe4 tʃˈe-ɜɲ t0ˈi2ɲ tʃˈaː6ŋ t0ˈom ˈan lˈuəɜ . |0
56
+ dataset/Xanh24h/speaker_0/3062.wav|zˈɔ ɗˈɔɜ , lˈəː6j ɲwˈə6n t0ˌy2 kˈiɲ zwˈe-ɲ kˈə1w ɗˈoɜj , tʃˈe-ɲ ˈe-4ɲ t0ˈeɜt0 tˈyə2ŋ zˈəɜt0 kˈaːw . |0
57
+ dataset/Xanh24h/speaker_0/3063.wav|zˈi6c vˈu6 nˈa2j ɗˈaːɜp ˈyɜŋ ɲˈu kˈə2w kˌuə4 kˌaːɜc zwˈe-ɲ ŋˈiɛ6p , hˈo6 kˈiɲ zwˈe-ɲ mˈuəɜn bˈa2j mˈəm kˈuɜŋ tˈə2n t0ˈaː2j tʃˈuɜ ɗˈaːɜw , tʃwˈə4n , fˈɔŋ t0ˈu6c mˌaː2 xˌoŋ kˈə2n t0ˈoɜn tˈəː2j zˈaːn , kˈoŋ sˈyɜc . |0
58
+ dataset/Xanh24h/speaker_0/3064.wav|ŋˈiɛn kˈiɜw tˈi6 tʃˈyə2ŋ ɗˌe4 t0ˈi2m hˈiɛ4w sˈu hˈyəɜŋ vˌaː2 ɲˈu kˈə2w kˌuə4 fˈu6 hwˈiɲ hˈiɛ6n nˈaj . |0
59
+ dataset/Xanh24h/speaker_0/3065.wav|vˌaː2 mˈo6t0 sˈoɜ xˌoŋ ŋˈaː6j tʃˈi t0ˈiɛ2n ɗˌe4 kˈɔɜ ɗˌyə6c ɗˈa6c kwˈiɛ2n nˈa2j . |0
60
+ dataset/Xanh24h/speaker_0/3066.wav|mˈo hˈi2ɲ nˈuəj ɣˈaː2 tˈaː4w zˈyə6c ɗˈaɜt0 ɣˈəɜp bˈaː ɣˈaː2 tˈyə2ŋ vˌə5n tʃˈaɜj hˈaː2ŋ . |0
61
+ dataset/Xanh24h/speaker_0/3067.wav|ɗˈoɜj vˌəːɜj ɲˌy5ŋ ŋˈyə2j tʃˈɔ6n mˈuə fˈu6 kˈiɛ6n tʃˌɔ tʃˈiɛɜc ɗˈiɛ6n twˈaː6j ˈiɛw kwˈiɜ kˌuə4 mˈi2ɲ , hˈɔ6 tˈyə2ŋ kˈɔɜ xˈaː4 nˈaŋ , lˈyə6 tʃˈɔ6n sˈaː4n fˈə4m tˈɛw kˌaːɜc t0ˈiɛw tʃˈiɜ nˈa2j . |0
62
+ dataset/Xanh24h/speaker_0/3068.wav|ɗˈiɛ2w nˈa2j sˌɛ5 t0ˈaː6w zˈaː mˈo6t0 ŋˈuə2n tˈu ɲˈə6p ˈo4n ɗˈi6ɲ vˌaː2 ɗˈaː zˈaː6ŋ tʃˌɔ kˈyə4 hˈaː2ŋ . |0
63
+ dataset/Xanh24h/speaker_0/3069.wav|nˈam hˈaːj ŋˈi2n xˌoŋ tʃˈam mˈyə2j t0ˈaːɜm , ˈe-ɲ kwˈiɛɜt0 ɗˈi6ɲ vˈaj vˈoɜn ŋˈən hˈaː2ŋ ɗˌe4 ɗˈə2w t0ˈy sˈəɪ zˈy6ŋ hˈe6 tˈoɜŋ bˈe4 nˈuəj t0ˈom hˈu2m bˈoŋ . |0
64
+ dataset/Xanh24h/speaker_0/3070.wav|xˌi tˈyəŋ hˈiɛ6w ɗˌaː5 kˈɔɜ tʃˈo5 ɗˈyɜŋ tʃˈen tˈi6 tʃˈyə2ŋ , tʃˈu4 ʃˈɒp kˈɔɜ tˈe4 bˈaɜt0 ɗˈə2w fˈaːɜt0 tʃˈiɛ4n tˈem ɗˈaː zˈaː6ŋ sˈaː4n fˈə4m . |0
65
+ dataset/Xanh24h/speaker_0/3071.wav|xˌi t0ˈyəɜj bˈa2ŋ t0ˈaj , hˈa5j t0ˈyəɜj vˈaː2w vˈu2ŋ zˈe5 ɗˌe4 nˈyəɜc t0ˌy2 t0ˌy2 ŋˈə2m sˈuəɜŋ ɗˈəɜt0 . |0
66
+ dataset/Xanh24h/speaker_0/3072.wav|kˈɔɜ tˈe4 nˈɔɜj , kˈiɲ zwˈe-ɲ zˈi6c vˈu6 vˈə6n t0ˈaː4j tʃˈɛ4 ˈɛm kˈɔɜ tˈi6 tʃˈyə2ŋ zˈo6ŋ ɲˌyŋ kˈu5ŋ kˈɔɜ zˈəɜt0 ɲˈiɛ2w kˈe-6ɲ tʃˈe-ɲ . |0
67
+ dataset/Xanh24h/speaker_0/3074.wav|tˈəː2j zˈaːn t0ˌy2 xˌoŋ ɗˌeɜn bˈaː mˈyəj lˈam ŋˈa2j . |0
68
+ dataset/Xanh24h/speaker_0/3075.wav|tʃˈuɜŋ zˈuɜp tʃˈɛ4 fˈaːɜt0 tʃˈiɛ4n vˈe2 mˈa6t0 tˈe4 tʃˈəɜt0 , tʃˈiɜ t0wˈe6 , kˈaː4m sˈuɜc vˌaː2 kˈi5 nˈaŋ sˈaː5 hˈo6j , zˈɔ ɗˈɔɜ ɗˈo2 tʃˈəːj tʃˈəː4 tˈe-2ɲ mˈo6t0 mˈa6t0 hˈaː2ŋ tˈiɛɜt0 ˈiɛɜw xˌoŋ tˈe4 tˈiɛɜw tʃˈɔŋ kˈuə6c sˈoɜŋ kˌuə4 tʃˈɛ4 ˈɛm . |0
whisperx/SubtitlesProcessor.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from conjunctions import get_conjunctions, get_comma
3
+ from typing import TextIO
4
+
5
+ def normal_round(n):
6
+ if n - math.floor(n) < 0.5:
7
+ return math.floor(n)
8
+ return math.ceil(n)
9
+
10
+
11
+ def format_timestamp(seconds: float, is_vtt: bool = False):
12
+
13
+ assert seconds >= 0, "non-negative timestamp expected"
14
+ milliseconds = round(seconds * 1000.0)
15
+
16
+ hours = milliseconds // 3_600_000
17
+ milliseconds -= hours * 3_600_000
18
+
19
+ minutes = milliseconds // 60_000
20
+ milliseconds -= minutes * 60_000
21
+
22
+ seconds = milliseconds // 1_000
23
+ milliseconds -= seconds * 1_000
24
+
25
+ separator = '.' if is_vtt else ','
26
+
27
+ hours_marker = f"{hours:02d}:"
28
+ return (
29
+ f"{hours_marker}{minutes:02d}:{seconds:02d}{separator}{milliseconds:03d}"
30
+ )
31
+
32
+
33
+
34
+ class SubtitlesProcessor:
35
+ def __init__(self, segments, lang, max_line_length = 45, min_char_length_splitter = 30, is_vtt = False):
36
+ self.comma = get_comma(lang)
37
+ self.conjunctions = set(get_conjunctions(lang))
38
+ self.segments = segments
39
+ self.lang = lang
40
+ self.max_line_length = max_line_length
41
+ self.min_char_length_splitter = min_char_length_splitter
42
+ self.is_vtt = is_vtt
43
+ complex_script_languages = ['th', 'lo', 'my', 'km', 'am', 'ko', 'ja', 'zh', 'ti', 'ta', 'te', 'kn', 'ml', 'hi', 'ne', 'mr', 'ar', 'fa', 'ur', 'ka']
44
+ if self.lang in complex_script_languages:
45
+ self.max_line_length = 30
46
+ self.min_char_length_splitter = 20
47
+
48
+ def estimate_timestamp_for_word(self, words, i, next_segment_start_time=None):
49
+ k = 0.25
50
+ has_prev_end = i > 0 and 'end' in words[i - 1]
51
+ has_next_start = i < len(words) - 1 and 'start' in words[i + 1]
52
+
53
+ if has_prev_end:
54
+ words[i]['start'] = words[i - 1]['end']
55
+ if has_next_start:
56
+ words[i]['end'] = words[i + 1]['start']
57
+ else:
58
+ if next_segment_start_time:
59
+ words[i]['end'] = next_segment_start_time if next_segment_start_time - words[i - 1]['end'] <= 1 else next_segment_start_time - 0.5
60
+ else:
61
+ words[i]['end'] = words[i]['start'] + len(words[i]['word']) * k
62
+
63
+ elif has_next_start:
64
+ words[i]['start'] = words[i + 1]['start'] - len(words[i]['word']) * k
65
+ words[i]['end'] = words[i + 1]['start']
66
+
67
+ else:
68
+ if next_segment_start_time:
69
+ words[i]['start'] = next_segment_start_time - 1
70
+ words[i]['end'] = next_segment_start_time - 0.5
71
+ else:
72
+ words[i]['start'] = 0
73
+ words[i]['end'] = 0
74
+
75
+
76
+
77
+ def process_segments(self, advanced_splitting=True):
78
+ subtitles = []
79
+ for i, segment in enumerate(self.segments):
80
+ next_segment_start_time = self.segments[i + 1]['start'] if i + 1 < len(self.segments) else None
81
+
82
+ if advanced_splitting:
83
+
84
+ split_points = self.determine_advanced_split_points(segment, next_segment_start_time)
85
+ subtitles.extend(self.generate_subtitles_from_split_points(segment, split_points, next_segment_start_time))
86
+ else:
87
+ words = segment['words']
88
+ for i, word in enumerate(words):
89
+ if 'start' not in word or 'end' not in word:
90
+ self.estimate_timestamp_for_word(words, i, next_segment_start_time)
91
+
92
+ subtitles.append({
93
+ 'start': segment['start'],
94
+ 'end': segment['end'],
95
+ 'text': segment['text']
96
+ })
97
+
98
+ return subtitles
99
+
100
+ def determine_advanced_split_points(self, segment, next_segment_start_time=None):
101
+ split_points = []
102
+ last_split_point = 0
103
+ char_count = 0
104
+
105
+ words = segment.get('words', segment['text'].split())
106
+ add_space = 0 if self.lang in ['zh', 'ja'] else 1
107
+
108
+ total_char_count = sum(len(word['word']) if isinstance(word, dict) else len(word) + add_space for word in words)
109
+ char_count_after = total_char_count
110
+
111
+ for i, word in enumerate(words):
112
+ word_text = word['word'] if isinstance(word, dict) else word
113
+ word_length = len(word_text) + add_space
114
+ char_count += word_length
115
+ char_count_after -= word_length
116
+
117
+ char_count_before = char_count - word_length
118
+
119
+ if isinstance(word, dict) and ('start' not in word or 'end' not in word):
120
+ self.estimate_timestamp_for_word(words, i, next_segment_start_time)
121
+
122
+ if char_count >= self.max_line_length:
123
+ midpoint = normal_round((last_split_point + i) / 2)
124
+ if char_count_before >= self.min_char_length_splitter:
125
+ split_points.append(midpoint)
126
+ last_split_point = midpoint + 1
127
+ char_count = sum(len(words[j]['word']) if isinstance(words[j], dict) else len(words[j]) + add_space for j in range(last_split_point, i + 1))
128
+
129
+ elif word_text.endswith(self.comma) and char_count_before >= self.min_char_length_splitter and char_count_after >= self.min_char_length_splitter:
130
+ split_points.append(i)
131
+ last_split_point = i + 1
132
+ char_count = 0
133
+
134
+ elif word_text.lower() in self.conjunctions and char_count_before >= self.min_char_length_splitter and char_count_after >= self.min_char_length_splitter:
135
+ split_points.append(i - 1)
136
+ last_split_point = i
137
+ char_count = word_length
138
+
139
+ return split_points
140
+
141
+
142
+ def generate_subtitles_from_split_points(self, segment, split_points, next_start_time=None):
143
+ subtitles = []
144
+
145
+ words = segment.get('words', segment['text'].split())
146
+ total_word_count = len(words)
147
+ total_time = segment['end'] - segment['start']
148
+ elapsed_time = segment['start']
149
+ prefix = ' ' if self.lang not in ['zh', 'ja'] else ''
150
+ start_idx = 0
151
+ for split_point in split_points:
152
+
153
+ fragment_words = words[start_idx:split_point + 1]
154
+ current_word_count = len(fragment_words)
155
+
156
+
157
+ if isinstance(fragment_words[0], dict):
158
+ start_time = fragment_words[0]['start']
159
+ end_time = fragment_words[-1]['end']
160
+ next_start_time_for_word = words[split_point + 1]['start'] if split_point + 1 < len(words) else None
161
+ if next_start_time_for_word and (next_start_time_for_word - end_time) <= 0.8:
162
+ end_time = next_start_time_for_word
163
+ else:
164
+ fragment = prefix.join(fragment_words).strip()
165
+ current_duration = (current_word_count / total_word_count) * total_time
166
+ start_time = elapsed_time
167
+ end_time = elapsed_time + current_duration
168
+ elapsed_time += current_duration
169
+
170
+
171
+ subtitles.append({
172
+ 'start': start_time,
173
+ 'end': end_time,
174
+ 'text': fragment if not isinstance(fragment_words[0], dict) else prefix.join(word['word'] for word in fragment_words)
175
+ })
176
+
177
+ start_idx = split_point + 1
178
+
179
+ # Handle the last fragment
180
+ if start_idx < len(words):
181
+ fragment_words = words[start_idx:]
182
+ current_word_count = len(fragment_words)
183
+
184
+ if isinstance(fragment_words[0], dict):
185
+ start_time = fragment_words[0]['start']
186
+ end_time = fragment_words[-1]['end']
187
+ else:
188
+ fragment = prefix.join(fragment_words).strip()
189
+ current_duration = (current_word_count / total_word_count) * total_time
190
+ start_time = elapsed_time
191
+ end_time = elapsed_time + current_duration
192
+
193
+ if next_start_time and (next_start_time - end_time) <= 0.8:
194
+ end_time = next_start_time
195
+
196
+ subtitles.append({
197
+ 'start': start_time,
198
+ 'end': end_time if end_time is not None else segment['end'],
199
+ 'text': fragment if not isinstance(fragment_words[0], dict) else prefix.join(word['word'] for word in fragment_words)
200
+ })
201
+
202
+ return subtitles
203
+
204
+
205
+
206
+ def save(self, filename="subtitles.srt", advanced_splitting=True):
207
+
208
+ subtitles = self.process_segments(advanced_splitting)
209
+
210
+ def write_subtitle(file, idx, start_time, end_time, text):
211
+
212
+ file.write(f"{idx}\n")
213
+ file.write(f"{start_time} --> {end_time}\n")
214
+ file.write(text + "\n\n")
215
+
216
+ with open(filename, 'w', encoding='utf-8') as file:
217
+ if self.is_vtt:
218
+ file.write("WEBVTT\n\n")
219
+
220
+ if advanced_splitting:
221
+ for idx, subtitle in enumerate(subtitles, 1):
222
+ start_time = format_timestamp(subtitle['start'], self.is_vtt)
223
+ end_time = format_timestamp(subtitle['end'], self.is_vtt)
224
+ text = subtitle['text'].strip()
225
+ write_subtitle(file, idx, start_time, end_time, text)
226
+
227
+ return len(subtitles)
whisperx/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .transcribe import load_model
2
+ from .alignment import load_align_model, align
3
+ from .audio import load_audio
4
+ from .diarize import assign_word_speakers, DiarizationPipeline
whisperx/__main__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .transcribe import cli
2
+
3
+
4
+ cli()
whisperx/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (372 Bytes). View file
 
whisperx/__pycache__/alignment.cpython-310.pyc ADDED
Binary file (12.6 kB). View file
 
whisperx/__pycache__/asr.cpython-310.pyc ADDED
Binary file (11.5 kB). View file
 
whisperx/__pycache__/audio.cpython-310.pyc ADDED
Binary file (4.46 kB). View file
 
whisperx/__pycache__/diarize.cpython-310.pyc ADDED
Binary file (2.79 kB). View file
 
whisperx/__pycache__/transcribe.cpython-310.pyc ADDED
Binary file (10.1 kB). View file
 
whisperx/__pycache__/types.cpython-310.pyc ADDED
Binary file (1.89 kB). View file
 
whisperx/__pycache__/utils.cpython-310.pyc ADDED
Binary file (13.2 kB). View file