Publish Kokoro PL/DE model catalog v1.0.0
Browse files- .gitattributes +1 -33
- .gitignore +5 -0
- LICENSE +201 -0
- README.md +129 -0
- SOURCES.lock.json +31 -0
- THIRD_PARTY_NOTICES.md +31 -0
- catalog.json +184 -0
- catalog.template.json +169 -0
- models/de/kokoro-de-fp32.onnx +3 -0
- models/de/kokoro-de-fp32.validation.json +23 -0
- models/pl/kokoro-pl-fp32.onnx +3 -0
- models/pl/kokoro-pl-fp32.validation.json +23 -0
- package-lock.json +172 -0
- package.json +13 -0
- phonemizers/de/phonemizer_de.bin +3 -0
- phonemizers/pl/phonemizer_pl.bin +3 -0
- requirements-export.txt +7 -0
- runtime/config.json +150 -0
- samples/de-anna.wav +3 -0
- samples/pl-mateusz.wav +0 -0
- schema/kokoro-catalog.schema.json +157 -0
- scripts/build_catalog.py +50 -0
- scripts/export_onnx.py +201 -0
- scripts/publish_hf.py +88 -0
- scripts/validate_package.py +159 -0
- scripts/validate_web.cjs +107 -0
- third-party/kokoro/LICENSE +201 -0
- third-party/phonemis/LICENSE +21 -0
- validation/cases.json +30 -0
- validation/package-validation.json +78 -0
- validation/web-de.json +19 -0
- validation/web-pl.json +19 -0
- voices/de/df_anna.bin +3 -0
- voices/pl/pm_mateusz.bin +3 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,3 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
| 1 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.wav filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.DS_Store
|
| 2 |
+
:memory:.ses
|
| 3 |
+
__pycache__/
|
| 4 |
+
*.pyc
|
| 5 |
+
node_modules/
|
LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
pipeline_tag: text-to-speech
|
| 4 |
+
library_name: onnxruntime
|
| 5 |
+
language:
|
| 6 |
+
- pl
|
| 7 |
+
- de
|
| 8 |
+
base_model: hexgrad/Kokoro-82M
|
| 9 |
+
tags:
|
| 10 |
+
- kokoro
|
| 11 |
+
- onnx
|
| 12 |
+
- on-device
|
| 13 |
+
- kotlin-multiplatform
|
| 14 |
+
- android
|
| 15 |
+
- jvm
|
| 16 |
+
- web
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
# Kokoro PL/DE for ONNX Runtime and Kotlin Multiplatform
|
| 20 |
+
|
| 21 |
+
Native Polish and German Kokoro-82M language packs prepared for on-device inference with ONNX
|
| 22 |
+
Runtime. The repository is organized for a client that first chooses a language and then a voice.
|
| 23 |
+
Each language can be downloaded independently; users do not need to fetch both packs.
|
| 24 |
+
|
| 25 |
+
## Available packs
|
| 26 |
+
|
| 27 |
+
| Language | Model | Voice | Model size | Phonemizer | Voice |
|
| 28 |
+
|---|---|---|---:|---:|---:|
|
| 29 |
+
| Polish (`pl-PL`) | `kokoro-pl-fp32` | Mateusz (male) | 310.5 MiB | 6.8 MiB | 510 KiB |
|
| 30 |
+
| German (`de-DE`) | `kokoro-de-fp32` | Anna (female) | 310.5 MiB | 6.8 MiB | 510 KiB |
|
| 31 |
+
|
| 32 |
+
The complete downloadable pack for one language is about 318 MiB plus tiny JSON metadata. Models
|
| 33 |
+
are FP32 to preserve quality; no quantized variant is included in version 1.0.0.
|
| 34 |
+
|
| 35 |
+
## Client flow
|
| 36 |
+
|
| 37 |
+
1. Fetch [`catalog.json`](catalog.json) from a pinned Hub revision such as `v1.0.0`.
|
| 38 |
+
2. Show `languages`, then show the selected language's `voices`.
|
| 39 |
+
3. Download only that language's `model.artifact`, `phonemizer.artifact`, the selected voice
|
| 40 |
+
`artifact`, and the shared 2.3 KiB tokenizer config.
|
| 41 |
+
4. Verify `sizeBytes` and `sha256` before activating a download.
|
| 42 |
+
5. Resolve artifact paths relative to the catalog URL, so a tagged catalog automatically keeps all
|
| 43 |
+
files on the same immutable release.
|
| 44 |
+
|
| 45 |
+
The JSON format is versioned and described by
|
| 46 |
+
[`schema/kokoro-catalog.schema.json`](schema/kokoro-catalog.schema.json). New voices can be added to
|
| 47 |
+
one language without changing the application API.
|
| 48 |
+
|
| 49 |
+
## Inference contract
|
| 50 |
+
|
| 51 |
+
The ONNX graph takes:
|
| 52 |
+
|
| 53 |
+
- `input_ids`: `int64[1, sequence_length]`, with token `0` added at both ends;
|
| 54 |
+
- `style`: `float32[1, 256]`;
|
| 55 |
+
- `speed`: `float32[1]`.
|
| 56 |
+
|
| 57 |
+
It returns a mono `float32` waveform at 24 kHz and an `int64` duration for every input token.
|
| 58 |
+
Batch size is fixed to one; sequence length is dynamic up to 510 phoneme Unicode code points plus
|
| 59 |
+
the two boundary tokens.
|
| 60 |
+
|
| 61 |
+
Voice files are raw little-endian `float32[510, 256]` matrices. Select style row
|
| 62 |
+
`phonemeCodePointCount - 1`. Count Unicode code points, not Kotlin/JVM UTF-16 code units; combining
|
| 63 |
+
marks such as the nasalization mark in `ɔ̃` count separately.
|
| 64 |
+
|
| 65 |
+
## Phonemization
|
| 66 |
+
|
| 67 |
+
The included 6.8 MiB `.bin` files are neural Protophone data for
|
| 68 |
+
[`Phonemis`](https://github.com/IgorSwat/Phonemis). They produce Kokoro-compatible IPA for Polish
|
| 69 |
+
and German without shipping eSpeak or GPL components. Phonemis itself is a small C++20 library and
|
| 70 |
+
is not embedded in these model-data files.
|
| 71 |
+
|
| 72 |
+
Android/JVM consumers can expose Phonemis through a shared native bridge. A Web client needs a
|
| 73 |
+
WebAssembly build of that bridge; this repository provides the same language data but does not ship
|
| 74 |
+
a JavaScript/Wasm wrapper.
|
| 75 |
+
|
| 76 |
+
## Validation
|
| 77 |
+
|
| 78 |
+
Both graphs pass ONNX validation, ONNX Runtime 1.29 CPU inference, and real
|
| 79 |
+
`onnxruntime-web 1.29.0` WebAssembly inference. Export validation compares each graph with its
|
| 80 |
+
PyTorch checkpoint. Token durations match exactly; waveform correlation is `0.9948` for Polish and
|
| 81 |
+
`0.9970` for German. Kokoro intentionally injects a small random excitation noise, so waveforms are
|
| 82 |
+
not expected to be bit-identical across runs.
|
| 83 |
+
|
| 84 |
+
Four natural-language runtime cases plus explicit 1-, 128-, and 510-phoneme boundary cases for
|
| 85 |
+
both languages are recorded in
|
| 86 |
+
[`validation/package-validation.json`](validation/package-validation.json). Generated previews are
|
| 87 |
+
available as [`samples/pl-mateusz.wav`](samples/pl-mateusz.wav) and
|
| 88 |
+
[`samples/de-anna.wav`](samples/de-anna.wav).
|
| 89 |
+
|
| 90 |
+
To repeat the local checks after rebuilding the graphs:
|
| 91 |
+
|
| 92 |
+
```bash
|
| 93 |
+
python scripts/build_catalog.py
|
| 94 |
+
python scripts/validate_package.py
|
| 95 |
+
npm install
|
| 96 |
+
npm run validate:web
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
Maintainers can publish the fully validated folder after authenticating with the Hugging Face CLI:
|
| 100 |
+
|
| 101 |
+
```bash
|
| 102 |
+
python scripts/publish_hf.py <namespace>/kokoro-kmp-models
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
The publisher excludes local dependencies and refuses to overwrite an existing immutable release
|
| 106 |
+
tag with a different commit.
|
| 107 |
+
|
| 108 |
+
## Sources and reproducibility
|
| 109 |
+
|
| 110 |
+
All source repositories, immutable revisions, and source checksums are pinned in
|
| 111 |
+
[`SOURCES.lock.json`](SOURCES.lock.json). `scripts/export_onnx.py` exports a self-contained opset 17
|
| 112 |
+
graph and rejects outputs that fail ONNX validation or diverge materially from PyTorch.
|
| 113 |
+
|
| 114 |
+
## Limitations
|
| 115 |
+
|
| 116 |
+
- Version 1.0.0 contains one native voice per language.
|
| 117 |
+
- Polish and German use separate fine-tuned model weights; a voice file cannot turn one language
|
| 118 |
+
model into the other.
|
| 119 |
+
- Text normalization and pronunciation still need application-level tests for names,
|
| 120 |
+
abbreviations, mixed-language text, and unusual numbers.
|
| 121 |
+
- The graphs are intentionally unquantized and prioritize quality over download size.
|
| 122 |
+
|
| 123 |
+
## License
|
| 124 |
+
|
| 125 |
+
Kokoro, the fine-tuned checkpoints, the converted ONNX graphs, speaker embeddings, and this
|
| 126 |
+
packaging remain under **Apache License 2.0**. The repository license has not been changed.
|
| 127 |
+
|
| 128 |
+
Phonemis assets remain under their upstream **MIT License**. See
|
| 129 |
+
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) for exact provenance and license boundaries.
|
SOURCES.lock.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"kokoroBase": {
|
| 3 |
+
"repository": "hexgrad/Kokoro-82M",
|
| 4 |
+
"revision": "f3ff3571791e39611d31c381e3a41a3af07b4987",
|
| 5 |
+
"files": {
|
| 6 |
+
"config.json": "5abb01e2403b072bf03d04fde160443e209d7a0dad49a423be15196b9b43c17f"
|
| 7 |
+
}
|
| 8 |
+
},
|
| 9 |
+
"languageModels": {
|
| 10 |
+
"repository": "software-mansion/react-native-executorch-kokoro",
|
| 11 |
+
"revision": "3744b57964eab7df6e8c48f0b84badb29e14df07",
|
| 12 |
+
"files": {
|
| 13 |
+
"finetunes/kokoro_polish_converted.pth": "e3202dc4d1f6e65dddff8a8e8d2e091ce9a3a66cf989c6c581a81b2f1969af49",
|
| 14 |
+
"finetunes/kokoro_german_converted.pth": "b8b2ab322963e7662c6036035c76c34a6a5582f814917407c94d632a1c930f71",
|
| 15 |
+
"voices/pm_mateusz.bin": "dc8f2919ede945e6962310b5204b912e64689d5698c571822bf75ad704870cb4",
|
| 16 |
+
"voices/df_anna.bin": "d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b"
|
| 17 |
+
}
|
| 18 |
+
},
|
| 19 |
+
"phonemis": {
|
| 20 |
+
"repository": "IgorSwat/Phonemis",
|
| 21 |
+
"revision": "71eb1ce33bd586d38cbac037843b8539d7829c3b",
|
| 22 |
+
"files": {
|
| 23 |
+
"data/pl/phonemizer_pl.bin": "ec85f4dc2c4ac7a72ff88b98b0664a4ed887bd15c0d5add2eb1d6a6ee05b73f2",
|
| 24 |
+
"data/de/phonemizer_de.bin": "4888dc7e54dc66098551555096562063364091fc246da0d057b629587bedaa0b"
|
| 25 |
+
}
|
| 26 |
+
},
|
| 27 |
+
"exporter": {
|
| 28 |
+
"repository": "SuvioMedia/kokoro",
|
| 29 |
+
"revision": "8ee8ec3179c38990dd0564fb703c4deb68be58e9"
|
| 30 |
+
}
|
| 31 |
+
}
|
THIRD_PARTY_NOTICES.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Third-party notices
|
| 2 |
+
|
| 3 |
+
This repository keeps the Kokoro licensing intact. Packaging and conversion do not replace or
|
| 4 |
+
relicense upstream work.
|
| 5 |
+
|
| 6 |
+
## Kokoro and the Polish/German fine-tunes
|
| 7 |
+
|
| 8 |
+
- Base model and architecture: [`hexgrad/Kokoro-82M`](https://huggingface.co/hexgrad/Kokoro-82M),
|
| 9 |
+
revision `f3ff3571791e39611d31c381e3a41a3af07b4987`.
|
| 10 |
+
- Polish and German converted checkpoints and speaker embeddings:
|
| 11 |
+
[`software-mansion/react-native-executorch-kokoro`](https://huggingface.co/software-mansion/react-native-executorch-kokoro),
|
| 12 |
+
revision `3744b57964eab7df6e8c48f0b84badb29e14df07`.
|
| 13 |
+
- ONNX exporter: [`SuvioMedia/kokoro`](https://github.com/SuvioMedia/kokoro), revision
|
| 14 |
+
`8ee8ec3179c38990dd0564fb703c4deb68be58e9`.
|
| 15 |
+
|
| 16 |
+
These materials and the resulting ONNX model files are distributed under Apache License 2.0.
|
| 17 |
+
The license text is available in [`LICENSE`](LICENSE) and [`third-party/kokoro/LICENSE`](third-party/kokoro/LICENSE).
|
| 18 |
+
|
| 19 |
+
## Phonemis
|
| 20 |
+
|
| 21 |
+
The files below come from [`IgorSwat/Phonemis`](https://github.com/IgorSwat/Phonemis), revision
|
| 22 |
+
`71eb1ce33bd586d38cbac037843b8539d7829c3b`:
|
| 23 |
+
|
| 24 |
+
- `phonemizers/pl/phonemizer_pl.bin`
|
| 25 |
+
- `phonemizers/de/phonemizer_de.bin`
|
| 26 |
+
|
| 27 |
+
Phonemis is distributed under the MIT License. Its unchanged license text is available in
|
| 28 |
+
[`third-party/phonemis/LICENSE`](third-party/phonemis/LICENSE). The MIT exception applies to
|
| 29 |
+
the Phonemis files; it does not alter the Apache-2.0 license of Kokoro.
|
| 30 |
+
|
| 31 |
+
Exact source file hashes are recorded in [`SOURCES.lock.json`](SOURCES.lock.json).
|
catalog.json
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "schema/kokoro-catalog.schema.json",
|
| 3 |
+
"schemaVersion": 1,
|
| 4 |
+
"catalogVersion": "1.0.0",
|
| 5 |
+
"distribution": {
|
| 6 |
+
"provider": "huggingface",
|
| 7 |
+
"artifactResolution": "relative-to-catalog",
|
| 8 |
+
"recommendedRevision": "v1.0.0"
|
| 9 |
+
},
|
| 10 |
+
"license": "Apache-2.0",
|
| 11 |
+
"modelFamily": "kokoro-82m",
|
| 12 |
+
"audio": {
|
| 13 |
+
"sampleRateHz": 24000,
|
| 14 |
+
"channels": 1,
|
| 15 |
+
"sampleType": "float32"
|
| 16 |
+
},
|
| 17 |
+
"runtime": {
|
| 18 |
+
"engine": "onnxruntime",
|
| 19 |
+
"opset": 17,
|
| 20 |
+
"batchSize": 1,
|
| 21 |
+
"maxPhonemeCodePoints": 510,
|
| 22 |
+
"durationToSamplesFactor": 600,
|
| 23 |
+
"inputs": [
|
| 24 |
+
{
|
| 25 |
+
"name": "input_ids",
|
| 26 |
+
"type": "int64",
|
| 27 |
+
"shape": [
|
| 28 |
+
1,
|
| 29 |
+
"sequence_length"
|
| 30 |
+
]
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"name": "style",
|
| 34 |
+
"type": "float32",
|
| 35 |
+
"shape": [
|
| 36 |
+
1,
|
| 37 |
+
256
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"name": "speed",
|
| 42 |
+
"type": "float32",
|
| 43 |
+
"shape": [
|
| 44 |
+
1
|
| 45 |
+
]
|
| 46 |
+
}
|
| 47 |
+
],
|
| 48 |
+
"outputs": [
|
| 49 |
+
{
|
| 50 |
+
"name": "waveform",
|
| 51 |
+
"type": "float32",
|
| 52 |
+
"shape": [
|
| 53 |
+
"num_samples"
|
| 54 |
+
]
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"name": "duration",
|
| 58 |
+
"type": "int64",
|
| 59 |
+
"shape": [
|
| 60 |
+
"sequence_length"
|
| 61 |
+
]
|
| 62 |
+
}
|
| 63 |
+
],
|
| 64 |
+
"tokenizer": {
|
| 65 |
+
"bosTokenId": 0,
|
| 66 |
+
"eosTokenId": 0,
|
| 67 |
+
"vocabularyField": "vocab",
|
| 68 |
+
"artifact": {
|
| 69 |
+
"path": "runtime/config.json",
|
| 70 |
+
"mediaType": "application/json",
|
| 71 |
+
"sizeBytes": 2351,
|
| 72 |
+
"sha256": "5abb01e2403b072bf03d04fde160443e209d7a0dad49a423be15196b9b43c17f"
|
| 73 |
+
}
|
| 74 |
+
},
|
| 75 |
+
"voiceStyle": {
|
| 76 |
+
"format": "raw-float32-le",
|
| 77 |
+
"shape": [
|
| 78 |
+
510,
|
| 79 |
+
256
|
| 80 |
+
],
|
| 81 |
+
"rowSelection": "phoneme_code_point_count_minus_one"
|
| 82 |
+
}
|
| 83 |
+
},
|
| 84 |
+
"languages": [
|
| 85 |
+
{
|
| 86 |
+
"id": "pl",
|
| 87 |
+
"locale": "pl-PL",
|
| 88 |
+
"displayName": "Polish",
|
| 89 |
+
"nativeName": "polski",
|
| 90 |
+
"model": {
|
| 91 |
+
"id": "kokoro-pl-fp32",
|
| 92 |
+
"format": "onnx",
|
| 93 |
+
"precision": "fp32",
|
| 94 |
+
"artifact": {
|
| 95 |
+
"path": "models/pl/kokoro-pl-fp32.onnx",
|
| 96 |
+
"mediaType": "application/onnx",
|
| 97 |
+
"sizeBytes": 325563781,
|
| 98 |
+
"sha256": "66637ea517e8ea4fea6c473c18a6f3b4fe982a8e7eb3879bb5f8250c7dc5679a"
|
| 99 |
+
},
|
| 100 |
+
"validation": {
|
| 101 |
+
"path": "models/pl/kokoro-pl-fp32.validation.json",
|
| 102 |
+
"mediaType": "application/json",
|
| 103 |
+
"sizeBytes": 1007,
|
| 104 |
+
"sha256": "63768a6dde6c8dabecec1ad673b3819c8d707f8e3cf565dda40950ec9c5c4476"
|
| 105 |
+
}
|
| 106 |
+
},
|
| 107 |
+
"phonemizer": {
|
| 108 |
+
"engine": "phonemis-protophone",
|
| 109 |
+
"language": "pl",
|
| 110 |
+
"license": "MIT",
|
| 111 |
+
"sourceRevision": "71eb1ce33bd586d38cbac037843b8539d7829c3b",
|
| 112 |
+
"artifact": {
|
| 113 |
+
"path": "phonemizers/pl/phonemizer_pl.bin",
|
| 114 |
+
"mediaType": "application/octet-stream",
|
| 115 |
+
"sizeBytes": 7094120,
|
| 116 |
+
"sha256": "ec85f4dc2c4ac7a72ff88b98b0664a4ed887bd15c0d5add2eb1d6a6ee05b73f2"
|
| 117 |
+
}
|
| 118 |
+
},
|
| 119 |
+
"voices": [
|
| 120 |
+
{
|
| 121 |
+
"id": "mateusz",
|
| 122 |
+
"displayName": "Mateusz",
|
| 123 |
+
"gender": "male",
|
| 124 |
+
"artifact": {
|
| 125 |
+
"path": "voices/pl/pm_mateusz.bin",
|
| 126 |
+
"mediaType": "application/octet-stream",
|
| 127 |
+
"sizeBytes": 522240,
|
| 128 |
+
"sha256": "dc8f2919ede945e6962310b5204b912e64689d5698c571822bf75ad704870cb4"
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
],
|
| 132 |
+
"previewAudioPath": "samples/pl-mateusz.wav"
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"id": "de",
|
| 136 |
+
"locale": "de-DE",
|
| 137 |
+
"displayName": "German",
|
| 138 |
+
"nativeName": "Deutsch",
|
| 139 |
+
"model": {
|
| 140 |
+
"id": "kokoro-de-fp32",
|
| 141 |
+
"format": "onnx",
|
| 142 |
+
"precision": "fp32",
|
| 143 |
+
"artifact": {
|
| 144 |
+
"path": "models/de/kokoro-de-fp32.onnx",
|
| 145 |
+
"mediaType": "application/onnx",
|
| 146 |
+
"sizeBytes": 325563781,
|
| 147 |
+
"sha256": "ecea710e0e4481d5930fc3486c5ed1c3dfd2dc752c2beb676135343d0236b1f3"
|
| 148 |
+
},
|
| 149 |
+
"validation": {
|
| 150 |
+
"path": "models/de/kokoro-de-fp32.validation.json",
|
| 151 |
+
"mediaType": "application/json",
|
| 152 |
+
"sizeBytes": 1142,
|
| 153 |
+
"sha256": "b9c7ff15e5be4824ff9e608d26ec21026d9e33ee3d4b430ad8ffecaa7af9e2d8"
|
| 154 |
+
}
|
| 155 |
+
},
|
| 156 |
+
"phonemizer": {
|
| 157 |
+
"engine": "phonemis-protophone",
|
| 158 |
+
"language": "de",
|
| 159 |
+
"license": "MIT",
|
| 160 |
+
"sourceRevision": "71eb1ce33bd586d38cbac037843b8539d7829c3b",
|
| 161 |
+
"artifact": {
|
| 162 |
+
"path": "phonemizers/de/phonemizer_de.bin",
|
| 163 |
+
"mediaType": "application/octet-stream",
|
| 164 |
+
"sizeBytes": 7094120,
|
| 165 |
+
"sha256": "4888dc7e54dc66098551555096562063364091fc246da0d057b629587bedaa0b"
|
| 166 |
+
}
|
| 167 |
+
},
|
| 168 |
+
"voices": [
|
| 169 |
+
{
|
| 170 |
+
"id": "anna",
|
| 171 |
+
"displayName": "Anna",
|
| 172 |
+
"gender": "female",
|
| 173 |
+
"artifact": {
|
| 174 |
+
"path": "voices/de/df_anna.bin",
|
| 175 |
+
"mediaType": "application/octet-stream",
|
| 176 |
+
"sizeBytes": 522240,
|
| 177 |
+
"sha256": "d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b"
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
],
|
| 181 |
+
"previewAudioPath": "samples/de-anna.wav"
|
| 182 |
+
}
|
| 183 |
+
]
|
| 184 |
+
}
|
catalog.template.json
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "schema/kokoro-catalog.schema.json",
|
| 3 |
+
"schemaVersion": 1,
|
| 4 |
+
"catalogVersion": "1.0.0",
|
| 5 |
+
"distribution": {
|
| 6 |
+
"provider": "huggingface",
|
| 7 |
+
"artifactResolution": "relative-to-catalog",
|
| 8 |
+
"recommendedRevision": "v1.0.0"
|
| 9 |
+
},
|
| 10 |
+
"license": "Apache-2.0",
|
| 11 |
+
"modelFamily": "kokoro-82m",
|
| 12 |
+
"audio": {
|
| 13 |
+
"sampleRateHz": 24000,
|
| 14 |
+
"channels": 1,
|
| 15 |
+
"sampleType": "float32"
|
| 16 |
+
},
|
| 17 |
+
"runtime": {
|
| 18 |
+
"engine": "onnxruntime",
|
| 19 |
+
"opset": 17,
|
| 20 |
+
"batchSize": 1,
|
| 21 |
+
"maxPhonemeCodePoints": 510,
|
| 22 |
+
"durationToSamplesFactor": 600,
|
| 23 |
+
"inputs": [
|
| 24 |
+
{
|
| 25 |
+
"name": "input_ids",
|
| 26 |
+
"type": "int64",
|
| 27 |
+
"shape": [1, "sequence_length"]
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"name": "style",
|
| 31 |
+
"type": "float32",
|
| 32 |
+
"shape": [1, 256]
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"name": "speed",
|
| 36 |
+
"type": "float32",
|
| 37 |
+
"shape": [1]
|
| 38 |
+
}
|
| 39 |
+
],
|
| 40 |
+
"outputs": [
|
| 41 |
+
{
|
| 42 |
+
"name": "waveform",
|
| 43 |
+
"type": "float32",
|
| 44 |
+
"shape": ["num_samples"]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"name": "duration",
|
| 48 |
+
"type": "int64",
|
| 49 |
+
"shape": ["sequence_length"]
|
| 50 |
+
}
|
| 51 |
+
],
|
| 52 |
+
"tokenizer": {
|
| 53 |
+
"bosTokenId": 0,
|
| 54 |
+
"eosTokenId": 0,
|
| 55 |
+
"vocabularyField": "vocab",
|
| 56 |
+
"artifact": {
|
| 57 |
+
"$artifact": {
|
| 58 |
+
"path": "runtime/config.json",
|
| 59 |
+
"mediaType": "application/json"
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"voiceStyle": {
|
| 64 |
+
"format": "raw-float32-le",
|
| 65 |
+
"shape": [510, 256],
|
| 66 |
+
"rowSelection": "phoneme_code_point_count_minus_one"
|
| 67 |
+
}
|
| 68 |
+
},
|
| 69 |
+
"languages": [
|
| 70 |
+
{
|
| 71 |
+
"id": "pl",
|
| 72 |
+
"locale": "pl-PL",
|
| 73 |
+
"displayName": "Polish",
|
| 74 |
+
"nativeName": "polski",
|
| 75 |
+
"model": {
|
| 76 |
+
"id": "kokoro-pl-fp32",
|
| 77 |
+
"format": "onnx",
|
| 78 |
+
"precision": "fp32",
|
| 79 |
+
"artifact": {
|
| 80 |
+
"$artifact": {
|
| 81 |
+
"path": "models/pl/kokoro-pl-fp32.onnx",
|
| 82 |
+
"mediaType": "application/onnx"
|
| 83 |
+
}
|
| 84 |
+
},
|
| 85 |
+
"validation": {
|
| 86 |
+
"$artifact": {
|
| 87 |
+
"path": "models/pl/kokoro-pl-fp32.validation.json",
|
| 88 |
+
"mediaType": "application/json"
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
},
|
| 92 |
+
"phonemizer": {
|
| 93 |
+
"engine": "phonemis-protophone",
|
| 94 |
+
"language": "pl",
|
| 95 |
+
"license": "MIT",
|
| 96 |
+
"sourceRevision": "71eb1ce33bd586d38cbac037843b8539d7829c3b",
|
| 97 |
+
"artifact": {
|
| 98 |
+
"$artifact": {
|
| 99 |
+
"path": "phonemizers/pl/phonemizer_pl.bin",
|
| 100 |
+
"mediaType": "application/octet-stream"
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"voices": [
|
| 105 |
+
{
|
| 106 |
+
"id": "mateusz",
|
| 107 |
+
"displayName": "Mateusz",
|
| 108 |
+
"gender": "male",
|
| 109 |
+
"artifact": {
|
| 110 |
+
"$artifact": {
|
| 111 |
+
"path": "voices/pl/pm_mateusz.bin",
|
| 112 |
+
"mediaType": "application/octet-stream"
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
+
],
|
| 117 |
+
"previewAudioPath": "samples/pl-mateusz.wav"
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"id": "de",
|
| 121 |
+
"locale": "de-DE",
|
| 122 |
+
"displayName": "German",
|
| 123 |
+
"nativeName": "Deutsch",
|
| 124 |
+
"model": {
|
| 125 |
+
"id": "kokoro-de-fp32",
|
| 126 |
+
"format": "onnx",
|
| 127 |
+
"precision": "fp32",
|
| 128 |
+
"artifact": {
|
| 129 |
+
"$artifact": {
|
| 130 |
+
"path": "models/de/kokoro-de-fp32.onnx",
|
| 131 |
+
"mediaType": "application/onnx"
|
| 132 |
+
}
|
| 133 |
+
},
|
| 134 |
+
"validation": {
|
| 135 |
+
"$artifact": {
|
| 136 |
+
"path": "models/de/kokoro-de-fp32.validation.json",
|
| 137 |
+
"mediaType": "application/json"
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
},
|
| 141 |
+
"phonemizer": {
|
| 142 |
+
"engine": "phonemis-protophone",
|
| 143 |
+
"language": "de",
|
| 144 |
+
"license": "MIT",
|
| 145 |
+
"sourceRevision": "71eb1ce33bd586d38cbac037843b8539d7829c3b",
|
| 146 |
+
"artifact": {
|
| 147 |
+
"$artifact": {
|
| 148 |
+
"path": "phonemizers/de/phonemizer_de.bin",
|
| 149 |
+
"mediaType": "application/octet-stream"
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
},
|
| 153 |
+
"voices": [
|
| 154 |
+
{
|
| 155 |
+
"id": "anna",
|
| 156 |
+
"displayName": "Anna",
|
| 157 |
+
"gender": "female",
|
| 158 |
+
"artifact": {
|
| 159 |
+
"$artifact": {
|
| 160 |
+
"path": "voices/de/df_anna.bin",
|
| 161 |
+
"mediaType": "application/octet-stream"
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
],
|
| 166 |
+
"previewAudioPath": "samples/de-anna.wav"
|
| 167 |
+
}
|
| 168 |
+
]
|
| 169 |
+
}
|
models/de/kokoro-de-fp32.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ecea710e0e4481d5930fc3486c5ed1c3dfd2dc752c2beb676135343d0236b1f3
|
| 3 |
+
size 325563781
|
models/de/kokoro-de-fp32.validation.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"language": "de-DE",
|
| 3 |
+
"model": "kokoro-de-fp32.onnx",
|
| 4 |
+
"modelBytes": 325563781,
|
| 5 |
+
"modelSha256": "ecea710e0e4481d5930fc3486c5ed1c3dfd2dc752c2beb676135343d0236b1f3",
|
| 6 |
+
"sourceCheckpoint": "kokoro_german_converted.pth",
|
| 7 |
+
"sourceCheckpointSha256": "b8b2ab322963e7662c6036035c76c34a6a5582f814917407c94d632a1c930f71",
|
| 8 |
+
"sourceRevision": "3744b57964eab7df6e8c48f0b84badb29e14df07",
|
| 9 |
+
"baseRevision": "f3ff3571791e39611d31c381e3a41a3af07b4987",
|
| 10 |
+
"opset": 17,
|
| 11 |
+
"sampleRateHz": 24000,
|
| 12 |
+
"voice": "df_anna.bin",
|
| 13 |
+
"voiceSha256": "d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b",
|
| 14 |
+
"referencePhonemes": "f\u02c8al\u0283\u0259s \u02c8y\u02d0b\u0259n f\u0254n ks\u02c8y\u02d0lo\u02d0f\u02cc\u0254nmu\u02d0z\u02cci\u02d0k kv\u02c8\u025blt j\u02c8e\u02d0d\u0259n \u0261\u027e\u02c8\u00f8\u02d0s\u0259r\u0259n \u02a6v\u02c8\u025b\u027ek.",
|
| 15 |
+
"referenceInputTokens": 75,
|
| 16 |
+
"referenceOutputSamples": 90600,
|
| 17 |
+
"maxAbsoluteError": 0.06611382961273193,
|
| 18 |
+
"meanAbsoluteError": 0.0024777022190392017,
|
| 19 |
+
"waveformCorrelation": 0.996961705255154,
|
| 20 |
+
"durationExactMatch": true,
|
| 21 |
+
"onnxRuntimeVersion": "1.29.0",
|
| 22 |
+
"torchVersion": "2.6.0"
|
| 23 |
+
}
|
models/pl/kokoro-pl-fp32.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:66637ea517e8ea4fea6c473c18a6f3b4fe982a8e7eb3879bb5f8250c7dc5679a
|
| 3 |
+
size 325563781
|
models/pl/kokoro-pl-fp32.validation.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"language": "pl-PL",
|
| 3 |
+
"model": "kokoro-pl-fp32.onnx",
|
| 4 |
+
"modelBytes": 325563781,
|
| 5 |
+
"modelSha256": "66637ea517e8ea4fea6c473c18a6f3b4fe982a8e7eb3879bb5f8250c7dc5679a",
|
| 6 |
+
"sourceCheckpoint": "kokoro_polish_converted.pth",
|
| 7 |
+
"sourceCheckpointSha256": "e3202dc4d1f6e65dddff8a8e8d2e091ce9a3a66cf989c6c581a81b2f1969af49",
|
| 8 |
+
"sourceRevision": "3744b57964eab7df6e8c48f0b84badb29e14df07",
|
| 9 |
+
"baseRevision": "f3ff3571791e39611d31c381e3a41a3af07b4987",
|
| 10 |
+
"opset": 17,
|
| 11 |
+
"sampleRateHz": 24000,
|
| 12 |
+
"voice": "pm_mateusz.bin",
|
| 13 |
+
"voiceSha256": "dc8f2919ede945e6962310b5204b912e64689d5698c571822bf75ad704870cb4",
|
| 14 |
+
"referencePhonemes": "z\u02c8a\u0292uwd\u0292 \u0261\u02c8\u025b\u0272\u0255l\u0254\u0303 j\u02c8a\u0292\u0272.",
|
| 15 |
+
"referenceInputTokens": 26,
|
| 16 |
+
"referenceOutputSamples": 49800,
|
| 17 |
+
"maxAbsoluteError": 0.07184462249279022,
|
| 18 |
+
"meanAbsoluteError": 0.0013195093488320708,
|
| 19 |
+
"waveformCorrelation": 0.9947539311111714,
|
| 20 |
+
"durationExactMatch": true,
|
| 21 |
+
"onnxRuntimeVersion": "1.29.0",
|
| 22 |
+
"torchVersion": "2.6.0"
|
| 23 |
+
}
|
package-lock.json
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "kokoro-kmp-model-validation",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"lockfileVersion": 3,
|
| 5 |
+
"requires": true,
|
| 6 |
+
"packages": {
|
| 7 |
+
"": {
|
| 8 |
+
"name": "kokoro-kmp-model-validation",
|
| 9 |
+
"version": "1.0.0",
|
| 10 |
+
"devDependencies": {
|
| 11 |
+
"onnxruntime-web": "1.29.0"
|
| 12 |
+
}
|
| 13 |
+
},
|
| 14 |
+
"node_modules/@protobufjs/aspromise": {
|
| 15 |
+
"version": "1.1.2",
|
| 16 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
| 17 |
+
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
| 18 |
+
"dev": true,
|
| 19 |
+
"license": "BSD-3-Clause"
|
| 20 |
+
},
|
| 21 |
+
"node_modules/@protobufjs/base64": {
|
| 22 |
+
"version": "1.1.2",
|
| 23 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
| 24 |
+
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
| 25 |
+
"dev": true,
|
| 26 |
+
"license": "BSD-3-Clause"
|
| 27 |
+
},
|
| 28 |
+
"node_modules/@protobufjs/codegen": {
|
| 29 |
+
"version": "2.0.5",
|
| 30 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz",
|
| 31 |
+
"integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
|
| 32 |
+
"dev": true,
|
| 33 |
+
"license": "BSD-3-Clause"
|
| 34 |
+
},
|
| 35 |
+
"node_modules/@protobufjs/eventemitter": {
|
| 36 |
+
"version": "1.1.1",
|
| 37 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz",
|
| 38 |
+
"integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==",
|
| 39 |
+
"dev": true,
|
| 40 |
+
"license": "BSD-3-Clause"
|
| 41 |
+
},
|
| 42 |
+
"node_modules/@protobufjs/fetch": {
|
| 43 |
+
"version": "1.1.1",
|
| 44 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz",
|
| 45 |
+
"integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==",
|
| 46 |
+
"dev": true,
|
| 47 |
+
"license": "BSD-3-Clause",
|
| 48 |
+
"dependencies": {
|
| 49 |
+
"@protobufjs/aspromise": "^1.1.1"
|
| 50 |
+
}
|
| 51 |
+
},
|
| 52 |
+
"node_modules/@protobufjs/float": {
|
| 53 |
+
"version": "1.0.2",
|
| 54 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
| 55 |
+
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
| 56 |
+
"dev": true,
|
| 57 |
+
"license": "BSD-3-Clause"
|
| 58 |
+
},
|
| 59 |
+
"node_modules/@protobufjs/path": {
|
| 60 |
+
"version": "1.1.2",
|
| 61 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
| 62 |
+
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
| 63 |
+
"dev": true,
|
| 64 |
+
"license": "BSD-3-Clause"
|
| 65 |
+
},
|
| 66 |
+
"node_modules/@protobufjs/pool": {
|
| 67 |
+
"version": "1.1.0",
|
| 68 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
| 69 |
+
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
| 70 |
+
"dev": true,
|
| 71 |
+
"license": "BSD-3-Clause"
|
| 72 |
+
},
|
| 73 |
+
"node_modules/@protobufjs/utf8": {
|
| 74 |
+
"version": "1.1.2",
|
| 75 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz",
|
| 76 |
+
"integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==",
|
| 77 |
+
"dev": true,
|
| 78 |
+
"license": "BSD-3-Clause"
|
| 79 |
+
},
|
| 80 |
+
"node_modules/@types/node": {
|
| 81 |
+
"version": "26.4.1",
|
| 82 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz",
|
| 83 |
+
"integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==",
|
| 84 |
+
"dev": true,
|
| 85 |
+
"license": "MIT",
|
| 86 |
+
"dependencies": {
|
| 87 |
+
"undici-types": "~8.3.0"
|
| 88 |
+
}
|
| 89 |
+
},
|
| 90 |
+
"node_modules/flatbuffers": {
|
| 91 |
+
"version": "25.9.23",
|
| 92 |
+
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz",
|
| 93 |
+
"integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==",
|
| 94 |
+
"dev": true,
|
| 95 |
+
"license": "Apache-2.0"
|
| 96 |
+
},
|
| 97 |
+
"node_modules/guid-typescript": {
|
| 98 |
+
"version": "1.0.9",
|
| 99 |
+
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
|
| 100 |
+
"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==",
|
| 101 |
+
"dev": true,
|
| 102 |
+
"license": "ISC"
|
| 103 |
+
},
|
| 104 |
+
"node_modules/long": {
|
| 105 |
+
"version": "5.3.2",
|
| 106 |
+
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
| 107 |
+
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
| 108 |
+
"dev": true,
|
| 109 |
+
"license": "Apache-2.0"
|
| 110 |
+
},
|
| 111 |
+
"node_modules/onnxruntime-common": {
|
| 112 |
+
"version": "1.29.0",
|
| 113 |
+
"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.29.0.tgz",
|
| 114 |
+
"integrity": "sha512-/F63/e2VJoaVXGGNu6S5QH7jivBThGO95OzAVXXQ8hTta/b1QxI8udHa6cI3+3mAb5WWIIaMMwfZw01oivjJ1g==",
|
| 115 |
+
"dev": true,
|
| 116 |
+
"license": "MIT"
|
| 117 |
+
},
|
| 118 |
+
"node_modules/onnxruntime-web": {
|
| 119 |
+
"version": "1.29.0",
|
| 120 |
+
"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.29.0.tgz",
|
| 121 |
+
"integrity": "sha512-LuQlpX6MFLJZu756erwUeb1mNfoJGbs1kzDwJGNlf5RvfYMdqhcY3vNpDPK40CUV2HoWTkIj+uS0o36GFHjeYw==",
|
| 122 |
+
"dev": true,
|
| 123 |
+
"license": "MIT",
|
| 124 |
+
"dependencies": {
|
| 125 |
+
"flatbuffers": "^25.1.24",
|
| 126 |
+
"guid-typescript": "^1.0.9",
|
| 127 |
+
"long": "^5.2.3",
|
| 128 |
+
"onnxruntime-common": "1.29.0",
|
| 129 |
+
"platform": "^1.3.6",
|
| 130 |
+
"protobufjs": "^7.2.4"
|
| 131 |
+
}
|
| 132 |
+
},
|
| 133 |
+
"node_modules/platform": {
|
| 134 |
+
"version": "1.3.6",
|
| 135 |
+
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
|
| 136 |
+
"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
|
| 137 |
+
"dev": true,
|
| 138 |
+
"license": "MIT"
|
| 139 |
+
},
|
| 140 |
+
"node_modules/protobufjs": {
|
| 141 |
+
"version": "7.6.6",
|
| 142 |
+
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz",
|
| 143 |
+
"integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==",
|
| 144 |
+
"dev": true,
|
| 145 |
+
"hasInstallScript": true,
|
| 146 |
+
"license": "BSD-3-Clause",
|
| 147 |
+
"dependencies": {
|
| 148 |
+
"@protobufjs/aspromise": "^1.1.2",
|
| 149 |
+
"@protobufjs/base64": "^1.1.2",
|
| 150 |
+
"@protobufjs/codegen": "^2.0.5",
|
| 151 |
+
"@protobufjs/eventemitter": "^1.1.1",
|
| 152 |
+
"@protobufjs/fetch": "^1.1.1",
|
| 153 |
+
"@protobufjs/float": "^1.0.2",
|
| 154 |
+
"@protobufjs/path": "^1.1.2",
|
| 155 |
+
"@protobufjs/pool": "^1.1.0",
|
| 156 |
+
"@protobufjs/utf8": "^1.1.1",
|
| 157 |
+
"@types/node": ">=13.7.0",
|
| 158 |
+
"long": "^5.3.2"
|
| 159 |
+
},
|
| 160 |
+
"engines": {
|
| 161 |
+
"node": ">=12.0.0"
|
| 162 |
+
}
|
| 163 |
+
},
|
| 164 |
+
"node_modules/undici-types": {
|
| 165 |
+
"version": "8.3.0",
|
| 166 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
|
| 167 |
+
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
|
| 168 |
+
"dev": true,
|
| 169 |
+
"license": "MIT"
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
}
|
package.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "kokoro-kmp-model-validation",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"private": true,
|
| 5 |
+
"scripts": {
|
| 6 |
+
"validate:web": "node scripts/validate_web.cjs pl && node scripts/validate_web.cjs de",
|
| 7 |
+
"validate:web:pl": "node scripts/validate_web.cjs pl",
|
| 8 |
+
"validate:web:de": "node scripts/validate_web.cjs de"
|
| 9 |
+
},
|
| 10 |
+
"devDependencies": {
|
| 11 |
+
"onnxruntime-web": "1.29.0"
|
| 12 |
+
}
|
| 13 |
+
}
|
phonemizers/de/phonemizer_de.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4888dc7e54dc66098551555096562063364091fc246da0d057b629587bedaa0b
|
| 3 |
+
size 7094120
|
phonemizers/pl/phonemizer_pl.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ec85f4dc2c4ac7a72ff88b98b0664a4ed887bd15c0d5add2eb1d6a6ee05b73f2
|
| 3 |
+
size 7094120
|
requirements-export.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
numpy==2.5.2
|
| 2 |
+
huggingface-hub==0.36.2
|
| 3 |
+
jsonschema==4.26.0
|
| 4 |
+
onnx==1.19.0
|
| 5 |
+
onnxruntime==1.29.0
|
| 6 |
+
soundfile==0.13.1
|
| 7 |
+
torch==2.6.0
|
runtime/config.json
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"istftnet": {
|
| 3 |
+
"upsample_kernel_sizes": [20, 12],
|
| 4 |
+
"upsample_rates": [10, 6],
|
| 5 |
+
"gen_istft_hop_size": 5,
|
| 6 |
+
"gen_istft_n_fft": 20,
|
| 7 |
+
"resblock_dilation_sizes": [
|
| 8 |
+
[1, 3, 5],
|
| 9 |
+
[1, 3, 5],
|
| 10 |
+
[1, 3, 5]
|
| 11 |
+
],
|
| 12 |
+
"resblock_kernel_sizes": [3, 7, 11],
|
| 13 |
+
"upsample_initial_channel": 512
|
| 14 |
+
},
|
| 15 |
+
"dim_in": 64,
|
| 16 |
+
"dropout": 0.2,
|
| 17 |
+
"hidden_dim": 512,
|
| 18 |
+
"max_conv_dim": 512,
|
| 19 |
+
"max_dur": 50,
|
| 20 |
+
"multispeaker": true,
|
| 21 |
+
"n_layer": 3,
|
| 22 |
+
"n_mels": 80,
|
| 23 |
+
"n_token": 178,
|
| 24 |
+
"style_dim": 128,
|
| 25 |
+
"text_encoder_kernel_size": 5,
|
| 26 |
+
"plbert": {
|
| 27 |
+
"hidden_size": 768,
|
| 28 |
+
"num_attention_heads": 12,
|
| 29 |
+
"intermediate_size": 2048,
|
| 30 |
+
"max_position_embeddings": 512,
|
| 31 |
+
"num_hidden_layers": 12,
|
| 32 |
+
"dropout": 0.1
|
| 33 |
+
},
|
| 34 |
+
"vocab": {
|
| 35 |
+
";": 1,
|
| 36 |
+
":": 2,
|
| 37 |
+
",": 3,
|
| 38 |
+
".": 4,
|
| 39 |
+
"!": 5,
|
| 40 |
+
"?": 6,
|
| 41 |
+
"—": 9,
|
| 42 |
+
"…": 10,
|
| 43 |
+
"\"": 11,
|
| 44 |
+
"(": 12,
|
| 45 |
+
")": 13,
|
| 46 |
+
"“": 14,
|
| 47 |
+
"”": 15,
|
| 48 |
+
" ": 16,
|
| 49 |
+
"\u0303": 17,
|
| 50 |
+
"ʣ": 18,
|
| 51 |
+
"ʥ": 19,
|
| 52 |
+
"ʦ": 20,
|
| 53 |
+
"ʨ": 21,
|
| 54 |
+
"ᵝ": 22,
|
| 55 |
+
"\uAB67": 23,
|
| 56 |
+
"A": 24,
|
| 57 |
+
"I": 25,
|
| 58 |
+
"O": 31,
|
| 59 |
+
"Q": 33,
|
| 60 |
+
"S": 35,
|
| 61 |
+
"T": 36,
|
| 62 |
+
"W": 39,
|
| 63 |
+
"Y": 41,
|
| 64 |
+
"ᵊ": 42,
|
| 65 |
+
"a": 43,
|
| 66 |
+
"b": 44,
|
| 67 |
+
"c": 45,
|
| 68 |
+
"d": 46,
|
| 69 |
+
"e": 47,
|
| 70 |
+
"f": 48,
|
| 71 |
+
"h": 50,
|
| 72 |
+
"i": 51,
|
| 73 |
+
"j": 52,
|
| 74 |
+
"k": 53,
|
| 75 |
+
"l": 54,
|
| 76 |
+
"m": 55,
|
| 77 |
+
"n": 56,
|
| 78 |
+
"o": 57,
|
| 79 |
+
"p": 58,
|
| 80 |
+
"q": 59,
|
| 81 |
+
"r": 60,
|
| 82 |
+
"s": 61,
|
| 83 |
+
"t": 62,
|
| 84 |
+
"u": 63,
|
| 85 |
+
"v": 64,
|
| 86 |
+
"w": 65,
|
| 87 |
+
"x": 66,
|
| 88 |
+
"y": 67,
|
| 89 |
+
"z": 68,
|
| 90 |
+
"ɑ": 69,
|
| 91 |
+
"ɐ": 70,
|
| 92 |
+
"ɒ": 71,
|
| 93 |
+
"æ": 72,
|
| 94 |
+
"β": 75,
|
| 95 |
+
"ɔ": 76,
|
| 96 |
+
"ɕ": 77,
|
| 97 |
+
"ç": 78,
|
| 98 |
+
"ɖ": 80,
|
| 99 |
+
"ð": 81,
|
| 100 |
+
"ʤ": 82,
|
| 101 |
+
"ə": 83,
|
| 102 |
+
"ɚ": 85,
|
| 103 |
+
"ɛ": 86,
|
| 104 |
+
"ɜ": 87,
|
| 105 |
+
"ɟ": 90,
|
| 106 |
+
"ɡ": 92,
|
| 107 |
+
"ɥ": 99,
|
| 108 |
+
"ɨ": 101,
|
| 109 |
+
"ɪ": 102,
|
| 110 |
+
"ʝ": 103,
|
| 111 |
+
"ɯ": 110,
|
| 112 |
+
"ɰ": 111,
|
| 113 |
+
"ŋ": 112,
|
| 114 |
+
"ɳ": 113,
|
| 115 |
+
"ɲ": 114,
|
| 116 |
+
"ɴ": 115,
|
| 117 |
+
"ø": 116,
|
| 118 |
+
"ɸ": 118,
|
| 119 |
+
"θ": 119,
|
| 120 |
+
"œ": 120,
|
| 121 |
+
"ɹ": 123,
|
| 122 |
+
"ɾ": 125,
|
| 123 |
+
"ɻ": 126,
|
| 124 |
+
"ʁ": 128,
|
| 125 |
+
"ɽ": 129,
|
| 126 |
+
"ʂ": 130,
|
| 127 |
+
"ʃ": 131,
|
| 128 |
+
"ʈ": 132,
|
| 129 |
+
"ʧ": 133,
|
| 130 |
+
"ʊ": 135,
|
| 131 |
+
"ʋ": 136,
|
| 132 |
+
"ʌ": 138,
|
| 133 |
+
"ɣ": 139,
|
| 134 |
+
"ɤ": 140,
|
| 135 |
+
"χ": 142,
|
| 136 |
+
"ʎ": 143,
|
| 137 |
+
"ʒ": 147,
|
| 138 |
+
"ʔ": 148,
|
| 139 |
+
"ˈ": 156,
|
| 140 |
+
"ˌ": 157,
|
| 141 |
+
"ː": 158,
|
| 142 |
+
"ʰ": 162,
|
| 143 |
+
"ʲ": 164,
|
| 144 |
+
"↓": 169,
|
| 145 |
+
"→": 171,
|
| 146 |
+
"↗": 172,
|
| 147 |
+
"↘": 173,
|
| 148 |
+
"ᵻ": 177
|
| 149 |
+
}
|
| 150 |
+
}
|
samples/de-anna.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ab75032aeb5be87b1844fb7008c58c0bda40ca52f907ed356466e11abb4adcab
|
| 3 |
+
size 180044
|
samples/pl-mateusz.wav
ADDED
|
Binary file (98.4 kB). View file
|
|
|
schema/kokoro-catalog.schema.json
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
| 3 |
+
"title": "Kokoro KMP model catalog",
|
| 4 |
+
"type": "object",
|
| 5 |
+
"additionalProperties": false,
|
| 6 |
+
"required": [
|
| 7 |
+
"schemaVersion",
|
| 8 |
+
"catalogVersion",
|
| 9 |
+
"distribution",
|
| 10 |
+
"license",
|
| 11 |
+
"modelFamily",
|
| 12 |
+
"audio",
|
| 13 |
+
"runtime",
|
| 14 |
+
"languages"
|
| 15 |
+
],
|
| 16 |
+
"properties": {
|
| 17 |
+
"$schema": { "type": "string" },
|
| 18 |
+
"schemaVersion": { "const": 1 },
|
| 19 |
+
"catalogVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
| 20 |
+
"distribution": {
|
| 21 |
+
"type": "object",
|
| 22 |
+
"additionalProperties": false,
|
| 23 |
+
"required": ["provider", "artifactResolution", "recommendedRevision"],
|
| 24 |
+
"properties": {
|
| 25 |
+
"provider": { "const": "huggingface" },
|
| 26 |
+
"artifactResolution": { "const": "relative-to-catalog" },
|
| 27 |
+
"recommendedRevision": { "type": "string", "minLength": 1 }
|
| 28 |
+
}
|
| 29 |
+
},
|
| 30 |
+
"license": { "const": "Apache-2.0" },
|
| 31 |
+
"modelFamily": { "const": "kokoro-82m" },
|
| 32 |
+
"audio": {
|
| 33 |
+
"type": "object",
|
| 34 |
+
"additionalProperties": false,
|
| 35 |
+
"required": ["sampleRateHz", "channels", "sampleType"],
|
| 36 |
+
"properties": {
|
| 37 |
+
"sampleRateHz": { "const": 24000 },
|
| 38 |
+
"channels": { "const": 1 },
|
| 39 |
+
"sampleType": { "const": "float32" }
|
| 40 |
+
}
|
| 41 |
+
},
|
| 42 |
+
"runtime": {
|
| 43 |
+
"type": "object",
|
| 44 |
+
"additionalProperties": true,
|
| 45 |
+
"required": [
|
| 46 |
+
"engine",
|
| 47 |
+
"opset",
|
| 48 |
+
"batchSize",
|
| 49 |
+
"maxPhonemeCodePoints",
|
| 50 |
+
"inputs",
|
| 51 |
+
"outputs",
|
| 52 |
+
"tokenizer",
|
| 53 |
+
"voiceStyle"
|
| 54 |
+
],
|
| 55 |
+
"properties": {
|
| 56 |
+
"engine": { "const": "onnxruntime" },
|
| 57 |
+
"opset": { "type": "integer", "minimum": 1 },
|
| 58 |
+
"batchSize": { "const": 1 },
|
| 59 |
+
"maxPhonemeCodePoints": { "type": "integer", "minimum": 1 },
|
| 60 |
+
"tokenizer": {
|
| 61 |
+
"type": "object",
|
| 62 |
+
"required": ["bosTokenId", "eosTokenId", "vocabularyField", "artifact"],
|
| 63 |
+
"properties": {
|
| 64 |
+
"artifact": { "$ref": "#/$defs/artifact" }
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
"voiceStyle": {
|
| 68 |
+
"type": "object",
|
| 69 |
+
"required": ["format", "shape", "rowSelection"]
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
},
|
| 73 |
+
"languages": {
|
| 74 |
+
"type": "array",
|
| 75 |
+
"minItems": 1,
|
| 76 |
+
"items": { "$ref": "#/$defs/language" }
|
| 77 |
+
}
|
| 78 |
+
},
|
| 79 |
+
"$defs": {
|
| 80 |
+
"artifact": {
|
| 81 |
+
"type": "object",
|
| 82 |
+
"additionalProperties": false,
|
| 83 |
+
"required": ["path", "mediaType", "sizeBytes", "sha256"],
|
| 84 |
+
"properties": {
|
| 85 |
+
"path": {
|
| 86 |
+
"type": "string",
|
| 87 |
+
"minLength": 1,
|
| 88 |
+
"not": { "pattern": "(^/|(^|/)\\.\\.(/|$))" }
|
| 89 |
+
},
|
| 90 |
+
"mediaType": { "type": "string", "minLength": 1 },
|
| 91 |
+
"sizeBytes": { "type": "integer", "minimum": 0 },
|
| 92 |
+
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
|
| 93 |
+
}
|
| 94 |
+
},
|
| 95 |
+
"voice": {
|
| 96 |
+
"type": "object",
|
| 97 |
+
"additionalProperties": false,
|
| 98 |
+
"required": ["id", "displayName", "gender", "artifact"],
|
| 99 |
+
"properties": {
|
| 100 |
+
"id": { "type": "string", "pattern": "^[a-z0-9_-]+$" },
|
| 101 |
+
"displayName": { "type": "string", "minLength": 1 },
|
| 102 |
+
"gender": { "enum": ["female", "male", "neutral", "unknown"] },
|
| 103 |
+
"artifact": { "$ref": "#/$defs/artifact" }
|
| 104 |
+
}
|
| 105 |
+
},
|
| 106 |
+
"language": {
|
| 107 |
+
"type": "object",
|
| 108 |
+
"additionalProperties": false,
|
| 109 |
+
"required": [
|
| 110 |
+
"id",
|
| 111 |
+
"locale",
|
| 112 |
+
"displayName",
|
| 113 |
+
"nativeName",
|
| 114 |
+
"model",
|
| 115 |
+
"phonemizer",
|
| 116 |
+
"voices",
|
| 117 |
+
"previewAudioPath"
|
| 118 |
+
],
|
| 119 |
+
"properties": {
|
| 120 |
+
"id": { "type": "string", "pattern": "^[a-z]{2,3}$" },
|
| 121 |
+
"locale": { "type": "string", "minLength": 2 },
|
| 122 |
+
"displayName": { "type": "string", "minLength": 1 },
|
| 123 |
+
"nativeName": { "type": "string", "minLength": 1 },
|
| 124 |
+
"model": {
|
| 125 |
+
"type": "object",
|
| 126 |
+
"additionalProperties": false,
|
| 127 |
+
"required": ["id", "format", "precision", "artifact", "validation"],
|
| 128 |
+
"properties": {
|
| 129 |
+
"id": { "type": "string", "minLength": 1 },
|
| 130 |
+
"format": { "const": "onnx" },
|
| 131 |
+
"precision": { "enum": ["fp32", "fp16", "int8"] },
|
| 132 |
+
"artifact": { "$ref": "#/$defs/artifact" },
|
| 133 |
+
"validation": { "$ref": "#/$defs/artifact" }
|
| 134 |
+
}
|
| 135 |
+
},
|
| 136 |
+
"phonemizer": {
|
| 137 |
+
"type": "object",
|
| 138 |
+
"additionalProperties": false,
|
| 139 |
+
"required": ["engine", "language", "license", "sourceRevision", "artifact"],
|
| 140 |
+
"properties": {
|
| 141 |
+
"engine": { "const": "phonemis-protophone" },
|
| 142 |
+
"language": { "type": "string", "minLength": 2 },
|
| 143 |
+
"license": { "const": "MIT" },
|
| 144 |
+
"sourceRevision": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
| 145 |
+
"artifact": { "$ref": "#/$defs/artifact" }
|
| 146 |
+
}
|
| 147 |
+
},
|
| 148 |
+
"voices": {
|
| 149 |
+
"type": "array",
|
| 150 |
+
"minItems": 1,
|
| 151 |
+
"items": { "$ref": "#/$defs/voice" }
|
| 152 |
+
},
|
| 153 |
+
"previewAudioPath": { "type": "string", "minLength": 1 }
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
}
|
scripts/build_catalog.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Hydrate catalog.template.json with immutable artifact sizes and checksums."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Any
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def sha256(path: Path) -> str:
|
| 16 |
+
digest = hashlib.sha256()
|
| 17 |
+
with path.open("rb") as source:
|
| 18 |
+
for block in iter(lambda: source.read(1024 * 1024), b""):
|
| 19 |
+
digest.update(block)
|
| 20 |
+
return digest.hexdigest()
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def hydrate(value: Any) -> Any:
|
| 24 |
+
if isinstance(value, list):
|
| 25 |
+
return [hydrate(item) for item in value]
|
| 26 |
+
if not isinstance(value, dict):
|
| 27 |
+
return value
|
| 28 |
+
if "$artifact" in value:
|
| 29 |
+
if len(value) != 1 or not isinstance(value["$artifact"], dict):
|
| 30 |
+
raise ValueError("$artifact must be the only key and contain an object")
|
| 31 |
+
artifact = dict(value["$artifact"])
|
| 32 |
+
relative_path = Path(artifact["path"])
|
| 33 |
+
if relative_path.is_absolute() or ".." in relative_path.parts:
|
| 34 |
+
raise ValueError(f"Artifact path must stay inside the repository: {relative_path}")
|
| 35 |
+
path = ROOT / relative_path
|
| 36 |
+
if not path.is_file():
|
| 37 |
+
raise FileNotFoundError(path)
|
| 38 |
+
artifact["sizeBytes"] = path.stat().st_size
|
| 39 |
+
artifact["sha256"] = sha256(path)
|
| 40 |
+
return artifact
|
| 41 |
+
return {key: hydrate(item) for key, item in value.items()}
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
template = json.loads((ROOT / "catalog.template.json").read_text(encoding="utf-8"))
|
| 45 |
+
catalog = hydrate(template)
|
| 46 |
+
(ROOT / "catalog.json").write_text(
|
| 47 |
+
json.dumps(catalog, ensure_ascii=False, indent=2) + "\n",
|
| 48 |
+
encoding="utf-8",
|
| 49 |
+
)
|
| 50 |
+
print(ROOT / "catalog.json")
|
scripts/export_onnx.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Export a Kokoro checkpoint to a self-contained ONNX model and verify it."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import hashlib
|
| 8 |
+
import json
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import onnx
|
| 13 |
+
import onnxruntime as ort
|
| 14 |
+
import torch
|
| 15 |
+
|
| 16 |
+
from kokoro import KModel
|
| 17 |
+
from kokoro.model import KModelForONNX
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def sha256(path: Path) -> str:
|
| 21 |
+
digest = hashlib.sha256()
|
| 22 |
+
with path.open("rb") as source:
|
| 23 |
+
for block in iter(lambda: source.read(1024 * 1024), b""):
|
| 24 |
+
digest.update(block)
|
| 25 |
+
return digest.hexdigest()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def make_reference_inputs(
|
| 29 |
+
model: KModel,
|
| 30 |
+
voice: Path,
|
| 31 |
+
phonemes: str,
|
| 32 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 33 |
+
missing = sorted({phoneme for phoneme in phonemes if model.vocab.get(phoneme) is None})
|
| 34 |
+
if missing:
|
| 35 |
+
raise RuntimeError(f"Reference phonemes missing from the Kokoro vocabulary: {missing}")
|
| 36 |
+
if not 1 <= len(phonemes) <= 510:
|
| 37 |
+
raise RuntimeError(f"Reference phoneme length must be in 1..510, got {len(phonemes)}")
|
| 38 |
+
|
| 39 |
+
voice_pack = np.fromfile(voice, dtype=np.float32)
|
| 40 |
+
if voice_pack.size != 510 * 256:
|
| 41 |
+
raise RuntimeError(
|
| 42 |
+
f"Expected a raw 510x256 float32 voice pack, got {voice_pack.size} values"
|
| 43 |
+
)
|
| 44 |
+
voice_pack = voice_pack.reshape(510, 256)
|
| 45 |
+
|
| 46 |
+
token_ids = [int(model.vocab[phoneme]) for phoneme in phonemes]
|
| 47 |
+
input_ids = torch.tensor([[0, *token_ids, 0]], dtype=torch.long)
|
| 48 |
+
style = torch.from_numpy(voice_pack[len(phonemes) - 1]).unsqueeze(0)
|
| 49 |
+
speed = torch.tensor([1.0], dtype=torch.float32)
|
| 50 |
+
return input_ids, style, speed
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def add_metadata(
|
| 54 |
+
output: Path,
|
| 55 |
+
*,
|
| 56 |
+
language: str,
|
| 57 |
+
checkpoint: Path,
|
| 58 |
+
source_revision: str,
|
| 59 |
+
base_revision: str,
|
| 60 |
+
) -> None:
|
| 61 |
+
model = onnx.load(output)
|
| 62 |
+
onnx.helper.set_model_props(
|
| 63 |
+
model,
|
| 64 |
+
{
|
| 65 |
+
"architecture": "Kokoro-82M",
|
| 66 |
+
"language": language,
|
| 67 |
+
"license": "Apache-2.0",
|
| 68 |
+
"sample_rate_hz": "24000",
|
| 69 |
+
"source_repository": "software-mansion/react-native-executorch-kokoro",
|
| 70 |
+
"source_revision": source_revision,
|
| 71 |
+
"source_checkpoint": checkpoint.name,
|
| 72 |
+
"source_checkpoint_sha256": sha256(checkpoint),
|
| 73 |
+
"base_repository": "hexgrad/Kokoro-82M",
|
| 74 |
+
"base_revision": base_revision,
|
| 75 |
+
},
|
| 76 |
+
)
|
| 77 |
+
onnx.save_model(model, output)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def export(args: argparse.Namespace) -> None:
|
| 81 |
+
checkpoint = args.checkpoint.resolve()
|
| 82 |
+
config = args.config.resolve()
|
| 83 |
+
voice = args.voice.resolve()
|
| 84 |
+
output = args.output.resolve()
|
| 85 |
+
output.parent.mkdir(parents=True, exist_ok=True)
|
| 86 |
+
|
| 87 |
+
torch.manual_seed(0)
|
| 88 |
+
model = KModel(
|
| 89 |
+
repo_id="hexgrad/Kokoro-82M",
|
| 90 |
+
config=str(config),
|
| 91 |
+
model=str(checkpoint),
|
| 92 |
+
disable_complex=True,
|
| 93 |
+
).cpu().eval()
|
| 94 |
+
export_model = KModelForONNX(model).cpu().eval()
|
| 95 |
+
input_ids, style, speed = make_reference_inputs(
|
| 96 |
+
model,
|
| 97 |
+
voice,
|
| 98 |
+
args.reference_phonemes,
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
torch.onnx.export(
|
| 102 |
+
export_model,
|
| 103 |
+
args=(input_ids, style, speed),
|
| 104 |
+
f=str(output),
|
| 105 |
+
input_names=["input_ids", "style", "speed"],
|
| 106 |
+
output_names=["waveform", "duration"],
|
| 107 |
+
opset_version=17,
|
| 108 |
+
dynamic_axes={
|
| 109 |
+
"input_ids": {1: "sequence_length"},
|
| 110 |
+
"waveform": {0: "num_samples"},
|
| 111 |
+
"duration": {0: "sequence_length"},
|
| 112 |
+
},
|
| 113 |
+
do_constant_folding=True,
|
| 114 |
+
dynamo=False,
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
add_metadata(
|
| 118 |
+
output,
|
| 119 |
+
language=args.language,
|
| 120 |
+
checkpoint=checkpoint,
|
| 121 |
+
source_revision=args.source_revision,
|
| 122 |
+
base_revision=args.base_revision,
|
| 123 |
+
)
|
| 124 |
+
onnx.checker.check_model(str(output), full_check=True)
|
| 125 |
+
|
| 126 |
+
options = ort.SessionOptions()
|
| 127 |
+
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
|
| 128 |
+
session = ort.InferenceSession(str(output), sess_options=options, providers=["CPUExecutionProvider"])
|
| 129 |
+
|
| 130 |
+
# Kokoro deliberately injects a small amount of random excitation noise. As a
|
| 131 |
+
# result, PyTorch and ONNX waveforms should be highly correlated, but are not
|
| 132 |
+
# expected to be bit-identical or pass a point-wise allclose assertion.
|
| 133 |
+
torch.manual_seed(0)
|
| 134 |
+
with torch.inference_mode():
|
| 135 |
+
torch_waveform, torch_duration = export_model(input_ids, style, speed)
|
| 136 |
+
ort_waveform, ort_duration = session.run(
|
| 137 |
+
None,
|
| 138 |
+
{
|
| 139 |
+
"input_ids": input_ids.numpy(),
|
| 140 |
+
"style": style.numpy(),
|
| 141 |
+
"speed": speed.numpy(),
|
| 142 |
+
},
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
expected_waveform = torch_waveform.detach().cpu().numpy()
|
| 146 |
+
expected_duration = torch_duration.detach().cpu().numpy()
|
| 147 |
+
np.testing.assert_array_equal(ort_duration, expected_duration)
|
| 148 |
+
if not np.isfinite(ort_waveform).all():
|
| 149 |
+
raise RuntimeError("ONNX Runtime produced non-finite waveform samples")
|
| 150 |
+
|
| 151 |
+
delta = np.abs(ort_waveform - expected_waveform)
|
| 152 |
+
correlation = float(np.corrcoef(ort_waveform, expected_waveform)[0, 1])
|
| 153 |
+
mean_absolute_error = float(delta.mean())
|
| 154 |
+
if correlation < 0.99 or mean_absolute_error > 0.005:
|
| 155 |
+
raise RuntimeError(
|
| 156 |
+
"ONNX/PyTorch validation failed: "
|
| 157 |
+
f"correlation={correlation:.6f}, meanAbsoluteError={mean_absolute_error:.6f}"
|
| 158 |
+
)
|
| 159 |
+
validation = {
|
| 160 |
+
"language": args.language,
|
| 161 |
+
"model": output.name,
|
| 162 |
+
"modelBytes": output.stat().st_size,
|
| 163 |
+
"modelSha256": sha256(output),
|
| 164 |
+
"sourceCheckpoint": checkpoint.name,
|
| 165 |
+
"sourceCheckpointSha256": sha256(checkpoint),
|
| 166 |
+
"sourceRevision": args.source_revision,
|
| 167 |
+
"baseRevision": args.base_revision,
|
| 168 |
+
"opset": 17,
|
| 169 |
+
"sampleRateHz": 24000,
|
| 170 |
+
"voice": voice.name,
|
| 171 |
+
"voiceSha256": sha256(voice),
|
| 172 |
+
"referencePhonemes": args.reference_phonemes,
|
| 173 |
+
"referenceInputTokens": int(input_ids.shape[1]),
|
| 174 |
+
"referenceOutputSamples": int(ort_waveform.size),
|
| 175 |
+
"maxAbsoluteError": float(delta.max(initial=0.0)),
|
| 176 |
+
"meanAbsoluteError": mean_absolute_error,
|
| 177 |
+
"waveformCorrelation": correlation,
|
| 178 |
+
"durationExactMatch": True,
|
| 179 |
+
"onnxRuntimeVersion": ort.__version__,
|
| 180 |
+
"torchVersion": torch.__version__,
|
| 181 |
+
}
|
| 182 |
+
validation_path = output.with_suffix(".validation.json")
|
| 183 |
+
validation_path.write_text(json.dumps(validation, indent=2) + "\n", encoding="utf-8")
|
| 184 |
+
print(json.dumps(validation, indent=2))
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def parse_args() -> argparse.Namespace:
|
| 188 |
+
parser = argparse.ArgumentParser()
|
| 189 |
+
parser.add_argument("--checkpoint", type=Path, required=True)
|
| 190 |
+
parser.add_argument("--config", type=Path, required=True)
|
| 191 |
+
parser.add_argument("--voice", type=Path, required=True)
|
| 192 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 193 |
+
parser.add_argument("--language", required=True)
|
| 194 |
+
parser.add_argument("--reference-phonemes", required=True)
|
| 195 |
+
parser.add_argument("--source-revision", required=True)
|
| 196 |
+
parser.add_argument("--base-revision", required=True)
|
| 197 |
+
return parser.parse_args()
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
if __name__ == "__main__":
|
| 201 |
+
export(parse_args())
|
scripts/publish_hf.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Validate and publish this folder as a public Hugging Face model repository."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import subprocess
|
| 8 |
+
import sys
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
from huggingface_hub import HfApi
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 15 |
+
EXPECTED_REPOSITORY_NAME = "kokoro-kmp-models"
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def run_validation(skip_web: bool) -> None:
|
| 19 |
+
subprocess.run([sys.executable, ROOT / "scripts/build_catalog.py"], check=True, cwd=ROOT)
|
| 20 |
+
subprocess.run([sys.executable, ROOT / "scripts/validate_package.py"], check=True, cwd=ROOT)
|
| 21 |
+
if not skip_web:
|
| 22 |
+
subprocess.run(["npm", "run", "validate:web"], check=True, cwd=ROOT)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def parse_args() -> argparse.Namespace:
|
| 26 |
+
parser = argparse.ArgumentParser()
|
| 27 |
+
parser.add_argument("repo_id", help="Hugging Face repo, e.g. username/kokoro-kmp-models")
|
| 28 |
+
parser.add_argument("--tag", default="v1.0.0")
|
| 29 |
+
parser.add_argument("--skip-web-validation", action="store_true")
|
| 30 |
+
return parser.parse_args()
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def main() -> None:
|
| 34 |
+
args = parse_args()
|
| 35 |
+
parts = args.repo_id.split("/")
|
| 36 |
+
if len(parts) != 2 or parts[1] != EXPECTED_REPOSITORY_NAME:
|
| 37 |
+
raise SystemExit(
|
| 38 |
+
f"repo_id must be <namespace>/{EXPECTED_REPOSITORY_NAME}; got {args.repo_id!r}"
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
run_validation(args.skip_web_validation)
|
| 42 |
+
|
| 43 |
+
api = HfApi()
|
| 44 |
+
identity = api.whoami()
|
| 45 |
+
writable_namespaces = {identity["name"]}
|
| 46 |
+
writable_namespaces.update(
|
| 47 |
+
org["name"]
|
| 48 |
+
for org in identity.get("orgs", [])
|
| 49 |
+
if org.get("roleInOrg") in {"admin", "write"}
|
| 50 |
+
)
|
| 51 |
+
if parts[0] not in writable_namespaces:
|
| 52 |
+
raise SystemExit(f"The authenticated account cannot publish to namespace {parts[0]!r}")
|
| 53 |
+
|
| 54 |
+
api.create_repo(args.repo_id, repo_type="model", private=False, exist_ok=True)
|
| 55 |
+
commit = api.upload_folder(
|
| 56 |
+
repo_id=args.repo_id,
|
| 57 |
+
repo_type="model",
|
| 58 |
+
folder_path=ROOT,
|
| 59 |
+
commit_message=f"Publish Kokoro PL/DE model catalog {args.tag}",
|
| 60 |
+
ignore_patterns=[
|
| 61 |
+
".git/**",
|
| 62 |
+
"node_modules/**",
|
| 63 |
+
"**/__pycache__/**",
|
| 64 |
+
"**/*.pyc",
|
| 65 |
+
":memory:.ses",
|
| 66 |
+
],
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
tags = {tag.ref: tag.target_commit for tag in api.list_repo_refs(args.repo_id).tags}
|
| 70 |
+
tag_ref = f"refs/tags/{args.tag}"
|
| 71 |
+
existing_target = tags.get(tag_ref)
|
| 72 |
+
if existing_target and existing_target != commit.oid:
|
| 73 |
+
raise SystemExit(
|
| 74 |
+
f"Refusing to move immutable tag {args.tag}: it already points to {existing_target}"
|
| 75 |
+
)
|
| 76 |
+
if not existing_target:
|
| 77 |
+
api.create_tag(
|
| 78 |
+
args.repo_id,
|
| 79 |
+
repo_type="model",
|
| 80 |
+
tag=args.tag,
|
| 81 |
+
revision=commit.oid,
|
| 82 |
+
tag_message=f"Kokoro PL/DE catalog {args.tag}",
|
| 83 |
+
)
|
| 84 |
+
print(f"https://huggingface.co/{args.repo_id}/tree/{args.tag}")
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
if __name__ == "__main__":
|
| 88 |
+
main()
|
scripts/validate_package.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Validate every catalog artifact and exercise all ONNX language packs."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Any, Iterator
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import onnxruntime as ort
|
| 13 |
+
import soundfile as sf
|
| 14 |
+
from jsonschema import Draft202012Validator
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def sha256(path: Path) -> str:
|
| 21 |
+
digest = hashlib.sha256()
|
| 22 |
+
with path.open("rb") as source:
|
| 23 |
+
for block in iter(lambda: source.read(1024 * 1024), b""):
|
| 24 |
+
digest.update(block)
|
| 25 |
+
return digest.hexdigest()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def artifacts(value: Any) -> Iterator[dict[str, Any]]:
|
| 29 |
+
if isinstance(value, list):
|
| 30 |
+
for item in value:
|
| 31 |
+
yield from artifacts(item)
|
| 32 |
+
elif isinstance(value, dict):
|
| 33 |
+
if {"path", "sizeBytes", "sha256"} <= value.keys():
|
| 34 |
+
yield value
|
| 35 |
+
for item in value.values():
|
| 36 |
+
yield from artifacts(item)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
catalog = json.loads((ROOT / "catalog.json").read_text(encoding="utf-8"))
|
| 40 |
+
schema = json.loads(
|
| 41 |
+
(ROOT / "schema/kokoro-catalog.schema.json").read_text(encoding="utf-8")
|
| 42 |
+
)
|
| 43 |
+
Draft202012Validator.check_schema(schema)
|
| 44 |
+
Draft202012Validator(schema).validate(catalog)
|
| 45 |
+
for artifact in artifacts(catalog):
|
| 46 |
+
path = ROOT / artifact["path"]
|
| 47 |
+
if not path.is_file():
|
| 48 |
+
raise FileNotFoundError(path)
|
| 49 |
+
if path.stat().st_size != artifact["sizeBytes"]:
|
| 50 |
+
raise RuntimeError(f"Size mismatch: {path}")
|
| 51 |
+
if sha256(path) != artifact["sha256"]:
|
| 52 |
+
raise RuntimeError(f"SHA-256 mismatch: {path}")
|
| 53 |
+
|
| 54 |
+
tokenizer = catalog["runtime"]["tokenizer"]
|
| 55 |
+
config_artifact = tokenizer["artifact"]
|
| 56 |
+
config = json.loads((ROOT / config_artifact["path"]).read_text(encoding="utf-8"))
|
| 57 |
+
vocab = config[tokenizer["vocabularyField"]]
|
| 58 |
+
languages = {language["id"]: language for language in catalog["languages"]}
|
| 59 |
+
cases = json.loads((ROOT / "validation/cases.json").read_text(encoding="utf-8"))
|
| 60 |
+
sessions: dict[str, ort.InferenceSession] = {}
|
| 61 |
+
results = []
|
| 62 |
+
|
| 63 |
+
for case in cases:
|
| 64 |
+
language = languages[case["language"]]
|
| 65 |
+
voices = {voice["id"]: voice for voice in language["voices"]}
|
| 66 |
+
voice = voices[case["voice"]]
|
| 67 |
+
phonemes = case["phonemes"]
|
| 68 |
+
missing = sorted({phoneme for phoneme in phonemes if phoneme not in vocab})
|
| 69 |
+
if missing:
|
| 70 |
+
raise RuntimeError(f"{case['id']}: phonemes missing from vocabulary: {missing}")
|
| 71 |
+
if not 1 <= len(phonemes) <= catalog["runtime"]["maxPhonemeCodePoints"]:
|
| 72 |
+
raise RuntimeError(f"{case['id']}: invalid phoneme length {len(phonemes)}")
|
| 73 |
+
|
| 74 |
+
token_ids = [vocab[phoneme] for phoneme in phonemes]
|
| 75 |
+
input_ids = np.asarray([[0, *token_ids, 0]], dtype=np.int64)
|
| 76 |
+
voice_pack = np.fromfile(ROOT / voice["artifact"]["path"], dtype="<f4").reshape(510, 256)
|
| 77 |
+
style = voice_pack[len(phonemes) - 1].reshape(1, 256)
|
| 78 |
+
speed = np.asarray([1.0], dtype=np.float32)
|
| 79 |
+
|
| 80 |
+
model_path = language["model"]["artifact"]["path"]
|
| 81 |
+
if model_path not in sessions:
|
| 82 |
+
sessions[model_path] = ort.InferenceSession(
|
| 83 |
+
str(ROOT / model_path),
|
| 84 |
+
providers=["CPUExecutionProvider"],
|
| 85 |
+
)
|
| 86 |
+
waveform, duration = sessions[model_path].run(
|
| 87 |
+
None,
|
| 88 |
+
{"input_ids": input_ids, "style": style, "speed": speed},
|
| 89 |
+
)
|
| 90 |
+
if not np.isfinite(waveform).all():
|
| 91 |
+
raise RuntimeError(f"{case['id']}: non-finite waveform")
|
| 92 |
+
if duration.shape != (input_ids.shape[1],):
|
| 93 |
+
raise RuntimeError(f"{case['id']}: unexpected duration shape {duration.shape}")
|
| 94 |
+
expected_samples = int(duration.sum()) * catalog["runtime"]["durationToSamplesFactor"]
|
| 95 |
+
if waveform.shape != (expected_samples,):
|
| 96 |
+
raise RuntimeError(
|
| 97 |
+
f"{case['id']}: expected {expected_samples} samples, got {waveform.shape}"
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
if not case["id"].endswith("-dynamic"):
|
| 101 |
+
preview_path = ROOT / language["previewAudioPath"]
|
| 102 |
+
preview_path.parent.mkdir(parents=True, exist_ok=True)
|
| 103 |
+
sf.write(preview_path, waveform, catalog["audio"]["sampleRateHz"], subtype="PCM_16")
|
| 104 |
+
|
| 105 |
+
results.append(
|
| 106 |
+
{
|
| 107 |
+
"id": case["id"],
|
| 108 |
+
"phonemeCodePoints": len(phonemes),
|
| 109 |
+
"inputTokens": int(input_ids.shape[1]),
|
| 110 |
+
"outputSamples": int(waveform.size),
|
| 111 |
+
"durationSeconds": waveform.size / catalog["audio"]["sampleRateHz"],
|
| 112 |
+
"peakAbsoluteAmplitude": float(np.abs(waveform).max(initial=0.0)),
|
| 113 |
+
}
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
boundary_results = []
|
| 117 |
+
for language in catalog["languages"]:
|
| 118 |
+
voice = language["voices"][0]
|
| 119 |
+
voice_pack = np.fromfile(ROOT / voice["artifact"]["path"], dtype="<f4").reshape(510, 256)
|
| 120 |
+
model_path = language["model"]["artifact"]["path"]
|
| 121 |
+
session = sessions[model_path]
|
| 122 |
+
for phoneme_count in (1, 128, catalog["runtime"]["maxPhonemeCodePoints"]):
|
| 123 |
+
token_ids = [vocab["a"]] * phoneme_count
|
| 124 |
+
input_ids = np.asarray([[0, *token_ids, 0]], dtype=np.int64)
|
| 125 |
+
waveform, duration = session.run(
|
| 126 |
+
None,
|
| 127 |
+
{
|
| 128 |
+
"input_ids": input_ids,
|
| 129 |
+
"style": voice_pack[phoneme_count - 1].reshape(1, 256),
|
| 130 |
+
"speed": np.asarray([1.0], dtype=np.float32),
|
| 131 |
+
},
|
| 132 |
+
)
|
| 133 |
+
expected_samples = int(duration.sum()) * catalog["runtime"]["durationToSamplesFactor"]
|
| 134 |
+
if waveform.shape != (expected_samples,) or not np.isfinite(waveform).all():
|
| 135 |
+
raise RuntimeError(
|
| 136 |
+
f"{language['id']}: failed boundary case with {phoneme_count} phonemes"
|
| 137 |
+
)
|
| 138 |
+
boundary_results.append(
|
| 139 |
+
{
|
| 140 |
+
"language": language["id"],
|
| 141 |
+
"phonemeCodePoints": phoneme_count,
|
| 142 |
+
"inputTokens": int(input_ids.shape[1]),
|
| 143 |
+
"outputSamples": int(waveform.size),
|
| 144 |
+
}
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
report = {
|
| 148 |
+
"catalogVersion": catalog["catalogVersion"],
|
| 149 |
+
"catalogSchemaValidated": True,
|
| 150 |
+
"onnxRuntimeVersion": ort.__version__,
|
| 151 |
+
"artifactsVerified": sum(1 for _ in artifacts(catalog)),
|
| 152 |
+
"cases": results,
|
| 153 |
+
"boundaryCases": boundary_results,
|
| 154 |
+
}
|
| 155 |
+
(ROOT / "validation/package-validation.json").write_text(
|
| 156 |
+
json.dumps(report, ensure_ascii=False, indent=2) + "\n",
|
| 157 |
+
encoding="utf-8",
|
| 158 |
+
)
|
| 159 |
+
print(json.dumps(report, ensure_ascii=False, indent=2))
|
scripts/validate_web.cjs
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
|
| 3 |
+
const fs = require('node:fs');
|
| 4 |
+
const path = require('node:path');
|
| 5 |
+
const ort = require('onnxruntime-web');
|
| 6 |
+
|
| 7 |
+
const root = path.resolve(__dirname, '..');
|
| 8 |
+
const languageId = process.argv[2];
|
| 9 |
+
if (!languageId) throw new Error('usage: node scripts/validate_web.cjs <pl|de>');
|
| 10 |
+
|
| 11 |
+
ort.env.wasm.numThreads = 1;
|
| 12 |
+
ort.env.wasm.proxy = false;
|
| 13 |
+
|
| 14 |
+
async function main() {
|
| 15 |
+
const catalog = JSON.parse(fs.readFileSync(path.join(root, 'catalog.json'), 'utf8'));
|
| 16 |
+
const cases = JSON.parse(fs.readFileSync(path.join(root, 'validation/cases.json'), 'utf8'));
|
| 17 |
+
const config = JSON.parse(fs.readFileSync(path.join(root, 'runtime/config.json'), 'utf8'));
|
| 18 |
+
const language = catalog.languages.find((item) => item.id === languageId);
|
| 19 |
+
const testCase = cases.find(
|
| 20 |
+
(item) => item.language === languageId && item.id.endsWith('-dynamic'),
|
| 21 |
+
);
|
| 22 |
+
if (!language || !testCase) throw new Error(`unknown language: ${languageId}`);
|
| 23 |
+
const voice = language.voices.find((item) => item.id === testCase.voice);
|
| 24 |
+
|
| 25 |
+
const phonemes = Array.from(testCase.phonemes);
|
| 26 |
+
const ids = [
|
| 27 |
+
0,
|
| 28 |
+
...phonemes.map((phoneme) => {
|
| 29 |
+
const id = config.vocab[phoneme];
|
| 30 |
+
if (id === undefined) throw new Error(`missing phoneme: ${phoneme}`);
|
| 31 |
+
return id;
|
| 32 |
+
}),
|
| 33 |
+
0,
|
| 34 |
+
];
|
| 35 |
+
|
| 36 |
+
const voiceBytes = fs.readFileSync(path.join(root, voice.artifact.path));
|
| 37 |
+
function styleAt(row) {
|
| 38 |
+
const styleOffset = row * 256 * 4;
|
| 39 |
+
const style = new Float32Array(256);
|
| 40 |
+
for (let index = 0; index < style.length; index += 1) {
|
| 41 |
+
style[index] = voiceBytes.readFloatLE(styleOffset + index * 4);
|
| 42 |
+
}
|
| 43 |
+
return style;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
const modelBytes = fs.readFileSync(path.join(root, language.model.artifact.path));
|
| 47 |
+
const session = await ort.InferenceSession.create(modelBytes, {
|
| 48 |
+
executionProviders: ['wasm'],
|
| 49 |
+
graphOptimizationLevel: 'all',
|
| 50 |
+
});
|
| 51 |
+
|
| 52 |
+
async function validate(caseId, caseIds, style) {
|
| 53 |
+
const output = await session.run({
|
| 54 |
+
input_ids: new ort.Tensor(
|
| 55 |
+
'int64',
|
| 56 |
+
BigInt64Array.from(caseIds.map(BigInt)),
|
| 57 |
+
[1, caseIds.length],
|
| 58 |
+
),
|
| 59 |
+
style: new ort.Tensor('float32', style, [1, 256]),
|
| 60 |
+
speed: new ort.Tensor('float32', Float32Array.of(1), [1]),
|
| 61 |
+
});
|
| 62 |
+
const waveform = output.waveform.data;
|
| 63 |
+
const durationSum = Array.from(output.duration.data).reduce(
|
| 64 |
+
(sum, item) => sum + Number(item),
|
| 65 |
+
0,
|
| 66 |
+
);
|
| 67 |
+
const expectedSamples = durationSum * catalog.runtime.durationToSamplesFactor;
|
| 68 |
+
if (waveform.length !== expectedSamples) {
|
| 69 |
+
throw new Error(`waveform/duration mismatch: ${waveform.length} vs ${expectedSamples}`);
|
| 70 |
+
}
|
| 71 |
+
let peak = 0;
|
| 72 |
+
for (const sample of waveform) {
|
| 73 |
+
if (!Number.isFinite(sample)) throw new Error('non-finite waveform');
|
| 74 |
+
peak = Math.max(peak, Math.abs(sample));
|
| 75 |
+
}
|
| 76 |
+
return {
|
| 77 |
+
id: caseId,
|
| 78 |
+
inputTokens: caseIds.length,
|
| 79 |
+
outputSamples: waveform.length,
|
| 80 |
+
peakAbsoluteAmplitude: peak,
|
| 81 |
+
};
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
const maxPhonemes = catalog.runtime.maxPhonemeCodePoints;
|
| 85 |
+
const maxIds = [0, ...Array(maxPhonemes).fill(config.vocab.a), 0];
|
| 86 |
+
const result = {
|
| 87 |
+
language: languageId,
|
| 88 |
+
onnxRuntimeWebVersion: JSON.parse(
|
| 89 |
+
fs.readFileSync(path.join(root, 'node_modules/onnxruntime-web/package.json'), 'utf8'),
|
| 90 |
+
).version,
|
| 91 |
+
executionProvider: 'wasm',
|
| 92 |
+
cases: [
|
| 93 |
+
await validate(testCase.id, ids, styleAt(phonemes.length - 1)),
|
| 94 |
+
await validate('max-phoneme-boundary', maxIds, styleAt(maxPhonemes - 1)),
|
| 95 |
+
],
|
| 96 |
+
};
|
| 97 |
+
fs.writeFileSync(
|
| 98 |
+
path.join(root, 'validation', `web-${languageId}.json`),
|
| 99 |
+
`${JSON.stringify(result, null, 2)}\n`,
|
| 100 |
+
);
|
| 101 |
+
console.log(JSON.stringify(result));
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
main().catch((error) => {
|
| 105 |
+
console.error(error);
|
| 106 |
+
process.exitCode = 1;
|
| 107 |
+
});
|
third-party/kokoro/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
third-party/phonemis/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 IgorSwat
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
validation/cases.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "pl-mateusz",
|
| 4 |
+
"language": "pl",
|
| 5 |
+
"voice": "mateusz",
|
| 6 |
+
"text": "Zażółć gęślą jaźń.",
|
| 7 |
+
"phonemes": "zˈaʒuwtɕ ɡˈɛɲɕlɔ̃ jˈaʒɲ."
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"id": "pl-dynamic",
|
| 11 |
+
"language": "pl",
|
| 12 |
+
"voice": "mateusz",
|
| 13 |
+
"text": "W Szczebrzeszynie chrząszcz brzmi w trzcinie.",
|
| 14 |
+
"phonemes": "f ʃʧˌɛbʒɛʃˈɨɲʲɛ xʃˈɔ̃ʃʧ bʒmˈi f tʃtɕˈiɲʲɛ."
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"id": "de-anna",
|
| 18 |
+
"language": "de",
|
| 19 |
+
"voice": "anna",
|
| 20 |
+
"text": "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.",
|
| 21 |
+
"phonemes": "fˈalʃəs ˈyːbən fˈɔn ksˈyːloːfˌɔnmuːzˌiːk kvˈɛlt jˈeːdən ɡɾˈøːsərən ʦvˈɛɾk."
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"id": "de-dynamic",
|
| 25 |
+
"language": "de",
|
| 26 |
+
"voice": "anna",
|
| 27 |
+
"text": "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern.",
|
| 28 |
+
"phonemes": "frˈanʦ jˈɑːkt ˈɪm kɔmplˈɛt fɛɾvˈɑːɾlɔstən tˈaksiː kvˈeːɾ dˈʊɐç bˈIɜn."
|
| 29 |
+
}
|
| 30 |
+
]
|
validation/package-validation.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"catalogVersion": "1.0.0",
|
| 3 |
+
"catalogSchemaValidated": true,
|
| 4 |
+
"onnxRuntimeVersion": "1.29.0",
|
| 5 |
+
"artifactsVerified": 9,
|
| 6 |
+
"cases": [
|
| 7 |
+
{
|
| 8 |
+
"id": "pl-mateusz",
|
| 9 |
+
"phonemeCodePoints": 24,
|
| 10 |
+
"inputTokens": 26,
|
| 11 |
+
"outputSamples": 49200,
|
| 12 |
+
"durationSeconds": 2.05,
|
| 13 |
+
"peakAbsoluteAmplitude": 0.24918872117996216
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"id": "pl-dynamic",
|
| 17 |
+
"phonemeCodePoints": 42,
|
| 18 |
+
"inputTokens": 44,
|
| 19 |
+
"outputSamples": 60000,
|
| 20 |
+
"durationSeconds": 2.5,
|
| 21 |
+
"peakAbsoluteAmplitude": 0.25136497616767883
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"id": "de-anna",
|
| 25 |
+
"phonemeCodePoints": 74,
|
| 26 |
+
"inputTokens": 76,
|
| 27 |
+
"outputSamples": 90000,
|
| 28 |
+
"durationSeconds": 3.75,
|
| 29 |
+
"peakAbsoluteAmplitude": 0.35915330052375793
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"id": "de-dynamic",
|
| 33 |
+
"phonemeCodePoints": 69,
|
| 34 |
+
"inputTokens": 71,
|
| 35 |
+
"outputSamples": 84000,
|
| 36 |
+
"durationSeconds": 3.5,
|
| 37 |
+
"peakAbsoluteAmplitude": 0.3485631048679352
|
| 38 |
+
}
|
| 39 |
+
],
|
| 40 |
+
"boundaryCases": [
|
| 41 |
+
{
|
| 42 |
+
"language": "pl",
|
| 43 |
+
"phonemeCodePoints": 1,
|
| 44 |
+
"inputTokens": 3,
|
| 45 |
+
"outputSamples": 13800
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"language": "pl",
|
| 49 |
+
"phonemeCodePoints": 128,
|
| 50 |
+
"inputTokens": 130,
|
| 51 |
+
"outputSamples": 177600
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"language": "pl",
|
| 55 |
+
"phonemeCodePoints": 510,
|
| 56 |
+
"inputTokens": 512,
|
| 57 |
+
"outputSamples": 616800
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"language": "de",
|
| 61 |
+
"phonemeCodePoints": 1,
|
| 62 |
+
"inputTokens": 3,
|
| 63 |
+
"outputSamples": 16200
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"language": "de",
|
| 67 |
+
"phonemeCodePoints": 128,
|
| 68 |
+
"inputTokens": 130,
|
| 69 |
+
"outputSamples": 79800
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"language": "de",
|
| 73 |
+
"phonemeCodePoints": 510,
|
| 74 |
+
"inputTokens": 512,
|
| 75 |
+
"outputSamples": 307200
|
| 76 |
+
}
|
| 77 |
+
]
|
| 78 |
+
}
|
validation/web-de.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"language": "de",
|
| 3 |
+
"onnxRuntimeWebVersion": "1.29.0",
|
| 4 |
+
"executionProvider": "wasm",
|
| 5 |
+
"cases": [
|
| 6 |
+
{
|
| 7 |
+
"id": "de-dynamic",
|
| 8 |
+
"inputTokens": 71,
|
| 9 |
+
"outputSamples": 84000,
|
| 10 |
+
"peakAbsoluteAmplitude": 0.35137680172920227
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"id": "max-phoneme-boundary",
|
| 14 |
+
"inputTokens": 512,
|
| 15 |
+
"outputSamples": 307200,
|
| 16 |
+
"peakAbsoluteAmplitude": 0.32699844241142273
|
| 17 |
+
}
|
| 18 |
+
]
|
| 19 |
+
}
|
validation/web-pl.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"language": "pl",
|
| 3 |
+
"onnxRuntimeWebVersion": "1.29.0",
|
| 4 |
+
"executionProvider": "wasm",
|
| 5 |
+
"cases": [
|
| 6 |
+
{
|
| 7 |
+
"id": "pl-dynamic",
|
| 8 |
+
"inputTokens": 44,
|
| 9 |
+
"outputSamples": 60000,
|
| 10 |
+
"peakAbsoluteAmplitude": 0.2551245093345642
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"id": "max-phoneme-boundary",
|
| 14 |
+
"inputTokens": 512,
|
| 15 |
+
"outputSamples": 616800,
|
| 16 |
+
"peakAbsoluteAmplitude": 0.16947251558303833
|
| 17 |
+
}
|
| 18 |
+
]
|
| 19 |
+
}
|
voices/de/df_anna.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b
|
| 3 |
+
size 522240
|
voices/pl/pm_mateusz.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:dc8f2919ede945e6962310b5204b912e64689d5698c571822bf75ad704870cb4
|
| 3 |
+
size 522240
|