Spaces:
Running
Running
AksharaLP demo v1.0.0
Browse files- .gitattributes +4 -34
- LICENSE +209 -0
- NOTICE +80 -0
- README.md +42 -6
- assets/favicon.svg +1 -0
- css/app.css +353 -0
- fonts/Inter-var.woff2 +0 -0
- fonts/NotoSansDevanagari-var.woff2 +3 -0
- fonts/OFL-Inter.txt +93 -0
- fonts/OFL-NotoSansDevanagari.txt +93 -0
- index.html +169 -17
- js/aksharalp.mjs +718 -0
- js/app.js +407 -0
- js/worker.js +40 -0
- model/dict/lex.bin +3 -0
- model/dict/lm.bin +3 -0
- model/dict/params.json +545 -0
- model/manifest.json +59 -0
- model/params.json +544 -0
- model/xlit.q4 +3 -0
- sw.js +33 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,5 @@
|
|
| 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 |
-
*.
|
| 5 |
-
*.
|
| 6 |
-
*.
|
| 7 |
-
*.
|
| 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 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 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 |
+
*.int8 filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.q4 filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.q8 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.woff2 filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
AksharaLP by Sourojit Dhua — https://huggingface.co/sourojitdotcom/AksharaLP-1M
|
| 2 |
+
Copyright 2026 Sourojit Dhua
|
| 3 |
+
|
| 4 |
+
Licensed under the Apache License, Version 2.0 (the full text follows). Commercial use is permitted.
|
| 5 |
+
Redistributions and derivative works must include the attribution notices in the accompanying
|
| 6 |
+
NOTICE file, as required by Section 4(d) of the License.
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
Apache License
|
| 10 |
+
Version 2.0, January 2004
|
| 11 |
+
http://www.apache.org/licenses/
|
| 12 |
+
|
| 13 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 14 |
+
|
| 15 |
+
1. Definitions.
|
| 16 |
+
|
| 17 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 18 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 19 |
+
|
| 20 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 21 |
+
the copyright owner that is granting the License.
|
| 22 |
+
|
| 23 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 24 |
+
other entities that control, are controlled by, or are under common
|
| 25 |
+
control with that entity. For the purposes of this definition,
|
| 26 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 27 |
+
direction or management of such entity, whether by contract or
|
| 28 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 29 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 30 |
+
|
| 31 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 32 |
+
exercising permissions granted by this License.
|
| 33 |
+
|
| 34 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 35 |
+
including but not limited to software source code, documentation
|
| 36 |
+
source, and configuration files.
|
| 37 |
+
|
| 38 |
+
"Object" form shall mean any form resulting from mechanical
|
| 39 |
+
transformation or translation of a Source form, including but
|
| 40 |
+
not limited to compiled object code, generated documentation,
|
| 41 |
+
and conversions to other media types.
|
| 42 |
+
|
| 43 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 44 |
+
Object form, made available under the License, as indicated by a
|
| 45 |
+
copyright notice that is included in or attached to the work
|
| 46 |
+
(an example is provided in the Appendix below).
|
| 47 |
+
|
| 48 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 49 |
+
form, that is based on (or derived from) the Work and for which the
|
| 50 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 51 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 52 |
+
of this License, Derivative Works shall not include works that remain
|
| 53 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 54 |
+
the Work and Derivative Works thereof.
|
| 55 |
+
|
| 56 |
+
"Contribution" shall mean any work of authorship, including
|
| 57 |
+
the original version of the Work and any modifications or additions
|
| 58 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 59 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 60 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 61 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 62 |
+
means any form of electronic, verbal, or written communication sent
|
| 63 |
+
to the Licensor or its representatives, including but not limited to
|
| 64 |
+
communication on electronic mailing lists, source code control systems,
|
| 65 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 66 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 67 |
+
excluding communication that is conspicuously marked or otherwise
|
| 68 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 69 |
+
|
| 70 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 71 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 72 |
+
subsequently incorporated within the Work.
|
| 73 |
+
|
| 74 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 78 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 79 |
+
Work and such Derivative Works in Source or Object form.
|
| 80 |
+
|
| 81 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 82 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 83 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 84 |
+
(except as stated in this section) patent license to make, have made,
|
| 85 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 86 |
+
where such license applies only to those patent claims licensable
|
| 87 |
+
by such Contributor that are necessarily infringed by their
|
| 88 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 89 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 90 |
+
institute patent litigation against any entity (including a
|
| 91 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 92 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 93 |
+
or contributory patent infringement, then any patent licenses
|
| 94 |
+
granted to You under this License for that Work shall terminate
|
| 95 |
+
as of the date such litigation is filed.
|
| 96 |
+
|
| 97 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 98 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 99 |
+
modifications, and in Source or Object form, provided that You
|
| 100 |
+
meet the following conditions:
|
| 101 |
+
|
| 102 |
+
(a) You must give any other recipients of the Work or
|
| 103 |
+
Derivative Works a copy of this License; and
|
| 104 |
+
|
| 105 |
+
(b) You must cause any modified files to carry prominent notices
|
| 106 |
+
stating that You changed the files; and
|
| 107 |
+
|
| 108 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 109 |
+
that You distribute, all copyright, patent, trademark, and
|
| 110 |
+
attribution notices from the Source form of the Work,
|
| 111 |
+
excluding those notices that do not pertain to any part of
|
| 112 |
+
the Derivative Works; and
|
| 113 |
+
|
| 114 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 115 |
+
distribution, then any Derivative Works that You distribute must
|
| 116 |
+
include a readable copy of the attribution notices contained
|
| 117 |
+
within such NOTICE file, excluding those notices that do not
|
| 118 |
+
pertain to any part of the Derivative Works, in at least one
|
| 119 |
+
of the following places: within a NOTICE text file distributed
|
| 120 |
+
as part of the Derivative Works; within the Source form or
|
| 121 |
+
documentation, if provided along with the Derivative Works; or,
|
| 122 |
+
within a display generated by the Derivative Works, if and
|
| 123 |
+
wherever such third-party notices normally appear. The contents
|
| 124 |
+
of the NOTICE file are for informational purposes only and
|
| 125 |
+
do not modify the License. You may add Your own attribution
|
| 126 |
+
notices within Derivative Works that You distribute, alongside
|
| 127 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 128 |
+
that such additional attribution notices cannot be construed
|
| 129 |
+
as modifying the License.
|
| 130 |
+
|
| 131 |
+
You may add Your own copyright statement to Your modifications and
|
| 132 |
+
may provide additional or different license terms and conditions
|
| 133 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 134 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 135 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 136 |
+
the conditions stated in this License.
|
| 137 |
+
|
| 138 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 139 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 140 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 141 |
+
this License, without any additional terms or conditions.
|
| 142 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 143 |
+
the terms of any separate license agreement you may have executed
|
| 144 |
+
with Licensor regarding such Contributions.
|
| 145 |
+
|
| 146 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 147 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 148 |
+
except as required for reasonable and customary use in describing the
|
| 149 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 150 |
+
|
| 151 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 152 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 153 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 154 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 155 |
+
implied, including, without limitation, any warranties or conditions
|
| 156 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 157 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 158 |
+
appropriateness of using or redistributing the Work and assume any
|
| 159 |
+
risks associated with Your exercise of permissions under this License.
|
| 160 |
+
|
| 161 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 162 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 163 |
+
unless required by applicable law (such as deliberate and grossly
|
| 164 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 165 |
+
liable to You for damages, including any direct, indirect, special,
|
| 166 |
+
incidental, or consequential damages of any character arising as a
|
| 167 |
+
result of this License or out of the use or inability to use the
|
| 168 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 169 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 170 |
+
other commercial damages or losses), even if such Contributor
|
| 171 |
+
has been advised of the possibility of such damages.
|
| 172 |
+
|
| 173 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 174 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 175 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 176 |
+
or other liability obligations and/or rights consistent with this
|
| 177 |
+
License. However, in accepting such obligations, You may act only
|
| 178 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 179 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 180 |
+
defend, and hold each Contributor harmless for any liability
|
| 181 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 182 |
+
of your accepting any such warranty or additional liability.
|
| 183 |
+
|
| 184 |
+
END OF TERMS AND CONDITIONS
|
| 185 |
+
|
| 186 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 187 |
+
|
| 188 |
+
To apply the Apache License to your work, attach the following
|
| 189 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 190 |
+
replaced with your own identifying information. (Don't include
|
| 191 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 192 |
+
comment syntax for the file format. We also recommend that a
|
| 193 |
+
file or class name and description of purpose be included on the
|
| 194 |
+
same "printed page" as the copyright notice for easier
|
| 195 |
+
identification within third-party archives.
|
| 196 |
+
|
| 197 |
+
Copyright [yyyy] [name of copyright owner]
|
| 198 |
+
|
| 199 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 200 |
+
you may not use this file except in compliance with the License.
|
| 201 |
+
You may obtain a copy of the License at
|
| 202 |
+
|
| 203 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 204 |
+
|
| 205 |
+
Unless required by applicable law or agreed to in writing, software
|
| 206 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 207 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 208 |
+
See the License for the specific language governing permissions and
|
| 209 |
+
limitations under the License.
|
NOTICE
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
AksharaLP by Sourojit Dhua — https://huggingface.co/sourojitdotcom/AksharaLP-1M
|
| 2 |
+
Copyright 2026 Sourojit Dhua
|
| 3 |
+
|
| 4 |
+
AksharaLP-1M (model weights, word lists and JavaScript/Python runtime) is licensed under the
|
| 5 |
+
Apache License, Version 2.0 (see LICENSE). Commercial use is permitted.
|
| 6 |
+
|
| 7 |
+
ATTRIBUTION
|
| 8 |
+
Under Section 4(d) of the Apache License, any redistribution of this work or of a Derivative Work
|
| 9 |
+
(for example: shipping these files in an app, a web page, a browser extension or an SDK, or
|
| 10 |
+
releasing a fine-tuned, quantized or converted model based on it) must include a readable copy of
|
| 11 |
+
this NOTICE file. Please use the following attribution text:
|
| 12 |
+
|
| 13 |
+
Transliteration by AksharaLP (Sourojit Dhua) — https://huggingface.co/sourojitdotcom/AksharaLP-1M
|
| 14 |
+
|
| 15 |
+
Recommended in-app credit (e.g. in an About, Settings or Licenses screen):
|
| 16 |
+
|
| 17 |
+
Hindi typing powered by AksharaLP by Sourojit Dhua
|
| 18 |
+
|
| 19 |
+
The model files in this repository were built with the help of the following
|
| 20 |
+
third-party resources. No third-party data is redistributed in this repository
|
| 21 |
+
other than as learned model parameters and derived word lists.
|
| 22 |
+
|
| 23 |
+
------------------------------------------------------------------------------
|
| 24 |
+
Aksharantar — AI4Bharat
|
| 25 |
+
https://huggingface.co/datasets/ai4bharat/Aksharantar
|
| 26 |
+
License: CC0 (mined data and existing sources) / CC-BY (manually collected data)
|
| 27 |
+
Used for: romanized <-> Devanagari word pairs for training.
|
| 28 |
+
Note from the dataset card: "We do not own any of the text from which this data has been extracted."
|
| 29 |
+
|
| 30 |
+
IndicXlit — AI4Bharat
|
| 31 |
+
https://github.com/AI4Bharat/IndicXlit
|
| 32 |
+
License: MIT. Copyright (c) 2022 AI4Bhārat
|
| 33 |
+
Used for: teacher model for knowledge distillation.
|
| 34 |
+
|
| 35 |
+
IndicCorp v2 — AI4Bharat
|
| 36 |
+
https://github.com/AI4Bharat/IndicBERT/tree/main#indiccorp-v2
|
| 37 |
+
License: CC0
|
| 38 |
+
Used for: Hindi lexicon and word-bigram language model (lex.bin, lm.bin).
|
| 39 |
+
|
| 40 |
+
CMUdict — Carnegie Mellon University
|
| 41 |
+
https://github.com/cmusphinx/cmudict
|
| 42 |
+
License: BSD-2-Clause-style. The full notice is reproduced below.
|
| 43 |
+
Used for: English word cues.
|
| 44 |
+
|
| 45 |
+
------------------------------------------------------------------------------
|
| 46 |
+
CMUdict license notice:
|
| 47 |
+
|
| 48 |
+
Copyright (C) 1993-2015 Carnegie Mellon University. All rights reserved.
|
| 49 |
+
|
| 50 |
+
Redistribution and use in source and binary forms, with or without
|
| 51 |
+
modification, are permitted provided that the following conditions
|
| 52 |
+
are met:
|
| 53 |
+
|
| 54 |
+
1. Redistributions of source code must retain the above copyright
|
| 55 |
+
notice, this list of conditions and the following disclaimer.
|
| 56 |
+
The contents of this file are deemed to be source code.
|
| 57 |
+
|
| 58 |
+
2. Redistributions in binary form must reproduce the above copyright
|
| 59 |
+
notice, this list of conditions and the following disclaimer in
|
| 60 |
+
the documentation and/or other materials provided with the
|
| 61 |
+
distribution.
|
| 62 |
+
|
| 63 |
+
This work was supported in part by funding from the Defense Advanced
|
| 64 |
+
Research Projects Agency, the Office of Naval Research and the National
|
| 65 |
+
Science Foundation of the United States of America, and by member
|
| 66 |
+
companies of the Carnegie Mellon Sphinx Speech Consortium. We acknowledge
|
| 67 |
+
the contributions of many volunteers to the expansion and improvement of
|
| 68 |
+
this dictionary.
|
| 69 |
+
|
| 70 |
+
THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
|
| 71 |
+
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
| 72 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 73 |
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
|
| 74 |
+
NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 75 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 76 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 77 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 78 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 79 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 80 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
README.md
CHANGED
|
@@ -1,10 +1,46 @@
|
|
| 1 |
---
|
| 2 |
-
title: AksharaLP
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: AksharaLP — Hindi Transliteration
|
| 3 |
+
emoji: 🪔
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: pink
|
| 6 |
sdk: static
|
| 7 |
+
app_file: index.html
|
| 8 |
+
pinned: true
|
| 9 |
+
license: apache-2.0
|
| 10 |
+
short_description: Tiny on-device romanized Hindi → Devanagari transliteration
|
| 11 |
+
models:
|
| 12 |
+
- sourojitdotcom/AksharaLP-1M
|
| 13 |
+
tags:
|
| 14 |
+
- transliteration
|
| 15 |
+
- hindi
|
| 16 |
+
- devanagari
|
| 17 |
+
- on-device
|
| 18 |
---
|
| 19 |
|
| 20 |
+
# AksharaLP — live demo
|
| 21 |
+
|
| 22 |
+
Type romanized Hindi and get Devanagari as you type. Everything runs **entirely in your browser** in a Web Worker —
|
| 23 |
+
no server, no API key, nothing you type leaves the page.
|
| 24 |
+
|
| 25 |
+
- **Two-tier download:** the core (0.57 MB gzipped: character model + reranker + runtime) starts working right away;
|
| 26 |
+
the dictionary pack (3.97 MB gzipped: 1.5M-word lexicon + bigram LM) is fetched in the background on
|
| 27 |
+
first use and cached (Cache API). If the pack cannot be loaded, the demo keeps working with the core alone (lower accuracy).
|
| 28 |
+
Add `?dict=0` to the URL to try the core only.
|
| 29 |
+
- **Modes:** Default · Strict (brand names stay in Latin)
|
| 30 |
+
- **Sentence context** (with the pack): a compact bigram LM picks the right word for ambiguous spellings (e.g. *main* → मैं / में)
|
| 31 |
+
- **Suggestions:** click any output word for ranked alternatives; picking one re-decodes the rest of the sentence
|
| 32 |
+
- After the first visit it works offline.
|
| 33 |
+
|
| 34 |
+
Model card, benchmarks and licensing: [sourojitdotcom/AksharaLP-1M](https://huggingface.co/sourojitdotcom/AksharaLP-1M)
|
| 35 |
+
|
| 36 |
+
Runtime: `js/aksharalp.mjs` — a dependency-free ES module (Apache-2.0) you can use in your own app.
|
| 37 |
+
Fonts: Inter and Noto Sans Devanagari, SIL Open Font License 1.1 (see `fonts/`).
|
| 38 |
+
|
| 39 |
+
## License & attribution
|
| 40 |
+
|
| 41 |
+
Apache-2.0, Copyright 2026 Sourojit Dhua. Commercial use is allowed; redistributions and derivatives must include
|
| 42 |
+
the `NOTICE` file (Apache-2.0 §4(d)). Attribution text:
|
| 43 |
+
|
| 44 |
+
```text
|
| 45 |
+
Transliteration by AksharaLP (Sourojit Dhua) — https://huggingface.co/sourojitdotcom/AksharaLP-1M
|
| 46 |
+
```
|
assets/favicon.svg
ADDED
|
|
css/app.css
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@font-face { font-family: "Inter"; src: url("../fonts/Inter-var.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
|
| 2 |
+
@font-face { font-family: "Noto Sans Devanagari"; src: url("../fonts/NotoSansDevanagari-var.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
|
| 3 |
+
|
| 4 |
+
:root {
|
| 5 |
+
--font: "Inter", "Noto Sans Devanagari", system-ui, -apple-system, "Segoe UI", sans-serif;
|
| 6 |
+
--deva: "Noto Sans Devanagari", "Inter", sans-serif;
|
| 7 |
+
--bg: #f6f6fb; --bg2: #ffffff; --ink: #0f1222; --ink2: #4a4f6a; --ink3: #8a8fa8;
|
| 8 |
+
--line: rgba(15, 18, 34, .08); --line2: rgba(15, 18, 34, .14);
|
| 9 |
+
--card: rgba(255, 255, 255, .78); --card-solid: #fff; --glass-blur: 18px;
|
| 10 |
+
--accent: #6d4aff; --a1: #6366f1; --a2: #a855f7; --a3: #f97316; --a4: #ec4899;
|
| 11 |
+
--hi: #7c3aed; --en: #0ea5e9; --dev: #f97316; --oth: #94a3b8;
|
| 12 |
+
--shadow: 0 1px 2px rgba(16, 20, 50, .04), 0 8px 24px -6px rgba(16, 20, 50, .10), 0 30px 60px -30px rgba(80, 60, 200, .18);
|
| 13 |
+
--radius: 22px; --ease: cubic-bezier(.2, .8, .2, 1);
|
| 14 |
+
color-scheme: light;
|
| 15 |
+
}
|
| 16 |
+
:root[data-theme="dark"] {
|
| 17 |
+
--bg: #090b14; --bg2: #0e1120; --ink: #eef0ff; --ink2: #b3b8d6; --ink3: #7b81a3;
|
| 18 |
+
--line: rgba(255, 255, 255, .07); --line2: rgba(255, 255, 255, .13);
|
| 19 |
+
--card: rgba(18, 21, 38, .72); --card-solid: #12152a;
|
| 20 |
+
--shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 20px 50px -20px rgba(0, 0, 0, .7), 0 0 0 1px rgba(255, 255, 255, .03);
|
| 21 |
+
color-scheme: dark;
|
| 22 |
+
}
|
| 23 |
+
@media (prefers-color-scheme: dark) {
|
| 24 |
+
:root[data-theme="auto"] {
|
| 25 |
+
--bg: #090b14; --bg2: #0e1120; --ink: #eef0ff; --ink2: #b3b8d6; --ink3: #7b81a3;
|
| 26 |
+
--line: rgba(255, 255, 255, .07); --line2: rgba(255, 255, 255, .13);
|
| 27 |
+
--card: rgba(18, 21, 38, .72); --card-solid: #12152a;
|
| 28 |
+
--shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 20px 50px -20px rgba(0, 0, 0, .7), 0 0 0 1px rgba(255, 255, 255, .03);
|
| 29 |
+
color-scheme: dark;
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
* { box-sizing: border-box; }
|
| 34 |
+
html, body { margin: 0; }
|
| 35 |
+
body { font-family: var(--font); background: var(--bg); color: var(--ink); -webkit-font-smoothing: antialiased; font-feature-settings: "cv11", "ss01"; line-height: 1.5;
|
| 36 |
+
transition: background .4s var(--ease), color .4s var(--ease); overflow-x: hidden; }
|
| 37 |
+
a { color: inherit; }
|
| 38 |
+
.deva { font-family: var(--deva); }
|
| 39 |
+
|
| 40 |
+
/* ---------- ambient background */
|
| 41 |
+
.bg { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
|
| 42 |
+
.blob { position: absolute; border-radius: 50%; filter: blur(80px); opacity: .55; animation: float 22s var(--ease) infinite alternate; }
|
| 43 |
+
.b1 { width: 620px; height: 620px; background: radial-gradient(circle at 30% 30%, #8b7bff, transparent 65%); top: -220px; left: -160px; }
|
| 44 |
+
.b2 { width: 560px; height: 560px; background: radial-gradient(circle at 50% 50%, #ff9a5a, transparent 65%); top: -120px; right: -200px; animation-delay: -6s; opacity: .38; }
|
| 45 |
+
.b3 { width: 700px; height: 700px; background: radial-gradient(circle at 50% 50%, #e879f9, transparent 65%); top: 520px; left: 35%; animation-delay: -12s; opacity: .22; }
|
| 46 |
+
:root[data-theme="dark"] .blob { opacity: .28; }
|
| 47 |
+
@media (prefers-color-scheme: dark) { :root[data-theme="auto"] .blob { opacity: .28; } }
|
| 48 |
+
.grid { position: absolute; inset: 0; background-image: linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px);
|
| 49 |
+
background-size: 56px 56px; mask-image: radial-gradient(ellipse 70% 50% at 50% 0%, #000 30%, transparent 75%); opacity: .55; }
|
| 50 |
+
@keyframes float { to { transform: translate3d(40px, 30px, 0) scale(1.08); } }
|
| 51 |
+
|
| 52 |
+
/* ---------- nav */
|
| 53 |
+
.nav { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between; padding: 14px clamp(16px, 4vw, 40px);
|
| 54 |
+
backdrop-filter: saturate(1.4) blur(14px); -webkit-backdrop-filter: saturate(1.4) blur(14px); background: color-mix(in oklab, var(--bg) 70%, transparent); border-bottom: 1px solid var(--line); }
|
| 55 |
+
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
|
| 56 |
+
.mark { width: 34px; height: 34px; filter: drop-shadow(0 6px 14px rgba(124, 58, 237, .35)); }
|
| 57 |
+
.brand-name { font-weight: 750; letter-spacing: -.02em; font-size: 18px; }
|
| 58 |
+
.brand-tag { font-size: 12px; color: var(--ink3); border: 1px solid var(--line2); padding: 2px 8px; border-radius: 99px; }
|
| 59 |
+
.nav-right { display: flex; align-items: center; gap: 10px; }
|
| 60 |
+
.nav-link { text-decoration: none; font-size: 14px; font-weight: 550; color: var(--ink2); padding: 8px 12px; border-radius: 10px; transition: background .2s; }
|
| 61 |
+
.nav-link:hover { background: var(--line); color: var(--ink); }
|
| 62 |
+
.pill { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 550; padding: 6px 12px; border-radius: 99px; background: var(--card); border: 1px solid var(--line2); color: var(--ink2); }
|
| 63 |
+
.status .dot { width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; box-shadow: 0 0 0 0 rgba(245, 158, 11, .6); animation: pulse 1.6s infinite; }
|
| 64 |
+
.status.ready .dot { background: #10b981; animation: pulse-g 2.4s infinite; }
|
| 65 |
+
@keyframes pulse { 70% { box-shadow: 0 0 0 8px rgba(245, 158, 11, 0); } 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); } }
|
| 66 |
+
@keyframes pulse-g { 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, .55); } 70% { box-shadow: 0 0 0 8px rgba(16, 185, 129, 0); } 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } }
|
| 67 |
+
.icon-btn { width: 38px; height: 38px; border-radius: 11px; border: 1px solid var(--line2); background: var(--card); color: var(--ink); display: grid; place-items: center; cursor: pointer; transition: transform .2s var(--ease); }
|
| 68 |
+
.icon-btn:hover { transform: rotate(-12deg); }
|
| 69 |
+
.icon-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; grid-area: 1/1; transition: opacity .3s, transform .4s var(--ease); }
|
| 70 |
+
.icon-btn .moon { fill: currentColor; stroke: none; }
|
| 71 |
+
:root .icon-btn .moon, :root[data-theme="dark"] .icon-btn .sun { opacity: 0; transform: scale(.5) rotate(-60deg); }
|
| 72 |
+
:root[data-theme="dark"] .icon-btn .moon { opacity: 1; transform: none; }
|
| 73 |
+
@media (prefers-color-scheme: dark) { :root[data-theme="auto"] .icon-btn .sun { opacity: 0; } :root[data-theme="auto"] .icon-btn .moon { opacity: 1; transform: none; } }
|
| 74 |
+
|
| 75 |
+
/* ---------- hero */
|
| 76 |
+
main { max-width: 1160px; margin: 0 auto; padding: 0 clamp(16px, 4vw, 40px); }
|
| 77 |
+
.hero { text-align: center; padding: clamp(34px, 6vw, 64px) 0 30px; animation: rise .9s var(--ease) both; }
|
| 78 |
+
.eyebrow { display: inline-flex; gap: 8px; align-items: center; font-size: 13px; font-weight: 600; color: var(--ink2); background: var(--card); border: 1px solid var(--line2);
|
| 79 |
+
padding: 7px 14px; border-radius: 99px; box-shadow: var(--shadow); }
|
| 80 |
+
.spark { background: linear-gradient(90deg, var(--a1), var(--a3)); -webkit-background-clip: text; background-clip: text; color: transparent; }
|
| 81 |
+
h1 { font-size: clamp(30px, 4.9vw, 58px); line-height: 1.06; letter-spacing: -.04em; font-weight: 800; margin: 22px auto 18px; max-width: 1020px; text-wrap: balance; }
|
| 82 |
+
.grad { background: linear-gradient(100deg, var(--a1) 0%, var(--a2) 40%, var(--a4) 70%, var(--a3) 100%); background-size: 200% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
|
| 83 |
+
animation: sheen 8s ease-in-out infinite alternate; }
|
| 84 |
+
@keyframes sheen { to { background-position: 100% 0; } }
|
| 85 |
+
.lede { max-width: 700px; margin: 0 auto; font-size: clamp(16px, 2vw, 19px); color: var(--ink2); }
|
| 86 |
+
.lede-strong { color: var(--ink); font-weight: 700; display: block; margin-bottom: 4px; }
|
| 87 |
+
.stats { display: inline-grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 26px auto 0; border: 1px solid var(--line2); border-radius: 18px; background: var(--card); box-shadow: var(--shadow); overflow: hidden; }
|
| 88 |
+
.stat { padding: 14px 26px; display: flex; gap: 12px; align-items: center; text-align: left; }
|
| 89 |
+
.stat + .stat { border-left: 1px solid var(--line2); }
|
| 90 |
+
.stat b { font-size: 26px; font-weight: 800; letter-spacing: -.03em; background: linear-gradient(100deg, var(--a1), var(--a4)); -webkit-background-clip: text; background-clip: text; color: transparent; white-space: nowrap; }
|
| 91 |
+
.stat span { font-size: 12.5px; line-height: 1.3; color: var(--ink2); }
|
| 92 |
+
.stat-src { margin: 10px 0 0; font-size: 11.5px; color: var(--ink3, var(--ink2)); opacity: .8; }
|
| 93 |
+
.stat-src a { color: inherit; }
|
| 94 |
+
@media (max-width: 600px) { .stats { grid-template-columns: 1fr; width: 100%; } .stat + .stat { border-left: 0; border-top: 1px solid var(--line2); } .stat { padding: 10px 18px; } .stat b { min-width: 74px; } }
|
| 95 |
+
.size-chip { font-weight: 700; color: var(--ink); background: linear-gradient(90deg, rgba(99, 102, 241, .14), rgba(249, 115, 22, .14)); padding: 1px 9px; border-radius: 8px; white-space: nowrap; }
|
| 96 |
+
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
|
| 97 |
+
|
| 98 |
+
/* ---------- cards */
|
| 99 |
+
.card { background: var(--card); border: 1px solid var(--line2); border-radius: var(--radius); box-shadow: var(--shadow); backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur)); }
|
| 100 |
+
.playground { position: relative; padding: 18px; animation: rise 1s .1s var(--ease) both; }
|
| 101 |
+
.playground::before { content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px; background: linear-gradient(120deg, rgba(99, 102, 241, .55), rgba(168, 85, 247, .15) 35%, rgba(249, 115, 22, .45));
|
| 102 |
+
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; }
|
| 103 |
+
|
| 104 |
+
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 2px 2px 14px; }
|
| 105 |
+
.spacer { flex: 1; }
|
| 106 |
+
.seg { position: relative; display: inline-flex; background: color-mix(in oklab, var(--ink) 6%, transparent); border-radius: 13px; padding: 4px; }
|
| 107 |
+
.seg button { position: relative; z-index: 1; border: 0; background: none; font: inherit; font-size: 13.5px; font-weight: 600; color: var(--ink2); padding: 8px 14px; border-radius: 10px; cursor: pointer; transition: color .25s; white-space: nowrap; }
|
| 108 |
+
.seg button[aria-checked="true"] { color: var(--ink); }
|
| 109 |
+
.seg-glider { position: absolute; top: 4px; bottom: 4px; left: 4px; border-radius: 10px; background: var(--card-solid); box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 4px 14px -6px rgba(80, 60, 200, .35);
|
| 110 |
+
transition: transform .35s var(--ease), width .35s var(--ease); }
|
| 111 |
+
.switch { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 600; color: var(--ink2); cursor: pointer; user-select: none; }
|
| 112 |
+
.switch input { position: absolute; opacity: 0; pointer-events: none; }
|
| 113 |
+
.track { width: 38px; height: 22px; border-radius: 99px; background: color-mix(in oklab, var(--ink) 18%, transparent); position: relative; transition: background .25s; }
|
| 114 |
+
.thumb { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .25); transition: transform .3s var(--ease); }
|
| 115 |
+
.switch input:checked + .track { background: linear-gradient(90deg, var(--a1), var(--a2)); }
|
| 116 |
+
.switch input:checked + .track .thumb { transform: translateX(16px); }
|
| 117 |
+
.switch input:focus-visible + .track { outline: 2px solid var(--a2); outline-offset: 2px; }
|
| 118 |
+
.lang-badge { font-size: 12.5px; font-weight: 650; padding: 6px 11px; border-radius: 99px; border: 1px solid var(--line2); display: inline-flex; gap: 7px; align-items: center; animation: pop .35s var(--ease); }
|
| 119 |
+
.lang-badge::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--c, var(--hi)); }
|
| 120 |
+
|
| 121 |
+
.panes { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
| 122 |
+
.pane { border-radius: 16px; border: 1px solid var(--line2); background: var(--bg2); padding: 14px 16px 16px; min-height: 210px; display: flex; flex-direction: column; transition: border-color .25s, box-shadow .25s; }
|
| 123 |
+
.pane.in:focus-within { border-color: color-mix(in oklab, var(--a2) 60%, transparent); box-shadow: 0 0 0 4px color-mix(in oklab, var(--a2) 14%, transparent); }
|
| 124 |
+
.pane.out { background: linear-gradient(180deg, color-mix(in oklab, var(--a1) 5%, var(--bg2)), var(--bg2)); }
|
| 125 |
+
.pane-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; min-height: 30px; }
|
| 126 |
+
.label { font-size: 12px; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; color: var(--ink3); }
|
| 127 |
+
.deva-label { font-family: var(--deva); text-transform: none; letter-spacing: 0; font-size: 13px; }
|
| 128 |
+
textarea { flex: 1; width: 100%; resize: none; border: 0; outline: 0; background: transparent; color: var(--ink); font: 500 clamp(18px, 2.2vw, 22px)/1.55 var(--font); letter-spacing: -.01em; }
|
| 129 |
+
textarea::placeholder { color: var(--ink3); opacity: .8; }
|
| 130 |
+
.output { flex: 1; font-family: var(--deva); font-size: clamp(22px, 2.8vw, 30px); line-height: 1.6; font-weight: 500; word-wrap: break-word; }
|
| 131 |
+
.output .ph { color: var(--ink3); opacity: .6; font-size: .8em; }
|
| 132 |
+
.w { position: relative; display: inline; border-radius: 8px; padding: 0 2px; cursor: pointer; transition: background .2s; }
|
| 133 |
+
.wt { background-image: linear-gradient(var(--c), var(--c)); background-size: 100% 2px; background-position: 0 96%; background-repeat: no-repeat; padding-bottom: 2px; }
|
| 134 |
+
.pn { color: var(--ink2); }
|
| 135 |
+
.w:hover, .w.sel { background-color: color-mix(in oklab, var(--c) 14%, transparent); }
|
| 136 |
+
.w.lang-HI { --c: color-mix(in oklab, var(--hi) 55%, transparent); }
|
| 137 |
+
.w.lang-EN { --c: color-mix(in oklab, var(--en) 60%, transparent); }
|
| 138 |
+
.w.lang-DEV { --c: color-mix(in oklab, var(--dev) 55%, transparent); }
|
| 139 |
+
.w.pinned { --c: var(--a3); }
|
| 140 |
+
.w.new { animation: wordin .45s var(--ease) both; }
|
| 141 |
+
@keyframes wordin { from { opacity: 0; filter: blur(4px); transform: translateY(6px); } to { opacity: 1; filter: none; transform: none; } }
|
| 142 |
+
.ghost-btn, .copy-btn { font: inherit; font-size: 12.5px; font-weight: 600; color: var(--ink2); border: 1px solid var(--line2); background: var(--card-solid); border-radius: 10px; padding: 6px 11px; cursor: pointer; display: inline-flex; gap: 6px; align-items: center; transition: transform .15s, background .2s, color .2s; }
|
| 143 |
+
.ghost-btn:hover, .copy-btn:hover:not(:disabled) { color: var(--ink); transform: translateY(-1px); }
|
| 144 |
+
.copy-btn svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; }
|
| 145 |
+
.copy-btn.done { color: #10b981; border-color: rgba(16, 185, 129, .45); }
|
| 146 |
+
.copy-btn:disabled { opacity: .5; cursor: default; }
|
| 147 |
+
|
| 148 |
+
.suggest { display: flex; align-items: center; gap: 12px; padding: 14px 4px 4px; min-height: 58px; }
|
| 149 |
+
.suggest-label { font-size: 12px; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; color: var(--ink3); white-space: nowrap; }
|
| 150 |
+
.chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
| 151 |
+
.chips .hint { color: var(--ink3); font-size: 13.5px; }
|
| 152 |
+
.chips .src { font-size: 13px; color: var(--ink3); margin-right: 2px; font-weight: 600; }
|
| 153 |
+
.chip { position: relative; overflow: hidden; font-family: var(--deva); font-size: 18px; font-weight: 500; padding: 5px 14px 7px; border-radius: 12px; border: 1px solid var(--line2); background: var(--card-solid); color: var(--ink); cursor: pointer;
|
| 154 |
+
transition: transform .18s var(--ease), border-color .2s, box-shadow .2s; animation: pop .35s var(--ease) both; }
|
| 155 |
+
.chip:hover { transform: translateY(-2px); border-color: color-mix(in oklab, var(--a2) 55%, transparent); box-shadow: 0 6px 16px -8px rgba(124, 58, 237, .5); }
|
| 156 |
+
.chip.on { border-color: transparent; color: #fff; background: linear-gradient(120deg, var(--a1), var(--a2)); }
|
| 157 |
+
.chip .p { position: absolute; left: 0; bottom: 0; height: 2px; background: linear-gradient(90deg, var(--a1), var(--a3)); border-radius: 2px; }
|
| 158 |
+
.chip.on .p { background: rgba(255, 255, 255, .7); }
|
| 159 |
+
.chip .rk { font-family: var(--font); font-size: 10.5px; font-weight: 700; opacity: .55; margin-left: 6px; vertical-align: 2px; }
|
| 160 |
+
.chip.latin { font-family: var(--font); font-size: 15px; }
|
| 161 |
+
@keyframes pop { from { opacity: 0; transform: scale(.92) translateY(4px); } to { opacity: 1; transform: none; } }
|
| 162 |
+
|
| 163 |
+
.meter { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-top: 12px; border-top: 1px solid var(--line); padding-top: 14px; }
|
| 164 |
+
.m { display: flex; flex-direction: column; gap: 2px; padding: 0 6px; }
|
| 165 |
+
.m .k { font-size: 11.5px; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; color: var(--ink3); }
|
| 166 |
+
.m .v { font-size: 17px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
|
| 167 |
+
.m .v small { font-size: 12px; font-weight: 600; color: var(--ink3); margin-left: 3px; }
|
| 168 |
+
.lock { font-size: 13px; }
|
| 169 |
+
.loader { position: absolute; left: 18px; right: 18px; bottom: 10px; display: flex; gap: 12px; align-items: center; font-size: 12.5px; color: var(--ink3); transition: opacity .5s; }
|
| 170 |
+
.loader .bar { flex: 1; height: 3px; border-radius: 3px; background: var(--line); overflow: hidden; }
|
| 171 |
+
.loader .bar span { display: block; height: 100%; width: 40%; background: linear-gradient(90deg, var(--a1), var(--a3)); border-radius: 3px; animation: load 1.2s ease-in-out infinite; }
|
| 172 |
+
@keyframes load { from { transform: translateX(-100%); } to { transform: translateX(260%); } }
|
| 173 |
+
.loader.gone { opacity: 0; pointer-events: none; }
|
| 174 |
+
|
| 175 |
+
/* ---------- sections */
|
| 176 |
+
.section { padding: 64px 0 0; }
|
| 177 |
+
.sec-head { text-align: center; margin-bottom: 26px; }
|
| 178 |
+
.sec-head h2 { font-size: clamp(26px, 3.6vw, 38px); letter-spacing: -.035em; margin: 0 0 8px; font-weight: 780; }
|
| 179 |
+
.sec-head p { color: var(--ink2); margin: 0; }
|
| 180 |
+
.examples { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
| 181 |
+
.ex { text-align: left; font: inherit; color: inherit; border: 1px solid var(--line2); background: var(--card); border-radius: 18px; padding: 16px 18px 18px; cursor: pointer; box-shadow: var(--shadow);
|
| 182 |
+
transition: transform .25s var(--ease), border-color .25s; display: flex; flex-direction: column; gap: 8px; backdrop-filter: blur(10px); }
|
| 183 |
+
.ex:hover { transform: translateY(-3px); border-color: color-mix(in oklab, var(--a2) 45%, transparent); }
|
| 184 |
+
.ex .tag { align-self: flex-start; font-size: 11.5px; font-weight: 700; letter-spacing: .04em; color: var(--a2); background: color-mix(in oklab, var(--a2) 12%, transparent); padding: 3px 9px; border-radius: 99px; }
|
| 185 |
+
.ex .ro { font-size: 15px; color: var(--ink2); }
|
| 186 |
+
.ex .dv { font-family: var(--deva); font-size: 21px; font-weight: 550; line-height: 1.5; min-height: 32px; }
|
| 187 |
+
.shimmer { display: inline-block; width: 70%; height: 18px; border-radius: 6px; background: linear-gradient(90deg, var(--line) 0%, var(--line2) 50%, var(--line) 100%); background-size: 200% 100%; animation: shim 1.2s linear infinite; }
|
| 188 |
+
@keyframes shim { to { background-position: -200% 0; } }
|
| 189 |
+
|
| 190 |
+
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
| 191 |
+
.feat { padding: 20px 20px 18px; border-radius: 18px; background: var(--card); border: 1px solid var(--line2); box-shadow: var(--shadow); }
|
| 192 |
+
.feat .ic { width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; font-size: 18px; color: #fff; background: linear-gradient(135deg, var(--a1), var(--a2)); box-shadow: 0 8px 18px -8px rgba(124, 58, 237, .7); }
|
| 193 |
+
.feat:nth-child(3n+2) .ic { background: linear-gradient(135deg, var(--a2), var(--a4)); }
|
| 194 |
+
.feat:nth-child(3n) .ic { background: linear-gradient(135deg, var(--a4), var(--a3)); }
|
| 195 |
+
.feat h3 { margin: 14px 0 4px; font-size: 17px; letter-spacing: -.02em; }
|
| 196 |
+
.feat p { margin: 0 0 12px; color: var(--ink2); font-size: 14.5px; }
|
| 197 |
+
.demo-line { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; font-size: 14px; padding: 10px 12px; border-radius: 12px; background: color-mix(in oklab, var(--ink) 4%, transparent); }
|
| 198 |
+
.demo-line .r { color: var(--ink3); }
|
| 199 |
+
.demo-line .arrow { color: var(--ink3); }
|
| 200 |
+
.demo-line .d { font-family: var(--deva); font-size: 18px; font-weight: 600; }
|
| 201 |
+
.demo-line + .demo-line { margin-top: 6px; }
|
| 202 |
+
|
| 203 |
+
.sizes { padding: 24px 26px; display: flex; flex-direction: column; gap: 18px; }
|
| 204 |
+
.srow { display: grid; grid-template-columns: 240px 1fr 120px; gap: 16px; align-items: center; }
|
| 205 |
+
.srow .nm { font-weight: 650; font-size: 14.5px; }
|
| 206 |
+
.srow .nm small { display: block; color: var(--ink3); font-weight: 500; font-size: 12.5px; }
|
| 207 |
+
.sbar { height: 14px; border-radius: 8px; background: color-mix(in oklab, var(--ink) 6%, transparent); overflow: hidden; }
|
| 208 |
+
.sbar span { display: block; height: 100%; border-radius: 8px; width: 0; transition: width 1.4s var(--ease); background: color-mix(in oklab, var(--ink) 28%, transparent); }
|
| 209 |
+
.srow.us .sbar span { background: linear-gradient(90deg, var(--a1), var(--a2), var(--a3)); min-width: 6px; box-shadow: 0 0 18px rgba(168, 85, 247, .6); }
|
| 210 |
+
.srow .val { text-align: right; font-weight: 750; font-variant-numeric: tabular-nums; }
|
| 211 |
+
.srow.us .val { background: linear-gradient(90deg, var(--a1), var(--a3)); -webkit-background-clip: text; background-clip: text; color: transparent; }
|
| 212 |
+
.sizes .note { font-size: 12.5px; color: var(--ink3); }
|
| 213 |
+
|
| 214 |
+
.how .steps { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; counter-reset: s; }
|
| 215 |
+
.steps li { padding: 20px; border-radius: 18px; border: 1px dashed var(--line2); }
|
| 216 |
+
.steps .n { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; font-weight: 750; font-size: 13px; color: #fff; background: linear-gradient(135deg, var(--a1), var(--a3)); margin-right: 8px; }
|
| 217 |
+
.steps b { font-size: 16.5px; }
|
| 218 |
+
.steps p { color: var(--ink2); font-size: 14.5px; margin: 10px 0 0; }
|
| 219 |
+
|
| 220 |
+
.foot { max-width: 1160px; margin: 70px auto 0; padding: 26px clamp(16px, 4vw, 40px) 40px; border-top: 1px solid var(--line); font-size: 13px; color: var(--ink2); display: flex; flex-direction: column; gap: 4px; }
|
| 221 |
+
.muted { color: var(--ink3); }
|
| 222 |
+
.toast { position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 20px); opacity: 0; background: var(--ink); color: var(--bg); padding: 10px 16px; border-radius: 12px; font-size: 14px; font-weight: 600; transition: all .35s var(--ease); pointer-events: none; z-index: 50; }
|
| 223 |
+
.toast.on { opacity: 1; transform: translate(-50%, 0); }
|
| 224 |
+
|
| 225 |
+
.l-short { display: none; }
|
| 226 |
+
@media (max-width: 600px) {
|
| 227 |
+
.l-long { display: none; } .l-short { display: inline; }
|
| 228 |
+
.seg { width: 100%; } .seg button { flex: 1; padding: 8px 6px; }
|
| 229 |
+
.toolbar { gap: 10px 14px; } .switch { font-size: 13px; }
|
| 230 |
+
.playground { padding: 14px; } h1 { letter-spacing: -.04em; }
|
| 231 |
+
.suggest { flex-direction: column; align-items: flex-start; gap: 8px; }
|
| 232 |
+
}
|
| 233 |
+
@media (max-width: 900px) {
|
| 234 |
+
.panes, .examples, .features, .how .steps { grid-template-columns: 1fr; }
|
| 235 |
+
.meter { grid-template-columns: repeat(2, 1fr); row-gap: 14px; }
|
| 236 |
+
.srow { grid-template-columns: 1fr 90px; } .srow .sbar { grid-column: 1 / -1; grid-row: 2; }
|
| 237 |
+
.brand-tag, .nav-link { display: none; }
|
| 238 |
+
.pane { min-height: 150px; }
|
| 239 |
+
}
|
| 240 |
+
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
|
| 241 |
+
|
| 242 |
+
/* ---------- word language tags, chips meta, feature demos */
|
| 243 |
+
.playground.tags .output { line-height: 1.9; }
|
| 244 |
+
.playground.tags .w { display: inline-flex; flex-direction: column; align-items: center; vertical-align: top; line-height: 1.35; padding: 2px 3px 3px; }
|
| 245 |
+
.tg { font-family: var(--font); font-size: 9.5px; font-weight: 750; letter-spacing: .06em; line-height: 1; padding: 3px 5px 2px; border-radius: 5px; margin-top: 1px; color: var(--hi); background: color-mix(in oklab, var(--hi) 13%, transparent); vertical-align: middle; }
|
| 246 |
+
.tg-EN { color: var(--en); background: color-mix(in oklab, var(--en) 14%, transparent); }
|
| 247 |
+
.tg-DEV { color: var(--dev); background: color-mix(in oklab, var(--dev) 14%, transparent); }
|
| 248 |
+
.tg-OTHER { color: var(--oth); background: color-mix(in oklab, var(--oth) 14%, transparent); }
|
| 249 |
+
.playground.tags .w.pinned .tg { color: #fff; background: var(--a3); }
|
| 250 |
+
.chips .meta { font-size: 12px; color: var(--ink3); font-weight: 600; margin-left: 4px; padding-left: 10px; border-left: 1px solid var(--line2); }
|
| 251 |
+
.chips .reset { padding: 5px 10px; }
|
| 252 |
+
.demo-line.big { align-items: center; }
|
| 253 |
+
.demo-line.big .d { font-family: var(--font); font-size: 30px; font-weight: 800; letter-spacing: -.03em; }
|
| 254 |
+
.mini-chip { font-family: var(--deva); font-size: 15px; padding: 2px 9px 3px; border-radius: 8px; border: 1px solid var(--line2); background: var(--card-solid); }
|
| 255 |
+
.mini-chip.on { color: #fff; border-color: transparent; background: linear-gradient(120deg, var(--a1), var(--a2)); }
|
| 256 |
+
.lid-w { display: inline-flex; flex-direction: column; align-items: center; gap: 3px; }
|
| 257 |
+
.lid-w .lw { font-size: 14px; color: var(--ink); }
|
| 258 |
+
.lang-badge.sm { font-size: 11.5px; padding: 3px 9px; align-self: center; }
|
| 259 |
+
|
| 260 |
+
/* ---------- on-device capabilities */
|
| 261 |
+
.kicker { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--a2); margin-bottom: 10px; }
|
| 262 |
+
.live-dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; animation: pulse-g 2.4s infinite; }
|
| 263 |
+
.caps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
| 264 |
+
.cap { position: relative; padding: 20px 20px 18px; border-radius: 20px; background: var(--card); border: 1px solid var(--line2); box-shadow: var(--shadow); display: flex; flex-direction: column;
|
| 265 |
+
backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); transition: transform .35s var(--ease), border-color .3s, box-shadow .35s; overflow: hidden; }
|
| 266 |
+
.cap::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .4s;
|
| 267 |
+
background: radial-gradient(420px circle at 0% 0%, color-mix(in oklab, var(--a2) 10%, transparent), transparent 60%); }
|
| 268 |
+
.cap:hover { transform: translateY(-4px); border-color: color-mix(in oklab, var(--a2) 40%, transparent); box-shadow: var(--shadow), 0 18px 40px -22px rgba(124, 58, 237, .55); }
|
| 269 |
+
.cap:hover::after { opacity: 1; }
|
| 270 |
+
.cap h3 { margin: 14px 0 4px; font-size: 17px; letter-spacing: -.02em; }
|
| 271 |
+
.cap p { margin: 0 0 12px; color: var(--ink2); font-size: 14.5px; }
|
| 272 |
+
.cap .fslot { margin-top: auto; }
|
| 273 |
+
.cic { width: 42px; height: 42px; border-radius: 13px; display: grid; place-items: center; color: #fff; background: linear-gradient(135deg, var(--a1), var(--a2)); box-shadow: 0 10px 22px -10px rgba(124, 58, 237, .8);
|
| 274 |
+
transition: transform .45s var(--ease); }
|
| 275 |
+
.cap:nth-child(3n+2) .cic { background: linear-gradient(135deg, var(--a2), var(--a4)); box-shadow: 0 10px 22px -10px rgba(236, 72, 153, .7); }
|
| 276 |
+
.cap:nth-child(3n) .cic { background: linear-gradient(135deg, var(--a4), var(--a3)); box-shadow: 0 10px 22px -10px rgba(249, 115, 22, .7); }
|
| 277 |
+
.cap:hover .cic { transform: translateY(-2px) rotate(-6deg) scale(1.06); }
|
| 278 |
+
.cic svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
| 279 |
+
.cic svg .f { fill: currentColor; stroke: none; }
|
| 280 |
+
.cap-offline .cic svg { animation: drift 4.5s ease-in-out infinite; }
|
| 281 |
+
.cap-realtime .cic svg { animation: flick 3.2s ease-in-out infinite; }
|
| 282 |
+
.cap-private .cic svg { animation: breathe 3.6s ease-in-out infinite; }
|
| 283 |
+
.cap-bharat .cic svg path { transform-origin: bottom; transform-box: fill-box; animation: bars 2.4s ease-in-out infinite; }
|
| 284 |
+
.cap-bharat .cic .bar2 { animation-delay: .15s; } .cap-bharat .cic .bar3 { animation-delay: .3s; } .cap-bharat .cic .bar4 { animation-delay: .45s; }
|
| 285 |
+
@keyframes drift { 0%, 100% { transform: translate(0, 0) rotate(0); } 50% { transform: translate(1.5px, -1.5px) rotate(-4deg); } }
|
| 286 |
+
@keyframes flick { 0%, 86%, 100% { opacity: 1; } 90% { opacity: .45; } 94% { opacity: 1; } 97% { opacity: .6; } }
|
| 287 |
+
@keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }
|
| 288 |
+
@keyframes bars { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(.55); } }
|
| 289 |
+
.pills { display: flex; flex-wrap: wrap; gap: 6px; margin: -2px 0 12px; }
|
| 290 |
+
.pl { font-size: 11.5px; font-weight: 650; color: var(--ink2); padding: 3px 9px; border-radius: 99px; border: 1px solid var(--line2); background: var(--card-solid); }
|
| 291 |
+
.net { font-size: 12px; font-weight: 650; margin: -2px 0 10px; display: inline-flex; align-items: center; gap: 7px; color: var(--ink2); }
|
| 292 |
+
.net::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #10b981; }
|
| 293 |
+
.net.off::before { background: var(--a3); } .net.off { color: var(--a3); }
|
| 294 |
+
.steps-live .st { opacity: 0; animation: stepin .5s var(--ease) forwards; animation-delay: calc(var(--i) * .45s + .2s); }
|
| 295 |
+
.steps-live .st:last-child { box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--a2) 35%, transparent); }
|
| 296 |
+
@keyframes stepin { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
|
| 297 |
+
.lat-live { margin-top: 8px; font-size: 12.5px; color: var(--ink3); }
|
| 298 |
+
.lat-live b { color: var(--ink); font-variant-numeric: tabular-nums; }
|
| 299 |
+
.ime { border-radius: 14px; border: 1px solid var(--line2); background: var(--bg2); padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; }
|
| 300 |
+
.ime-lbl { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink3); }
|
| 301 |
+
.ime-in { font-size: 14px; color: var(--ink2); min-height: 21px; }
|
| 302 |
+
.caret { display: inline-block; width: 2px; height: 1.05em; margin-left: 1px; vertical-align: -2px; background: var(--a2); animation: blink 1s steps(1) infinite; }
|
| 303 |
+
@keyframes blink { 50% { opacity: 0; } }
|
| 304 |
+
.ime-out { font-family: var(--deva); font-size: 18px; font-weight: 600; min-height: 28px; padding-top: 6px; border-top: 1px dashed var(--line2); }
|
| 305 |
+
.mode-row .mlab { font-size: 11.5px; font-weight: 700; color: var(--a2); min-width: 108px; }
|
| 306 |
+
.cap .mini-chip { animation: pop .35s var(--ease) both; }
|
| 307 |
+
.rv { opacity: 0; transform: translateY(18px); transition: opacity .7s var(--ease) var(--d, 0ms), transform .7s var(--ease) var(--d, 0ms), border-color .3s, box-shadow .35s; }
|
| 308 |
+
.rv.in { opacity: 1; transform: none; }
|
| 309 |
+
.rv.in.cap:hover { transform: translateY(-4px); }
|
| 310 |
+
|
| 311 |
+
/* ---------- best in class for its size */
|
| 312 |
+
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
| 313 |
+
.tile { position: relative; padding: 22px 22px 20px; border-radius: 20px; background: var(--card); box-shadow: var(--shadow); isolation: isolate; overflow: hidden; }
|
| 314 |
+
.tile::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; z-index: -1;
|
| 315 |
+
background: conic-gradient(from var(--ang, 0deg), rgba(99, 102, 241, .65), rgba(168, 85, 247, .15), rgba(249, 115, 22, .6), rgba(236, 72, 153, .15), rgba(99, 102, 241, .65));
|
| 316 |
+
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; animation: spin 9s linear infinite; }
|
| 317 |
+
@property --ang { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
|
| 318 |
+
@keyframes spin { to { --ang: 360deg; } }
|
| 319 |
+
.tv { display: flex; align-items: baseline; gap: 4px; }
|
| 320 |
+
.tv .num { font-size: clamp(36px, 4.6vw, 50px); font-weight: 800; letter-spacing: -.045em; line-height: 1; font-variant-numeric: tabular-nums;
|
| 321 |
+
background: linear-gradient(100deg, var(--a1), var(--a2) 45%, var(--a4) 75%, var(--a3)); -webkit-background-clip: text; background-clip: text; color: transparent; }
|
| 322 |
+
.tv .tu { font-size: 20px; font-weight: 750; color: var(--a2); }
|
| 323 |
+
.tl { margin-top: 10px; font-weight: 700; font-size: 15px; letter-spacing: -.01em; }
|
| 324 |
+
.ts { margin-top: 4px; font-size: 12.5px; color: var(--ink3); }
|
| 325 |
+
.board { margin-top: 14px; padding: 18px 22px; display: flex; flex-direction: column; gap: 12px; }
|
| 326 |
+
.board .bh { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink3); }
|
| 327 |
+
.brow { display: grid; grid-template-columns: 34px 220px 1fr 120px; gap: 14px; align-items: center; font-size: 14px; }
|
| 328 |
+
.brow .rk { font-weight: 800; color: var(--ink3); }
|
| 329 |
+
.brow.us .rk, .brow.us .nm { color: var(--hi); font-weight: 750; }
|
| 330 |
+
.brow .val { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
|
| 331 |
+
.brow.us .sbar span { background: linear-gradient(90deg, var(--a1), var(--a2), var(--a3)); box-shadow: 0 0 18px rgba(168, 85, 247, .6); }
|
| 332 |
+
.best-hl { margin: 14px auto 0; text-align: center; font-weight: 650; color: var(--ink2); }
|
| 333 |
+
@media (max-width: 900px) {
|
| 334 |
+
.caps, .tiles { grid-template-columns: 1fr; }
|
| 335 |
+
.brow { grid-template-columns: 30px 1fr 90px; } .brow .sbar { grid-column: 1 / -1; grid-row: 2; }
|
| 336 |
+
}
|
| 337 |
+
.board[hidden], .best-hl[hidden], .section[hidden] { display: none; }
|
| 338 |
+
|
| 339 |
+
/* ---------- license & attribution */
|
| 340 |
+
.lic { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
| 341 |
+
.lic-card { padding: 20px; border-radius: 18px; background: var(--card); border: 1px solid var(--line2); box-shadow: var(--shadow); }
|
| 342 |
+
.lic-card h3 { margin: 12px 0 4px; font-size: 17px; letter-spacing: -.02em; }
|
| 343 |
+
.lic-card p { margin: 0; color: var(--ink2); font-size: 14.5px; }
|
| 344 |
+
.lic-card code, .attr code { font-size: 12.5px; padding: 1px 5px; border-radius: 6px; background: color-mix(in oklab, var(--ink) 7%, transparent); }
|
| 345 |
+
.lic-ic { width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; font-weight: 800; color: #fff; background: linear-gradient(135deg, #10b981, #0ea5e9); }
|
| 346 |
+
.lic-card.req .lic-ic { background: linear-gradient(135deg, var(--a2), var(--a3)); }
|
| 347 |
+
.attr { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
|
| 348 |
+
.attr-row { display: grid; grid-template-columns: 190px 1fr auto; gap: 12px; align-items: center; padding: 12px 14px; border-radius: 16px; border: 1px solid var(--line2); background: var(--card); }
|
| 349 |
+
.attr-k { font-size: 12px; font-weight: 700; letter-spacing: .04em; color: var(--ink2); }
|
| 350 |
+
.attr-k em { display: block; font-style: normal; font-weight: 600; color: var(--a2); }
|
| 351 |
+
.attr-code { margin: 0; font: 500 13px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; white-space: pre-wrap; word-break: break-word; color: var(--ink); background: var(--bg2); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
|
| 352 |
+
.attr-copy.done { color: #10b981; border-color: rgba(16, 185, 129, .45); }
|
| 353 |
+
@media (max-width: 900px) { .lic { grid-template-columns: 1fr; } .attr-row { grid-template-columns: 1fr; } }
|
fonts/Inter-var.woff2
ADDED
|
Binary file (92.3 kB). View file
|
|
|
fonts/NotoSansDevanagari-var.woff2
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:755bf24ca84bf1d8633c9487fa6c2b230efed3f8b66844736ec6dd997a935d2f
|
| 3 |
+
size 226472
|
fonts/OFL-Inter.txt
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
| 2 |
+
|
| 3 |
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
| 4 |
+
This license is copied below, and is also available with a FAQ at:
|
| 5 |
+
https://scripts.sil.org/OFL
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
-----------------------------------------------------------
|
| 9 |
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
| 10 |
+
-----------------------------------------------------------
|
| 11 |
+
|
| 12 |
+
PREAMBLE
|
| 13 |
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
| 14 |
+
development of collaborative font projects, to support the font creation
|
| 15 |
+
efforts of academic and linguistic communities, and to provide a free and
|
| 16 |
+
open framework in which fonts may be shared and improved in partnership
|
| 17 |
+
with others.
|
| 18 |
+
|
| 19 |
+
The OFL allows the licensed fonts to be used, studied, modified and
|
| 20 |
+
redistributed freely as long as they are not sold by themselves. The
|
| 21 |
+
fonts, including any derivative works, can be bundled, embedded,
|
| 22 |
+
redistributed and/or sold with any software provided that any reserved
|
| 23 |
+
names are not used by derivative works. The fonts and derivatives,
|
| 24 |
+
however, cannot be released under any other type of license. The
|
| 25 |
+
requirement for fonts to remain under this license does not apply
|
| 26 |
+
to any document created using the fonts or their derivatives.
|
| 27 |
+
|
| 28 |
+
DEFINITIONS
|
| 29 |
+
"Font Software" refers to the set of files released by the Copyright
|
| 30 |
+
Holder(s) under this license and clearly marked as such. This may
|
| 31 |
+
include source files, build scripts and documentation.
|
| 32 |
+
|
| 33 |
+
"Reserved Font Name" refers to any names specified as such after the
|
| 34 |
+
copyright statement(s).
|
| 35 |
+
|
| 36 |
+
"Original Version" refers to the collection of Font Software components as
|
| 37 |
+
distributed by the Copyright Holder(s).
|
| 38 |
+
|
| 39 |
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
| 40 |
+
or substituting -- in part or in whole -- any of the components of the
|
| 41 |
+
Original Version, by changing formats or by porting the Font Software to a
|
| 42 |
+
new environment.
|
| 43 |
+
|
| 44 |
+
"Author" refers to any designer, engineer, programmer, technical
|
| 45 |
+
writer or other person who contributed to the Font Software.
|
| 46 |
+
|
| 47 |
+
PERMISSION & CONDITIONS
|
| 48 |
+
Permission is hereby granted, free of charge, to any person obtaining
|
| 49 |
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
| 50 |
+
redistribute, and sell modified and unmodified copies of the Font
|
| 51 |
+
Software, subject to the following conditions:
|
| 52 |
+
|
| 53 |
+
1) Neither the Font Software nor any of its individual components,
|
| 54 |
+
in Original or Modified Versions, may be sold by itself.
|
| 55 |
+
|
| 56 |
+
2) Original or Modified Versions of the Font Software may be bundled,
|
| 57 |
+
redistributed and/or sold with any software, provided that each copy
|
| 58 |
+
contains the above copyright notice and this license. These can be
|
| 59 |
+
included either as stand-alone text files, human-readable headers or
|
| 60 |
+
in the appropriate machine-readable metadata fields within text or
|
| 61 |
+
binary files as long as those fields can be easily viewed by the user.
|
| 62 |
+
|
| 63 |
+
3) No Modified Version of the Font Software may use the Reserved Font
|
| 64 |
+
Name(s) unless explicit written permission is granted by the corresponding
|
| 65 |
+
Copyright Holder. This restriction only applies to the primary font name as
|
| 66 |
+
presented to the users.
|
| 67 |
+
|
| 68 |
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
| 69 |
+
Software shall not be used to promote, endorse or advertise any
|
| 70 |
+
Modified Version, except to acknowledge the contribution(s) of the
|
| 71 |
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
| 72 |
+
permission.
|
| 73 |
+
|
| 74 |
+
5) The Font Software, modified or unmodified, in part or in whole,
|
| 75 |
+
must be distributed entirely under this license, and must not be
|
| 76 |
+
distributed under any other license. The requirement for fonts to
|
| 77 |
+
remain under this license does not apply to any document created
|
| 78 |
+
using the Font Software.
|
| 79 |
+
|
| 80 |
+
TERMINATION
|
| 81 |
+
This license becomes null and void if any of the above conditions are
|
| 82 |
+
not met.
|
| 83 |
+
|
| 84 |
+
DISCLAIMER
|
| 85 |
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 86 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
| 87 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
| 88 |
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
| 89 |
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
| 90 |
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
| 91 |
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 92 |
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
| 93 |
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
fonts/OFL-NotoSansDevanagari.txt
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/devanagari)
|
| 2 |
+
|
| 3 |
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
| 4 |
+
This license is copied below, and is also available with a FAQ at:
|
| 5 |
+
https://scripts.sil.org/OFL
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
-----------------------------------------------------------
|
| 9 |
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
| 10 |
+
-----------------------------------------------------------
|
| 11 |
+
|
| 12 |
+
PREAMBLE
|
| 13 |
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
| 14 |
+
development of collaborative font projects, to support the font creation
|
| 15 |
+
efforts of academic and linguistic communities, and to provide a free and
|
| 16 |
+
open framework in which fonts may be shared and improved in partnership
|
| 17 |
+
with others.
|
| 18 |
+
|
| 19 |
+
The OFL allows the licensed fonts to be used, studied, modified and
|
| 20 |
+
redistributed freely as long as they are not sold by themselves. The
|
| 21 |
+
fonts, including any derivative works, can be bundled, embedded,
|
| 22 |
+
redistributed and/or sold with any software provided that any reserved
|
| 23 |
+
names are not used by derivative works. The fonts and derivatives,
|
| 24 |
+
however, cannot be released under any other type of license. The
|
| 25 |
+
requirement for fonts to remain under this license does not apply
|
| 26 |
+
to any document created using the fonts or their derivatives.
|
| 27 |
+
|
| 28 |
+
DEFINITIONS
|
| 29 |
+
"Font Software" refers to the set of files released by the Copyright
|
| 30 |
+
Holder(s) under this license and clearly marked as such. This may
|
| 31 |
+
include source files, build scripts and documentation.
|
| 32 |
+
|
| 33 |
+
"Reserved Font Name" refers to any names specified as such after the
|
| 34 |
+
copyright statement(s).
|
| 35 |
+
|
| 36 |
+
"Original Version" refers to the collection of Font Software components as
|
| 37 |
+
distributed by the Copyright Holder(s).
|
| 38 |
+
|
| 39 |
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
| 40 |
+
or substituting -- in part or in whole -- any of the components of the
|
| 41 |
+
Original Version, by changing formats or by porting the Font Software to a
|
| 42 |
+
new environment.
|
| 43 |
+
|
| 44 |
+
"Author" refers to any designer, engineer, programmer, technical
|
| 45 |
+
writer or other person who contributed to the Font Software.
|
| 46 |
+
|
| 47 |
+
PERMISSION & CONDITIONS
|
| 48 |
+
Permission is hereby granted, free of charge, to any person obtaining
|
| 49 |
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
| 50 |
+
redistribute, and sell modified and unmodified copies of the Font
|
| 51 |
+
Software, subject to the following conditions:
|
| 52 |
+
|
| 53 |
+
1) Neither the Font Software nor any of its individual components,
|
| 54 |
+
in Original or Modified Versions, may be sold by itself.
|
| 55 |
+
|
| 56 |
+
2) Original or Modified Versions of the Font Software may be bundled,
|
| 57 |
+
redistributed and/or sold with any software, provided that each copy
|
| 58 |
+
contains the above copyright notice and this license. These can be
|
| 59 |
+
included either as stand-alone text files, human-readable headers or
|
| 60 |
+
in the appropriate machine-readable metadata fields within text or
|
| 61 |
+
binary files as long as those fields can be easily viewed by the user.
|
| 62 |
+
|
| 63 |
+
3) No Modified Version of the Font Software may use the Reserved Font
|
| 64 |
+
Name(s) unless explicit written permission is granted by the corresponding
|
| 65 |
+
Copyright Holder. This restriction only applies to the primary font name as
|
| 66 |
+
presented to the users.
|
| 67 |
+
|
| 68 |
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
| 69 |
+
Software shall not be used to promote, endorse or advertise any
|
| 70 |
+
Modified Version, except to acknowledge the contribution(s) of the
|
| 71 |
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
| 72 |
+
permission.
|
| 73 |
+
|
| 74 |
+
5) The Font Software, modified or unmodified, in part or in whole,
|
| 75 |
+
must be distributed entirely under this license, and must not be
|
| 76 |
+
distributed under any other license. The requirement for fonts to
|
| 77 |
+
remain under this license does not apply to any document created
|
| 78 |
+
using the Font Software.
|
| 79 |
+
|
| 80 |
+
TERMINATION
|
| 81 |
+
This license becomes null and void if any of the above conditions are
|
| 82 |
+
not met.
|
| 83 |
+
|
| 84 |
+
DISCLAIMER
|
| 85 |
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 86 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
| 87 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
| 88 |
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
| 89 |
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
| 90 |
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
| 91 |
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 92 |
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
| 93 |
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
index.html
CHANGED
|
@@ -1,19 +1,171 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en" data-theme="auto">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
| 6 |
+
<title>AksharaLP — Hindi transliteration that runs in your browser</title>
|
| 7 |
+
<meta name="description" content="Type Hindi in English letters, get Devanagari instantly. A tiny, context-aware model that runs fully offline in your browser." />
|
| 8 |
+
<meta name="theme-color" content="#0b0d17" media="(prefers-color-scheme: dark)" />
|
| 9 |
+
<meta name="theme-color" content="#f7f7fb" media="(prefers-color-scheme: light)" />
|
| 10 |
+
<meta property="og:title" content="AksharaLP — Hindi transliteration, on-device" />
|
| 11 |
+
<meta property="og:description" content="Romanized Hindi → Devanagari. Tiny. Context-aware. Private." />
|
| 12 |
+
<link rel="icon" href="assets/favicon.svg" type="image/svg+xml" />
|
| 13 |
+
<link rel="preload" href="fonts/Inter-var.woff2" as="font" type="font/woff2" crossorigin />
|
| 14 |
+
<link rel="preload" href="fonts/NotoSansDevanagari-var.woff2" as="font" type="font/woff2" crossorigin />
|
| 15 |
+
<link rel="stylesheet" href="css/app.css" />
|
| 16 |
+
<script>
|
| 17 |
+
(function () { try { var t = localStorage.getItem("aklp-theme"); if (t) document.documentElement.dataset.theme = t; } catch (e) {} })();
|
| 18 |
+
</script>
|
| 19 |
+
</head>
|
| 20 |
+
<body>
|
| 21 |
+
<div class="bg" aria-hidden="true"><span class="blob b1"></span><span class="blob b2"></span><span class="blob b3"></span><span class="grid"></span></div>
|
| 22 |
+
|
| 23 |
+
<header class="nav">
|
| 24 |
+
<a class="brand" href="#" aria-label="AksharaLP home">
|
| 25 |
+
<svg class="mark" viewBox="0 0 40 40" aria-hidden="true"><defs><linearGradient id="mk" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#6366f1"/><stop offset=".55" stop-color="#a855f7"/><stop offset="1" stop-color="#f97316"/></linearGradient></defs><rect width="40" height="40" rx="11" fill="url(#mk)"/><text x="20" y="28.5" text-anchor="middle" font-family="Noto Sans Devanagari" font-weight="700" font-size="22" fill="#fff">भ</text></svg>
|
| 26 |
+
<span class="brand-name">AksharaLP</span>
|
| 27 |
+
<span class="brand-tag">Hindi</span>
|
| 28 |
+
</a>
|
| 29 |
+
<nav class="nav-right">
|
| 30 |
+
<span class="pill status" id="status"><span class="dot"></span><span id="status-text">Loading model…</span></span>
|
| 31 |
+
<a class="nav-link" id="card-link" href="https://huggingface.co/sourojitdotcom/AksharaLP-1M" target="_blank" rel="noopener">Model card <span aria-hidden="true">↗</span></a>
|
| 32 |
+
<button class="icon-btn" id="theme" aria-label="Toggle dark mode" title="Toggle theme">
|
| 33 |
+
<svg class="sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.5v2.2M12 19.3v2.2M4.6 4.6l1.6 1.6M17.8 17.8l1.6 1.6M2.5 12h2.2M19.3 12h2.2M4.6 19.4l1.6-1.6M17.8 6.2l1.6-1.6"/></svg>
|
| 34 |
+
<svg class="moon" viewBox="0 0 24 24"><path d="M20.5 14.6A8.5 8.5 0 0 1 9.4 3.5a8.5 8.5 0 1 0 11.1 11.1z"/></svg>
|
| 35 |
+
</button>
|
| 36 |
+
</nav>
|
| 37 |
+
</header>
|
| 38 |
+
|
| 39 |
+
<main>
|
| 40 |
+
<section class="hero">
|
| 41 |
+
<div class="eyebrow"><span class="spark">✦</span> Open model · 100% on-device · No server</div>
|
| 42 |
+
<h1>The world’s 3rd most spoken language, typed on the world’s most used keyboard. <span class="grad">In <span id="hero-size-short">a few MB</span>.</span></h1>
|
| 43 |
+
<p class="lede"><b class="lede-strong">Hindi typed in English letters → Devanagari, fully offline.</b>
|
| 44 |
+
Context-aware, as you type. The whole thing is <b class="size-chip" id="hero-size">—</b> and runs inside this tab; nothing you write ever leaves your device.</p>
|
| 45 |
+
<div class="stats" aria-label="Why it matters">
|
| 46 |
+
<div class="stat"><b>#3</b><span>most spoken language<br>in the world</span></div>
|
| 47 |
+
<div class="stat"><b>611M</b><span>people speak Hindi<br>(first or second language)</span></div>
|
| 48 |
+
<div class="stat"><b id="stat-size">—</b><span>to type it, with<br>no server and no GPU</span></div>
|
| 49 |
+
</div>
|
| 50 |
+
<p class="stat-src">Source: <a href="https://www.ethnologue.com/insights/ethnologue200/" target="_blank" rel="noopener">Ethnologue 200</a>, 2026 (29th edition, SIL Global). Speaker counts include second-language speakers.</p>
|
| 51 |
+
</section>
|
| 52 |
+
|
| 53 |
+
<section class="playground card" id="playground" aria-label="Live transliteration playground">
|
| 54 |
+
<div class="toolbar">
|
| 55 |
+
<div class="seg" role="radiogroup" aria-label="Vocabulary mode" id="modes">
|
| 56 |
+
<button role="radio" aria-checked="true" data-mode="conversational" title="Everything in Devanagari">Default</button>
|
| 57 |
+
<button role="radio" aria-checked="false" data-mode="strict" title="Keep brand and product names in Latin script">Strict</button>
|
| 58 |
+
<span class="seg-glider" aria-hidden="true"></span>
|
| 59 |
+
</div>
|
| 60 |
+
<label class="switch" title="Use the sentence-level language model to pick words from context">
|
| 61 |
+
<input type="checkbox" id="ctx" checked /><span class="track"><span class="thumb"></span></span><span class="l-long">Sentence context</span><span class="l-short">Context</span>
|
| 62 |
+
</label>
|
| 63 |
+
<span class="spacer"></span>
|
| 64 |
+
<span class="lang-badge" id="sent-lang" hidden></span>
|
| 65 |
+
</div>
|
| 66 |
+
|
| 67 |
+
<div class="panes">
|
| 68 |
+
<div class="pane in">
|
| 69 |
+
<div class="pane-head"><span class="label">Romanized Hindi</span><button class="ghost-btn" id="clear" title="Clear">Clear</button></div>
|
| 70 |
+
<textarea id="input" spellcheck="false" autocomplete="off" autocapitalize="off" placeholder="Type here… e.g. kal meri meeting hai, please mujhe remind kar dena" rows="4" disabled></textarea>
|
| 71 |
+
</div>
|
| 72 |
+
<div class="pane out">
|
| 73 |
+
<div class="pane-head"><span class="label deva-label">देवनागरी</span>
|
| 74 |
+
<button class="copy-btn" id="copy" title="Copy Devanagari" disabled>
|
| 75 |
+
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button>
|
| 76 |
+
</div>
|
| 77 |
+
<div id="output" class="output" aria-live="polite"><span class="ph">आपका देवनागरी पाठ यहाँ दिखेगा</span></div>
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div class="suggest" id="suggest" aria-label="Suggestions">
|
| 82 |
+
<span class="suggest-label">Suggestions</span>
|
| 83 |
+
<div class="chips" id="chips"><span class="hint">Click any word in the output — or just keep typing — to see ranked alternatives.</span></div>
|
| 84 |
+
</div>
|
| 85 |
+
|
| 86 |
+
<div class="meter">
|
| 87 |
+
<div class="m"><span class="k">Latency</span><span class="v" id="m-lat">—</span></div>
|
| 88 |
+
<div class="m"><span class="k">Download</span><span class="v" id="m-size">—</span></div>
|
| 89 |
+
<div class="m"><span class="k">Parameters</span><span class="v" id="m-params">—</span></div>
|
| 90 |
+
<div class="m"><span class="k">Dictionary</span><span class="v" id="m-lex">—</span></div>
|
| 91 |
+
<div class="m"><span class="k">Runs on</span><span class="v">Your device <span class="lock">🔒</span></span></div>
|
| 92 |
+
</div>
|
| 93 |
+
<div class="loader" id="loader"><div class="bar"><span></span></div><span id="loader-text">Downloading model…</span></div>
|
| 94 |
+
</section>
|
| 95 |
+
|
| 96 |
+
<section class="section" id="examples-sec">
|
| 97 |
+
<div class="sec-head"><h2>Try an example</h2><p>Every preview below is computed live by the model in your browser.</p></div>
|
| 98 |
+
<div class="examples" id="examples"></div>
|
| 99 |
+
</section>
|
| 100 |
+
|
| 101 |
+
<section class="section" id="ondevice" aria-labelledby="ondevice-h">
|
| 102 |
+
<div class="sec-head"><span class="kicker"><span class="live-dot"></span>Live in this tab</span><h2 id="ondevice-h">What it brings on-device</h2>
|
| 103 |
+
<p>No server in the loop. Every example below is computed right now, inside this page.</p></div>
|
| 104 |
+
<div class="caps" id="caps"></div>
|
| 105 |
+
</section>
|
| 106 |
+
|
| 107 |
+
<section class="section" id="best" aria-labelledby="best-h" hidden>
|
| 108 |
+
<div class="sec-head"><span class="kicker">Measured, not claimed</span><h2 id="best-h">By the numbers</h2>
|
| 109 |
+
<p>Each tile is generated by the release build from measured results and appears only if its rule holds.</p></div>
|
| 110 |
+
<div class="tiles" id="tiles"></div>
|
| 111 |
+
<div class="board card" id="board" hidden></div>
|
| 112 |
+
<p class="best-hl" id="best-hl" hidden></p>
|
| 113 |
+
</section>
|
| 114 |
+
<script type="application/json" id="claims-data">{"heading": "Best in class for its size", "tiles": [{"id": "accuracy_vs:indicxlit_model", "value": 70.4, "dec": 1, "unit": "%", "label": "top-1 — higher than IndicXlit (model only) (59.2%)", "sub": "at 5× smaller · Aksharantar Hindi test"}, {"id": "accuracy_vs:indicxlit_full", "value": 70.4, "dec": 1, "unit": "%", "label": "top-1 — higher than IndicXlit (full package) (69.3%)", "sub": "at 47× smaller · Aksharantar Hindi test"}, {"id": "accuracy_per_mb_rank1", "value": 8.1, "dec": 1, "unit": "pts/MB", "label": "highest top-1 accuracy per MB among compared models", "sub": "next: IndicXlit (model only) at 1.28 pts/MB"}, {"id": "top3_vs_top1:indicxlit_model", "value": 87.7, "dec": 1, "unit": "%", "label": "right word in the first 3 suggestions — vs 59.2% top-1 for IndicXlit (model only)", "sub": "Aksharantar Hindi test"}, {"id": "top3_vs_top1:indicxlit_full", "value": 87.7, "dec": 1, "unit": "%", "label": "right word in the first 3 suggestions — vs 69.3% top-1 for IndicXlit (full package)", "sub": "Aksharantar Hindi test"}, {"id": "smaller_than:indicxlit_model", "value": 5, "dec": 0, "unit": "×", "label": "smaller than IndicXlit (model only)", "sub": "8.68 MB vs 46.0 MB on disk (fp32 weights)"}, {"id": "smaller_than:indicxlit_full", "value": 47, "dec": 0, "unit": "×", "label": "smaller than IndicXlit (full package)", "sub": "8.68 MB vs 404 MB on disk (fp32 weights + 358 MB rescoring dictionary)"}, {"id": "browser_latency", "value": 219.7, "dec": 1, "unit": "ms", "label": "per word (p50) in the browser", "sub": "an 8-vCPU Intel Xeon cloud VM (headless Chrome 156, Linux)"}, {"id": "package_size", "value": 4.53, "dec": 2, "unit": "MB", "label": "complete download", "sub": "core + 1.5M-word dictionary pack · 989K parameters"}, {"id": "core_size", "value": 0.57, "dec": 2, "unit": "MB", "label": "to start typing", "sub": "the core works on its own (53.4% top-1 without the pack); the dictionary pack streams in after and is cached"}], "board": [{"name": "AksharaLP-1M", "bytes": 8684745, "top1": 70.37, "us": true, "per_mb": 8.10271343603065}, {"name": "IndicXlit (model only)", "bytes": 46043828, "top1": 59.16, "us": false, "per_mb": 1.2848627616278994}, {"name": "IndicXlit (full package)", "bytes": 404043828, "top1": 69.33, "us": false, "per_mb": 0.1715902958923555}], "highlight": "No compared model is both smaller and more accurate: AksharaLP-1M sits on the size–accuracy frontier."}</script>
|
| 115 |
+
|
| 116 |
+
<section class="section">
|
| 117 |
+
<div class="sec-head"><h2>Small model. Serious accuracy.</h2><p>Built for keyboards, chat apps and browsers where every kilobyte and millisecond counts.</p></div>
|
| 118 |
+
<div class="features" id="features"></div>
|
| 119 |
+
</section>
|
| 120 |
+
|
| 121 |
+
<section class="section">
|
| 122 |
+
<div class="sec-head"><h2>Fits where big models can’t</h2><p>Download size of the core and of core + dictionary versus a widely used open transliteration model.</p></div>
|
| 123 |
+
<div class="sizes card" id="sizes"></div>
|
| 124 |
+
</section>
|
| 125 |
+
|
| 126 |
+
<section class="section how">
|
| 127 |
+
<div class="sec-head"><h2>How it works</h2></div>
|
| 128 |
+
<ol class="steps">
|
| 129 |
+
<li><span class="n">1</span><b>Generate</b><p>A 4-bit character Transformer (the core) proposes spellings. With the dictionary pack attached it also searches a lexicon trie and consonant-skeleton matches, and adds acronym and spelling-variant candidates.</p></li>
|
| 130 |
+
<li><span class="n">2</span><b>Rerank</b><p>A tiny learned reranker scores every candidate with model, lexicon and frequency features.</p></li>
|
| 131 |
+
<li><span class="n">3</span><b>Decide in context</b><p>With the dictionary pack, a compact word-bigram language model chooses the best sentence, e.g. <span class="deva">मैं</span> vs <span class="deva">में</span>. Without it, each word keeps its top-ranked spelling.</p></li>
|
| 132 |
+
</ol>
|
| 133 |
+
</section>
|
| 134 |
+
<section class="section" id="license" aria-labelledby="license-h">
|
| 135 |
+
<div class="sec-head"><span class="kicker">Apache-2.0 · Copyright 2026 Sourojit Dhua</span><h2 id="license-h">License & attribution</h2>
|
| 136 |
+
<p>Free for commercial use. Credit AksharaLP and Sourojit Dhua when you ship it.</p></div>
|
| 137 |
+
<div class="lic">
|
| 138 |
+
<div class="lic-card ok"><div class="lic-ic">✓</div><h3>Commercial use allowed</h3>
|
| 139 |
+
<p>Use, modify and ship the model and runtime in commercial products, free of charge, under the Apache License 2.0.</p></div>
|
| 140 |
+
<div class="lic-card req"><div class="lic-ic">§</div><h3>Attribution required</h3>
|
| 141 |
+
<p>Apache-2.0 §4(d): every redistribution or derivative (apps, web pages, extensions, SDKs, fine-tuned or converted models) must include the <code>NOTICE</code> file. The runtime keeps its <code>/*! … */</code> header, including when minified.</p></div>
|
| 142 |
+
</div>
|
| 143 |
+
<div class="attr">
|
| 144 |
+
<div class="attr-row"><span class="attr-k">Attribution text <em>(required)</em></span>
|
| 145 |
+
<pre class="attr-code" id="attr-req">Transliteration by AksharaLP (Sourojit Dhua) — https://huggingface.co/sourojitdotcom/AksharaLP-1M</pre>
|
| 146 |
+
<button class="ghost-btn attr-copy" data-copy="attr-req">Copy</button></div>
|
| 147 |
+
<div class="attr-row"><span class="attr-k">In-app credit <em>(recommended)</em></span>
|
| 148 |
+
<pre class="attr-code" id="attr-app">Hindi typing powered by <a href="https://huggingface.co/sourojitdotcom/AksharaLP-1M">AksharaLP by Sourojit Dhua</a></pre>
|
| 149 |
+
<button class="ghost-btn attr-copy" data-copy="attr-app">Copy</button></div>
|
| 150 |
+
<div class="attr-row"><span class="attr-k">Citation <em>(BibTeX)</em></span>
|
| 151 |
+
<pre class="attr-code" id="attr-bib">@software{dhua_aksharalp_2026,
|
| 152 |
+
author = {Dhua, Sourojit},
|
| 153 |
+
title = {AksharaLP: Tiny, Context-Aware Hindi Transliteration for the Browser},
|
| 154 |
+
year = {2026},
|
| 155 |
+
url = {https://huggingface.co/sourojitdotcom/AksharaLP-1M},
|
| 156 |
+
license = {Apache-2.0}
|
| 157 |
+
}</pre>
|
| 158 |
+
<button class="ghost-btn attr-copy" data-copy="attr-bib">Copy</button></div>
|
| 159 |
+
</div>
|
| 160 |
+
</section>
|
| 161 |
+
</main>
|
| 162 |
+
|
| 163 |
+
<footer class="foot">
|
| 164 |
+
<div>AksharaLP by Sourojit Dhua — <a href="https://huggingface.co/sourojitdotcom/AksharaLP-1M" target="_blank" rel="noopener">huggingface.co/sourojitdotcom/AksharaLP-1M</a> · Copyright 2026 Sourojit Dhua · Code & weights Apache-2.0 (attribution required, see NOTICE) · Data attributions in the <a href="https://huggingface.co/sourojitdotcom/AksharaLP-1M" target="_blank" rel="noopener">model card</a></div>
|
| 165 |
+
<div class="muted">Inference runs locally in a Web Worker (dependency-free JavaScript). No analytics, no network calls after load.</div>
|
| 166 |
+
</footer>
|
| 167 |
+
|
| 168 |
+
<div class="toast" id="toast" role="status"></div>
|
| 169 |
+
<script type="module" src="js/app.js"></script>
|
| 170 |
+
</body>
|
| 171 |
</html>
|
js/aksharalp.mjs
ADDED
|
@@ -0,0 +1,718 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*!
|
| 2 |
+
* BhashaCore JS runtime — romanized Hindi / Hinglish -> Devanagari, fully offline (browser, Web Worker, Node >= 18).
|
| 3 |
+
* Zero dependencies. Pure-JS port of the reference Python runtime (bhc/translit2.py, bhc/xlit_q.py, bhc/lexlm.py,
|
| 4 |
+
* bhc/lextrie.py, bhc/lid.py, bhc/hinglish.py) over the exported asset formats:
|
| 5 |
+
* xlit.q4 | xlit.q8 | xlit.int8 char Transformer (pre-LN enc/dec), 4/8-bit grouped or per-row INT8 weights
|
| 6 |
+
* lex.bin Devanagari lexicon (LX4 alphabetical front-coded + 4-bit bands, or v2 bucketed)
|
| 7 |
+
* lm.bin pruned backoff word-bigram LM (varint CSR + 4-bit codebooks)
|
| 8 |
+
* params.json decoding params + reranker (linear w or MLP w1/b1/w2/b2; mu / sd)
|
| 9 |
+
* lid.int8 char-CNN + BiGRU token / sentence language ID (optional)
|
| 10 |
+
* loan.tsv, natural_hi.tsv Hinglish loanword lexicon, Natural-Hindi glossary (optional)
|
| 11 |
+
* Bundle layout: a small CORE (model + params.json) that works standalone, plus an optional dictionary pack in
|
| 12 |
+
* dict/ (lex.bin + lm.bin + params.json overriding the core params), fetched on first use, cached with the Cache API
|
| 13 |
+
* when available, and attached with engine.loadDict(); if it cannot be fetched the engine stays in core-only mode.
|
| 14 |
+
*
|
| 15 |
+
* AksharaLP by Sourojit Dhua — https://huggingface.co/sourojitdotcom/AksharaLP-1M
|
| 16 |
+
* Copyright 2026 Sourojit Dhua. Licensed under the Apache License, Version 2.0; commercial use permitted.
|
| 17 |
+
* Attribution required (Apache-2.0 §4(d)): keep this notice and the NOTICE file in redistributions and derivatives:
|
| 18 |
+
* "Transliteration by AksharaLP (Sourojit Dhua) — https://huggingface.co/sourojitdotcom/AksharaLP-1M"
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
// ------------------------------------------------------------------ vocab
|
| 22 |
+
const PAD = 0, BOS = 1, EOS = 2, UNK = 3, MAXLEN = 32, V = 132;
|
| 23 |
+
const NEG = -Infinity;
|
| 24 |
+
const encSrc = (w) => {
|
| 25 |
+
const s = w.toLowerCase().slice(0, MAXLEN - 1), ids = [];
|
| 26 |
+
for (const c of s) { const k = c.charCodeAt(0); ids.push(c.length === 1 && k >= 97 && k <= 122 ? k - 97 + 4 : UNK); }
|
| 27 |
+
ids.push(EOS); return ids;
|
| 28 |
+
};
|
| 29 |
+
const t2i = (ch) => { const k = ch.codePointAt(0); return k >= 0x900 && k < 0x980 ? k - 0x900 + 4 : -1; };
|
| 30 |
+
const encTgt = (w) => { const ids = []; for (const c of [...w].slice(0, MAXLEN - 2)) { const i = t2i(c); ids.push(i < 0 ? UNK : i); } ids.push(EOS); return ids; };
|
| 31 |
+
const decTgt = (ids) => { let s = ""; for (const i of ids) if (i > UNK) s += String.fromCharCode(0x900 + i - 4); return s; };
|
| 32 |
+
|
| 33 |
+
// ------------------------------------------------------------------ binary helpers
|
| 34 |
+
function f16(h) {
|
| 35 |
+
const s = (h & 0x8000) ? -1 : 1, e = (h >> 10) & 0x1f, f = h & 0x3ff;
|
| 36 |
+
if (e === 0) return s * f * 5.960464477539063e-8;
|
| 37 |
+
if (e === 31) return f ? NaN : s * Infinity;
|
| 38 |
+
return s * (1 + f / 1024) * Math.pow(2, e - 15);
|
| 39 |
+
}
|
| 40 |
+
function readHeader(buf) {
|
| 41 |
+
const u8 = new Uint8Array(buf), dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
|
| 42 |
+
const n = dv.getUint32(0, true);
|
| 43 |
+
const meta = JSON.parse(new TextDecoder().decode(u8.subarray(4, 4 + n)));
|
| 44 |
+
const data = u8.subarray(4 + n);
|
| 45 |
+
return { meta, data, dv: new DataView(data.buffer, data.byteOffset, data.byteLength) };
|
| 46 |
+
}
|
| 47 |
+
const prod = (a) => a.reduce((x, y) => x * y, 1);
|
| 48 |
+
const f16arr = (dv, off, n) => { const o = new Float32Array(n); for (let i = 0; i < n; i++) o[i] = f16(dv.getUint16(off + 2 * i, true)); return o; };
|
| 49 |
+
|
| 50 |
+
/** Parse xlit.int8 / xlit.q4 / xlit.q8 / lid.int8 into {cfg, extra, T: {name: {shape, data: Float32Array}}}. */
|
| 51 |
+
export function parseWeights(buf) {
|
| 52 |
+
const { meta, data, dv } = readHeader(buf); const T = {};
|
| 53 |
+
for (const t of meta.tensors) {
|
| 54 |
+
const [k, shape, kind, off] = t; const cnt = prod(shape); let w;
|
| 55 |
+
if (kind === "f16") w = f16arr(dv, off, cnt);
|
| 56 |
+
else if (kind === "i8") { // per-row symmetric INT8 (+ fp16 row scale)
|
| 57 |
+
const r = shape[0], c = cnt / r, sc = f16arr(dv, off + cnt, r); w = new Float32Array(cnt);
|
| 58 |
+
for (let i = 0; i < r; i++) for (let j = 0; j < c; j++) { const q = (data[off + i * c + j] << 24) >> 24; w[i * c + j] = q * sc[i]; }
|
| 59 |
+
} else { // q4 / q8: group-wise symmetric (G inputs per fp16 scale)
|
| 60 |
+
const bits = kind.length > 1 ? parseInt(kind.slice(1)) : meta.bits, G = meta.G, ln = t[4];
|
| 61 |
+
const [r, c] = shape, ng = Math.ceil(c / G), sc = f16arr(dv, off + ln, r * ng); w = new Float32Array(cnt);
|
| 62 |
+
for (let i = 0; i < cnt; i++) {
|
| 63 |
+
let q;
|
| 64 |
+
if (bits === 4) { const b = data[off + (i >> 1)]; q = ((i & 1) ? (b & 15) : (b >> 4)) - 8; }
|
| 65 |
+
else q = (data[off + i] << 24) >> 24;
|
| 66 |
+
const row = (i / c) | 0, col = i - row * c; w[i] = q * sc[row * ng + ((col / G) | 0)];
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
T[k] = { shape, data: w };
|
| 70 |
+
}
|
| 71 |
+
return { cfg: meta.cfg, extra: meta.extra || {}, T };
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
// ------------------------------------------------------------------ math kernels
|
| 75 |
+
function linear(x, xo, W, b, out, oo, nin, nout) { // out[oo..] = W x + b ; W row-major [nout, nin]
|
| 76 |
+
for (let o = 0; o < nout; o++) {
|
| 77 |
+
let s = b ? b[o] : 0; const r = o * nin;
|
| 78 |
+
for (let i = 0; i < nin; i++) s += W[r + i] * x[xo + i];
|
| 79 |
+
out[oo + o] = s;
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
function layerNorm(x, xo, g, b, out, oo, d) {
|
| 83 |
+
let m = 0; for (let i = 0; i < d; i++) m += x[xo + i]; m /= d;
|
| 84 |
+
let v = 0; for (let i = 0; i < d; i++) { const t = x[xo + i] - m; v += t * t; } v /= d;
|
| 85 |
+
const r = 1 / Math.sqrt(v + 1e-5);
|
| 86 |
+
for (let i = 0; i < d; i++) out[oo + i] = (x[xo + i] - m) * r * g[i] + b[i];
|
| 87 |
+
}
|
| 88 |
+
function erf(x) { // |err| < 1.2e-7 (Numerical Recipes erfc)
|
| 89 |
+
const z = Math.abs(x), t = 1 / (1 + 0.5 * z);
|
| 90 |
+
const r = t * Math.exp(-z * z - 1.26551223 + t * (1.00002368 + t * (0.37409196 + t * (0.09678418 + t * (-0.18628806 +
|
| 91 |
+
t * (0.27886807 + t * (-1.13520398 + t * (1.48851587 + t * (-0.82215223 + t * 0.17087277)))))))));
|
| 92 |
+
return x >= 0 ? 1 - r : r - 1;
|
| 93 |
+
}
|
| 94 |
+
const gelu = (x) => 0.5 * x * (1 + erf(x / Math.SQRT2));
|
| 95 |
+
const sigmoid = (x) => 1 / (1 + Math.exp(-x));
|
| 96 |
+
|
| 97 |
+
// ------------------------------------------------------------------ char Transformer
|
| 98 |
+
export class XlitModel {
|
| 99 |
+
constructor(w) {
|
| 100 |
+
const c = w.cfg; this.d = c.d; this.h = c.h; this.dk = c.d / c.h; this.ff = c.ff; this.ne = c.enc; this.nd = c.dec;
|
| 101 |
+
const g = (k) => { const t = w.T[k]; if (!t) throw new Error("missing tensor " + k); return t.data; };
|
| 102 |
+
this.semb = g("semb.weight"); this.temb = g("temb.weight"); this.spos = g("spos.weight"); this.tpos = g("tpos.weight");
|
| 103 |
+
const att = (p) => ({ q: g(p + ".q.weight"), qb: g(p + ".q.bias"), kv: g(p + ".kv.weight"), kvb: g(p + ".kv.bias"), o: g(p + ".o.weight"), ob: g(p + ".o.bias") });
|
| 104 |
+
const ln = (p) => ({ g: g(p + ".weight"), b: g(p + ".bias") });
|
| 105 |
+
const ffn = (p) => ({ w1: g(p + ".ff.0.weight"), b1: g(p + ".ff.0.bias"), w2: g(p + ".ff.2.weight"), b2: g(p + ".ff.2.bias") });
|
| 106 |
+
this.enc = []; for (let i = 0; i < c.enc; i++) { const p = "enc." + i; this.enc.push({ n1: ln(p + ".n1"), att: att(p + ".att"), n2: ln(p + ".n2"), ff: ffn(p) }); }
|
| 107 |
+
this.dec = []; for (let i = 0; i < c.dec; i++) { const p = "dec." + i; this.dec.push({ n1: ln(p + ".n1"), sa: att(p + ".sa"), n2: ln(p + ".n2"), ca: att(p + ".ca"), n3: ln(p + ".n3"), ff: ffn(p) }); }
|
| 108 |
+
this.en = ln("en"); this.dn = ln("dn"); this.scale = Math.sqrt(c.d);
|
| 109 |
+
this.nParams = Object.values(w.T).reduce((a, t) => a + t.data.length, 0);
|
| 110 |
+
const d = this.d; this._y = new Float32Array(d); this._a = new Float32Array(d); this._f = new Float32Array(this.ff); this._q = new Float32Array(d); this._kv = new Float32Array(2 * d);
|
| 111 |
+
this._sc = new Float64Array(MAXLEN);
|
| 112 |
+
}
|
| 113 |
+
_ffn(L, x, xo, n) { // x[xo] += FF(LN(x))
|
| 114 |
+
const d = this.d, y = this._y, f = this._f, a = this._a;
|
| 115 |
+
layerNorm(x, xo, n.g, n.b, y, 0, d); linear(y, 0, L.w1, L.b1, f, 0, d, this.ff);
|
| 116 |
+
for (let i = 0; i < this.ff; i++) f[i] = gelu(f[i]);
|
| 117 |
+
linear(f, 0, L.w2, L.b2, a, 0, this.ff, d); for (let i = 0; i < d; i++) x[xo + i] += a[i];
|
| 118 |
+
}
|
| 119 |
+
/** attention of one query q (len d) over K/V rows (stride 2d in kvbuf: K at +0, V at +d) -> out (len d) */
|
| 120 |
+
_attend(q, kvbuf, kvo, n, out) {
|
| 121 |
+
const { h, dk, d } = this, sc = n <= MAXLEN ? this._sc : new Float64Array(n), inv = 1 / Math.sqrt(dk);
|
| 122 |
+
for (let hh = 0; hh < h; hh++) {
|
| 123 |
+
let mx = -Infinity;
|
| 124 |
+
for (let j = 0; j < n; j++) { let s = 0; const ko = kvo + j * 2 * d + hh * dk; for (let i = 0; i < dk; i++) s += q[hh * dk + i] * kvbuf[ko + i]; s *= inv; sc[j] = s; if (s > mx) mx = s; }
|
| 125 |
+
let z = 0; for (let j = 0; j < n; j++) { sc[j] = Math.exp(sc[j] - mx); z += sc[j]; }
|
| 126 |
+
for (let i = 0; i < dk; i++) { let s = 0; for (let j = 0; j < n; j++) s += sc[j] * kvbuf[kvo + j * 2 * d + d + hh * dk + i]; out[hh * dk + i] = s / z; }
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
/** encode one word -> {S, cross: per decoder layer K/V of memory (Float32Array S*2d)} */
|
| 130 |
+
encode(ids) {
|
| 131 |
+
const d = this.d, S = ids.length, x = new Float32Array(S * d), y = new Float32Array(S * d), kv = new Float32Array(S * 2 * d), att = new Float32Array(d), o = this._a;
|
| 132 |
+
for (let t = 0; t < S; t++) for (let i = 0; i < d; i++) x[t * d + i] = this.semb[ids[t] * d + i] * this.scale + this.spos[t * d + i];
|
| 133 |
+
for (const L of this.enc) {
|
| 134 |
+
for (let t = 0; t < S; t++) { layerNorm(x, t * d, L.n1.g, L.n1.b, y, t * d, d); linear(y, t * d, L.att.kv, L.att.kvb, kv, t * 2 * d, d, 2 * d); }
|
| 135 |
+
const nx = new Float32Array(x);
|
| 136 |
+
for (let t = 0; t < S; t++) {
|
| 137 |
+
linear(y, t * d, L.att.q, L.att.qb, this._q, 0, d, d); this._attend(this._q, kv, 0, S, att);
|
| 138 |
+
linear(att, 0, L.att.o, L.att.ob, o, 0, d, d); for (let i = 0; i < d; i++) nx[t * d + i] += o[i];
|
| 139 |
+
}
|
| 140 |
+
for (let t = 0; t < S; t++) this._ffn(L.ff, nx, t * d, L.n2);
|
| 141 |
+
x.set(nx);
|
| 142 |
+
}
|
| 143 |
+
const mem = new Float32Array(S * d); for (let t = 0; t < S; t++) layerNorm(x, t * d, this.en.g, this.en.b, mem, t * d, d);
|
| 144 |
+
const cross = this.dec.map((L) => { const c = new Float32Array(S * 2 * d); for (let t = 0; t < S; t++) linear(mem, t * d, L.ca.kv, L.ca.kvb, c, t * 2 * d, d, 2 * d); return c; });
|
| 145 |
+
return { S, cross };
|
| 146 |
+
}
|
| 147 |
+
newCache(K) { const d = this.d; return this.dec.map(() => new Float32Array(K * MAXLEN * 2 * d)); }
|
| 148 |
+
/** one decoder step for beam rows `rows` (indices into cache) with tokens tok[row] at position t -> logprobs[row] (Float64Array V) */
|
| 149 |
+
step(enc, cache, rows, tok, t, out) {
|
| 150 |
+
const d = this.d, x = new Float32Array(d), y = this._y, att = new Float32Array(d), o = this._a;
|
| 151 |
+
for (const r of rows) {
|
| 152 |
+
for (let i = 0; i < d; i++) x[i] = this.temb[tok[r] * d + i] * this.scale + this.tpos[t * d + i];
|
| 153 |
+
for (let l = 0; l < this.nd; l++) {
|
| 154 |
+
const L = this.dec[l], C = cache[l], base = r * MAXLEN * 2 * d;
|
| 155 |
+
layerNorm(x, 0, L.n1.g, L.n1.b, y, 0, d);
|
| 156 |
+
linear(y, 0, L.sa.kv, L.sa.kvb, C, base + t * 2 * d, d, 2 * d);
|
| 157 |
+
linear(y, 0, L.sa.q, L.sa.qb, this._q, 0, d, d); this._attend(this._q, C, base, t + 1, att);
|
| 158 |
+
linear(att, 0, L.sa.o, L.sa.ob, o, 0, d, d); for (let i = 0; i < d; i++) x[i] += o[i];
|
| 159 |
+
layerNorm(x, 0, L.n2.g, L.n2.b, y, 0, d);
|
| 160 |
+
linear(y, 0, L.ca.q, L.ca.qb, this._q, 0, d, d); this._attend(this._q, enc.cross[l], 0, enc.S, att);
|
| 161 |
+
linear(att, 0, L.ca.o, L.ca.ob, o, 0, d, d); for (let i = 0; i < d; i++) x[i] += o[i];
|
| 162 |
+
this._ffn(L.ff, x, 0, L.n3);
|
| 163 |
+
}
|
| 164 |
+
layerNorm(x, 0, this.dn.g, this.dn.b, y, 0, d);
|
| 165 |
+
const lp = out[r]; let mx = -Infinity;
|
| 166 |
+
for (let v = 0; v < V; v++) { let s = 0; for (let i = 0; i < d; i++) s += y[i] * this.temb[v * d + i]; lp[v] = s; if (s > mx) mx = s; }
|
| 167 |
+
let z = 0; for (let v = 0; v < V; v++) z += Math.exp(lp[v] - mx); const lz = mx + Math.log(z);
|
| 168 |
+
for (let v = 0; v < V; v++) lp[v] -= lz;
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
/** beam search for one word (identical procedure to bhc.xlit_model.beam_search_fast for one batch row) */
|
| 172 |
+
beam(enc, S, { beam: K = 8, nbest = 8, trie = null } = {}) {
|
| 173 |
+
const d = this.d, cache = this.newCache(K), out = Array.from({ length: K }, () => new Float64Array(V));
|
| 174 |
+
let score = new Array(K).fill(NEG); score[0] = 0; let tok = new Array(K).fill(BOS); let hist = Array.from({ length: K }, () => []);
|
| 175 |
+
let nodes = trie ? new Array(K).fill(0) : null; const done = []; const L = Math.min(MAXLEN - 1, S + 8);
|
| 176 |
+
const tmp = new Float32Array(MAXLEN * 2 * d);
|
| 177 |
+
for (let t = 0; t < L; t++) {
|
| 178 |
+
const rows = []; for (let k = 0; k < K; k++) if (score[k] > NEG) rows.push(k);
|
| 179 |
+
this.step(enc, cache, rows, tok, t, out);
|
| 180 |
+
const cand = []; // (total, beam, v)
|
| 181 |
+
for (const k of rows) {
|
| 182 |
+
const lp = out[k]; let allow = null;
|
| 183 |
+
if (trie) { const n = nodes[k]; if (n === null) continue; allow = trie.allowed(n); }
|
| 184 |
+
if (allow) { for (const v of allow) if (v !== PAD && v !== BOS && v !== UNK) cand.push([score[k] + lp[v], k, v]); }
|
| 185 |
+
else { cand.push([score[k] + lp[EOS], k, EOS]); for (let v = 4; v < V; v++) cand.push([score[k] + lp[v], k, v]); }
|
| 186 |
+
}
|
| 187 |
+
cand.sort((a, b) => b[0] - a[0] || (a[1] * V + a[2]) - (b[1] * V + b[2]));
|
| 188 |
+
const top = cand.slice(0, 2 * K);
|
| 189 |
+
const ns = new Array(K).fill(NEG), nt = new Array(K).fill(EOS), par = new Array(K).fill(0), nn = trie ? new Array(K).fill(null) : null;
|
| 190 |
+
let j = 0;
|
| 191 |
+
for (const [sc, b, v] of top) {
|
| 192 |
+
if (!(sc > NEG)) continue;
|
| 193 |
+
if (v === EOS) { if (done.length < nbest) done.push([decTgt(hist[b]), sc]); continue; }
|
| 194 |
+
if (j < K) { ns[j] = sc; nt[j] = v; par[j] = b; if (trie) nn[j] = trie.child(nodes[b], v); j++; }
|
| 195 |
+
}
|
| 196 |
+
let alive = true;
|
| 197 |
+
if (done.length >= nbest && (j === 0 || ns[0] < Math.min(...done.map((x) => x[1])))) alive = false;
|
| 198 |
+
else if (!j) alive = false;
|
| 199 |
+
if (!alive) break;
|
| 200 |
+
for (const C of cache) { // reorder self-attention caches by parent beam
|
| 201 |
+
const n = (t + 1) * 2 * d, olds = [];
|
| 202 |
+
for (let k = 0; k < j; k++) { const src = par[k] * MAXLEN * 2 * d; olds.push(C.slice(src, src + n)); }
|
| 203 |
+
for (let k = 0; k < j; k++) C.set(olds[k], k * MAXLEN * 2 * d);
|
| 204 |
+
}
|
| 205 |
+
hist = Array.from({ length: K }, (_, k) => (k < j ? hist[par[k]].concat([nt[k]]) : []));
|
| 206 |
+
score = ns; tok = nt; nodes = nn;
|
| 207 |
+
}
|
| 208 |
+
const best = new Map();
|
| 209 |
+
for (const [s, sc] of done) if (!best.has(s) || sc > best.get(s)) best.set(s, sc);
|
| 210 |
+
return [...best.entries()].sort((a, b) => b[1] - a[1]).slice(0, nbest);
|
| 211 |
+
}
|
| 212 |
+
/** teacher-forced ln P(tgt | src) (as bhc.xlit_model.score_pairs) */
|
| 213 |
+
scorePair(enc, tgt) {
|
| 214 |
+
const ids = encTgt(tgt), cache = this.newCache(1), out = [new Float64Array(V)]; let tok = [BOS], s = 0;
|
| 215 |
+
for (let t = 0; t < ids.length; t++) { this.step(enc, cache, [0], tok, t, out); s += out[0][ids[t]]; tok = [ids[t]]; }
|
| 216 |
+
return s;
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
// ------------------------------------------------------------------ lexicon + bigram LM
|
| 221 |
+
function readVarints(b, n, pos) {
|
| 222 |
+
const out = new Uint32Array(n);
|
| 223 |
+
for (let i = 0; i < n; i++) { let v = 0, sh = 0, c; do { c = b[pos++]; v += (c & 0x7f) * 2 ** sh; sh += 7; } while (c >= 0x80); out[i] = v; }
|
| 224 |
+
return [out, pos];
|
| 225 |
+
}
|
| 226 |
+
const unpack4 = (b, n) => { const o = new Uint8Array(n); for (let i = 0; i < n; i++) o[i] = (i & 1) ? b[i >> 1] & 15 : b[i >> 1] >> 4; return o; };
|
| 227 |
+
|
| 228 |
+
export class LexLM {
|
| 229 |
+
constructor(lexBuf, lmBuf) {
|
| 230 |
+
if (!lexBuf) { // core-only: empty lexicon, no LM
|
| 231 |
+
this.words = []; this.sortedWords = []; this.uni = new Float32Array(0); this.N = 0; this.unk = 0; this.alpha = true; this.hasLM = false; return;
|
| 232 |
+
}
|
| 233 |
+
const b = new Uint8Array(lexBuf), dv = new DataView(b.buffer, b.byteOffset, b.byteLength); const words = [];
|
| 234 |
+
const decodeFC = (P, S, nWords) => { let prev = [], j = 0, pi = 0;
|
| 235 |
+
while (words.length < nWords) { const k = P ? P[pi++] : S[j++]; const cur = prev.slice(0, k);
|
| 236 |
+
for (;;) { const c = S[j++], ch = c & 0x7f; if (ch !== 0x7f) cur.push(ch); if (c & 0x80) break; }
|
| 237 |
+
words.push(String.fromCharCode(...cur.map((x) => 0x900 + x))); prev = cur; } };
|
| 238 |
+
if (b[0] === 0x4c && b[1] === 0x58 && b[2] === 0x34 && b[3] === 0) { // "LX4\0"
|
| 239 |
+
const N = dv.getUint32(4, true), nfc = dv.getUint32(8, true), NB = dv.getUint32(16, true); this.unk = dv.getFloat32(12, true);
|
| 240 |
+
let pos = 20; const ucb = new Float32Array(NB); for (let i = 0; i < NB; i++) ucb[i] = dv.getFloat32(pos + 4 * i, true); pos += 4 * NB;
|
| 241 |
+
const band = unpack4(b.subarray(pos, pos + ((N + 1) >> 1)), N); pos += (N + 1) >> 1;
|
| 242 |
+
this.uni = new Float32Array(N); for (let i = 0; i < N; i++) this.uni[i] = ucb[band[i]];
|
| 243 |
+
decodeFC(b.subarray(pos, pos + N), b.subarray(pos + N, pos + N + nfc), N); this.N = N; this.alpha = true;
|
| 244 |
+
} else { // v2 (frequency-bucketed)
|
| 245 |
+
const N = dv.getUint32(0, true), nb = dv.getUint32(4, true), nfc = dv.getUint32(8, true); this.unk = dv.getFloat32(12, true);
|
| 246 |
+
let [bn, pos] = readVarints(b, nb, 16); const blp = []; for (let i = 0; i < nb; i++) blp.push(f16(dv.getUint16(pos + 2 * i, true))); pos += 2 * nb;
|
| 247 |
+
this.uni = new Float32Array(N); let w = 0; for (let i = 0; i < nb; i++) for (let k = 0; k < bn[i]; k++) this.uni[w++] = blp[i];
|
| 248 |
+
decodeFC(null, b.subarray(pos, pos + nfc), N); this.N = N; this.alpha = false;
|
| 249 |
+
}
|
| 250 |
+
this.words = words;
|
| 251 |
+
let sorted = this.alpha; for (let i = 1; sorted && i < words.length; i++) if (!(words[i - 1] < words[i])) sorted = false;
|
| 252 |
+
if (!sorted) { this.map = new Map(); words.forEach((w, i) => this.map.set(w, i)); }
|
| 253 |
+
this.sortedWords = sorted ? words : [...new Set(words)].sort();
|
| 254 |
+
this.hasLM = false;
|
| 255 |
+
if (lmBuf) this._loadLM(new Uint8Array(lmBuf));
|
| 256 |
+
}
|
| 257 |
+
id(w) {
|
| 258 |
+
if (this.map) { const i = this.map.get(w); return i === undefined ? null : i; }
|
| 259 |
+
let lo = 0, hi = this.words.length; while (lo < hi) { const m = (lo + hi) >> 1; if (this.words[m] < w) lo = m + 1; else hi = m; }
|
| 260 |
+
return lo < this.words.length && this.words[lo] === w ? lo : null;
|
| 261 |
+
}
|
| 262 |
+
_loadLM(b) {
|
| 263 |
+
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength), N = this.N;
|
| 264 |
+
const nbg = dv.getUint32(4, true), nh = dv.getUint32(16, true); let pos = 20;
|
| 265 |
+
const cb = [], cbb = []; for (let i = 0; i < 16; i++) cb.push(dv.getFloat32(pos + 4 * i, true)); pos += 64;
|
| 266 |
+
for (let i = 0; i < 16; i++) cbb.push(dv.getFloat32(pos + 4 * i, true)); pos += 64;
|
| 267 |
+
let cnt, delta; [cnt, pos] = readVarints(b, N + 1, pos); [delta, pos] = readVarints(b, nbg, pos);
|
| 268 |
+
const q = unpack4(b.subarray(pos, pos + ((nbg + 1) >> 1)), nbg); pos += (nbg + 1) >> 1;
|
| 269 |
+
const qb = unpack4(b.subarray(pos, pos + ((nh + 1) >> 1)), nh);
|
| 270 |
+
this.off = new Uint32Array(N + 2); this.succ = new Uint32Array(nbg); this.bq = q; this.cb = Float32Array.from(cb);
|
| 271 |
+
this.bow = new Float32Array(N + 1); let i = 0, hi = 0;
|
| 272 |
+
for (let h = 0; h <= N; h++) {
|
| 273 |
+
this.off[h] = i; const n = cnt[h]; if (!n) continue;
|
| 274 |
+
this.bow[h] = cbb[qb[hi++]]; let acc = -1;
|
| 275 |
+
for (let k = 0; k < n; k++) { acc = acc < 0 ? delta[i] : acc + delta[i] + 1; this.succ[i++] = acc; }
|
| 276 |
+
}
|
| 277 |
+
this.off[N + 1] = i; this.hasLM = nbg > 0;
|
| 278 |
+
}
|
| 279 |
+
unigram(wid) { return wid === null ? this.unk : wid === this.N ? Math.log(0.04) : this.uni[wid]; }
|
| 280 |
+
/** ln P(wid | prev); prev null = sentence start; wid null = OOV; wid N = </s> */
|
| 281 |
+
logp(prev, wid) {
|
| 282 |
+
const h = prev === null ? this.N : prev;
|
| 283 |
+
if (wid !== null && this.hasLM) {
|
| 284 |
+
let lo = this.off[h], hi = this.off[h + 1];
|
| 285 |
+
while (lo < hi) { const m = (lo + hi) >> 1; if (this.succ[m] < wid) lo = m + 1; else hi = m; }
|
| 286 |
+
if (lo < this.off[h + 1] && this.succ[lo] === wid) return this.cb[this.bq[lo]];
|
| 287 |
+
}
|
| 288 |
+
return (this.hasLM ? this.bow[h] : 0) + this.unigram(wid);
|
| 289 |
+
}
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
/** lazy lexicon trie over the sorted word list (same node semantics as bhc/lextrie.py) */
|
| 293 |
+
class LazyTrie {
|
| 294 |
+
constructor(sortedWords) { this.w = sortedWords; this.nodes = [[0, sortedWords.length, 0]]; this.ids = new Map([["0,0," + sortedWords.length, 0]]); this.cache = new Map(); this.allow = new Map(); }
|
| 295 |
+
_bisect(x, lo, hi) { const w = this.w; while (lo < hi) { const m = (lo + hi) >> 1; if (w[m] < x) lo = m + 1; else hi = m; } return lo; }
|
| 296 |
+
children(n) {
|
| 297 |
+
let c = this.cache.get(n); if (c) return c;
|
| 298 |
+
const [lo, hi, d] = this.nodes[n], w = this.w; c = new Map(); let pos = lo;
|
| 299 |
+
if (pos < hi && w[pos].length === d) pos++;
|
| 300 |
+
while (pos < hi) {
|
| 301 |
+
const ch = w[pos].charCodeAt(d), pre = w[pos].slice(0, d);
|
| 302 |
+
const end = this._bisect(pre + String.fromCharCode(ch + 1), pos, hi);
|
| 303 |
+
const key = pos + "," + (d + 1) + "," + end; let nid = this.ids.get(key);
|
| 304 |
+
if (nid === undefined) { nid = this.nodes.length; this.nodes.push([pos, end, d + 1]); this.ids.set(key, nid); }
|
| 305 |
+
c.set(ch - 0x900 + 4, nid); pos = end;
|
| 306 |
+
}
|
| 307 |
+
if (this.cache.size > 400000) { this.cache.clear(); this.allow.clear(); }
|
| 308 |
+
this.cache.set(n, c); return c;
|
| 309 |
+
}
|
| 310 |
+
final(n) { const [lo, , d] = this.nodes[n]; return lo < this.w.length && this.w[lo].length === d; }
|
| 311 |
+
allowed(n) { let a = this.allow.get(n); if (!a) { a = [...this.children(n).keys()]; if (this.final(n)) a.push(EOS); this.allow.set(n, a); } return a; }
|
| 312 |
+
child(n, v) { return this.children(n).get(v); }
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
// ------------------------------------------------------------------ language ID (char-CNN + BiGRU)
|
| 316 |
+
const LID_CH = {}; [..."abcdefghijklmnopqrstuvwxyz'"].forEach((c, i) => (LID_CH[c] = i + 3));
|
| 317 |
+
const WMAX = 16, MODES3 = ["english", "romanized_hindi", "hinglish"];
|
| 318 |
+
const RE_LATIN_APOS = /^[A-Za-z]+(?:'[A-Za-z]+)?$/, RE_DEVA = /^[\u0900-\u0963\u0971-\u097F]+$/;
|
| 319 |
+
function whash(w, n) { let h = 2166136261; for (const ch of new TextEncoder().encode(w.toLowerCase())) h = Math.imul(h ^ ch, 16777619) >>> 0; return h % n; }
|
| 320 |
+
|
| 321 |
+
export class LID {
|
| 322 |
+
constructor(w) {
|
| 323 |
+
this.cfg = w.cfg; this.x = w.extra || {}; const g = (k) => w.T[k] && w.T[k].data;
|
| 324 |
+
Object.assign(this, { ce: g("ce.weight"), c1: g("c1.weight"), c1b: g("c1.bias"), c2: g("c2.weight"), c2b: g("c2.bias"), wemb: g("wemb.weight"),
|
| 325 |
+
wih: g("gru.weight_ih_l0"), whh: g("gru.weight_hh_l0"), bih: g("gru.bias_ih_l0"), bhh: g("gru.bias_hh_l0"),
|
| 326 |
+
wihR: g("gru.weight_ih_l0_reverse"), whhR: g("gru.weight_hh_l0_reverse"), bihR: g("gru.bias_ih_l0_reverse"), bhhR: g("gru.bias_hh_l0_reverse"),
|
| 327 |
+
tw: g("tok.weight"), tb: g("tok.bias"), s0: g("sent.0.weight"), s0b: g("sent.0.bias"), s2: g("sent.2.weight"), s2b: g("sent.2.bias") });
|
| 328 |
+
this.nParams = Object.values(w.T).reduce((a, t) => a + t.data.length, 0);
|
| 329 |
+
}
|
| 330 |
+
_wvec(word) {
|
| 331 |
+
const { ce: E, cf } = this.cfg; const ids = new Array(WMAX).fill(0); const w = [...word.toLowerCase()].slice(0, WMAX - 2);
|
| 332 |
+
ids[0] = 1; w.forEach((c, i) => (ids[i + 1] = LID_CH[c] ?? 2)); ids[w.length + 1] = 2;
|
| 333 |
+
const x = new Float32Array(E * WMAX); for (let t = 0; t < WMAX; t++) for (let i = 0; i < E; i++) x[i * WMAX + t] = this.ce[ids[t] * E + i];
|
| 334 |
+
const conv = (inp, cin, W, b) => { const o = new Float32Array(cf * WMAX);
|
| 335 |
+
for (let oc = 0; oc < cf; oc++) for (let t = 0; t < WMAX; t++) { let s = b[oc];
|
| 336 |
+
for (let ic = 0; ic < cin; ic++) for (let k = 0; k < 3; k++) { const tt = t + k - 1; if (tt >= 0 && tt < WMAX) s += W[(oc * cin + ic) * 3 + k] * inp[ic * WMAX + tt]; }
|
| 337 |
+
o[oc * WMAX + t] = s > 0 ? s : 0; } return o; };
|
| 338 |
+
const h1 = conv(x, E, this.c1, this.c1b), h2 = conv(h1, cf, this.c2, this.c2b);
|
| 339 |
+
const wh = this.cfg.wh, wd = this.cfg.wd, v = new Float32Array(cf + (wh ? wd : 0));
|
| 340 |
+
for (let oc = 0; oc < cf; oc++) { let m = -Infinity; for (let t = 0; t < WMAX; t++) { const val = ids[t] === 0 ? -1e4 : h2[oc * WMAX + t] + h1[oc * WMAX + t]; if (val > m) m = val; } v[oc] = m; }
|
| 341 |
+
if (wh) { const r = whash(word, wh); for (let i = 0; i < wd; i++) v[cf + i] = this.wemb[r * wd + i]; }
|
| 342 |
+
return v;
|
| 343 |
+
}
|
| 344 |
+
_gru(xs, Wih, Whh, bih, bhh, rev) {
|
| 345 |
+
const H = this.cfg.hid, nin = xs[0].length, T = xs.length, out = new Array(T); let h = new Float32Array(H);
|
| 346 |
+
const gi = new Float32Array(3 * H), gh = new Float32Array(3 * H);
|
| 347 |
+
for (let s = 0; s < T; s++) {
|
| 348 |
+
const t = rev ? T - 1 - s : s; linear(xs[t], 0, Wih, bih, gi, 0, nin, 3 * H); linear(h, 0, Whh, bhh, gh, 0, H, 3 * H);
|
| 349 |
+
const nh = new Float32Array(H);
|
| 350 |
+
for (let i = 0; i < H; i++) { const r = sigmoid(gi[i] + gh[i]), z = sigmoid(gi[H + i] + gh[H + i]), n = Math.tanh(gi[2 * H + i] + r * gh[2 * H + i]); nh[i] = (1 - z) * n + z * h[i]; }
|
| 351 |
+
h = nh; out[t] = h;
|
| 352 |
+
}
|
| 353 |
+
return out;
|
| 354 |
+
}
|
| 355 |
+
/** Latin words -> {pen: P(EN) per word, ps: [english, romanized_hindi, hinglish]} */
|
| 356 |
+
run(words) {
|
| 357 |
+
if (!words.length) return { pen: [], ps: null };
|
| 358 |
+
const H = this.cfg.hid, xs = words.map((w) => this._wvec(w)), T = xs.length, nin = xs[0].length;
|
| 359 |
+
const f = this._gru(xs, this.wih, this.whh, this.bih, this.bhh, false), r = this._gru(xs, this.wihR, this.whhR, this.bihR, this.bhhR, true);
|
| 360 |
+
const pen = [], hm = new Float32Array(2 * H), hx = new Float32Array(2 * H).fill(-1e4), z = new Float32Array(2 * H + nin), lo = new Float32Array(2);
|
| 361 |
+
for (let t = 0; t < T; t++) {
|
| 362 |
+
for (let i = 0; i < H; i++) { z[i] = f[t][i]; z[H + i] = r[t][i]; } z.set(xs[t], 2 * H);
|
| 363 |
+
linear(z, 0, this.tw, this.tb, lo, 0, 2 * H + nin, 2); const m = Math.max(lo[0], lo[1]), e0 = Math.exp(lo[0] - m), e1 = Math.exp(lo[1] - m); pen.push(e0 / (e0 + e1));
|
| 364 |
+
for (let i = 0; i < 2 * H; i++) { hm[i] += z[i] / T; if (z[i] > hx[i]) hx[i] = z[i]; }
|
| 365 |
+
}
|
| 366 |
+
const sin = new Float32Array(4 * H + 1); sin.set(hm, 0); sin.set(hx, 2 * H); sin[4 * H] = pen.reduce((a, b) => a + b, 0) / T;
|
| 367 |
+
const h1 = new Float32Array(32); linear(sin, 0, this.s0, this.s0b, h1, 0, 4 * H + 1, 32); for (let i = 0; i < 32; i++) h1[i] = Math.max(0, h1[i]);
|
| 368 |
+
const s = new Float32Array(3); linear(h1, 0, this.s2, this.s2b, s, 0, 32, 3); const m = Math.max(...s); const e = [...s].map((v) => Math.exp(v - m)); const Z = e.reduce((a, b) => a + b, 0);
|
| 369 |
+
return { pen, ps: e.map((v) => v / Z) };
|
| 370 |
+
}
|
| 371 |
+
tag(tokens) {
|
| 372 |
+
const lat = tokens.filter((t) => RE_LATIN_APOS.test(t)); const { pen } = this.run(lat); let k = 0; const th = this.x.tok_th ?? 0.5;
|
| 373 |
+
return tokens.map((t) => (RE_DEVA.test(t) ? "DEV" : RE_LATIN_APOS.test(t) ? (pen[k++] >= th ? "EN" : "HI") : "OTHER"));
|
| 374 |
+
}
|
| 375 |
+
mode(tokens) {
|
| 376 |
+
const nd = tokens.filter((t) => RE_DEVA.test(t)).length, nl = tokens.filter((t) => RE_LATIN_APOS.test(t)).length;
|
| 377 |
+
if (nd && !nl) return "devanagari";
|
| 378 |
+
if (nd && nl) return nd / (nd + nl) >= (this.x.dev_frac ?? 0.5) ? "devanagari" : "mixed_script";
|
| 379 |
+
if (!nl) return "english";
|
| 380 |
+
const { ps } = this.run(tokens.filter((t) => RE_LATIN_APOS.test(t))); const bias = this.x.mode_bias || [0, 0, 0];
|
| 381 |
+
let best = 0, bv = -Infinity; ps.forEach((p, i) => { const v = Math.log(p + 1e-9) + bias[i]; if (v > bv) { bv = v; best = i; } });
|
| 382 |
+
return MODES3[best];
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
// ------------------------------------------------------------------ tokenizer + policy tables
|
| 387 |
+
export const TOKEN_RE = /(https?:\/\/\S+|www\.\S+|[\p{L}\p{N}_.+-]+@[\p{L}\p{N}_-]+\.[\p{L}\p{N}_.]+|[@#][\p{L}\p{N}_]+|[A-Za-z]+(?:'[A-Za-z]+)?|[\u0900-\u0963\u0971-\u097F]+|[0-9\u0966-\u096F]+(?:[.,:][0-9\u0966-\u096F]+)*|[\u0964\u0965]|[^\sA-Za-z0-9\u0900-\u097F])/gu;
|
| 388 |
+
const RE_LATIN = /^[A-Za-z]+$/;
|
| 389 |
+
const RE_ACRO = /^[b-df-hj-np-tv-z]{2,7}$/;
|
| 390 |
+
const LETTER = Object.fromEntries([..."abcdefghijklmnopqrstuvwxyz"].map((c, i) => [c, ("\u090f \u092c\u0940 \u0938\u0940 \u0921\u0940 \u0908 \u090f\u092b \u091c\u0940 \u090f\u091a \u0906\u0908 \u091c\u0947 \u0915\u0947 \u090f\u0932 \u090f\u092e \u090f\u0928 " +
|
| 391 |
+
"\u0913 \u092a\u0940 \u0915\u094d\u092f\u0942 \u0906\u0930 \u090f\u0938 \u091f\u0940 \u092f\u0942 \u0935\u0940 \u0921\u092c\u094d\u0932\u094d\u092f\u0942 \u090f\u0915\u094d\u0938 \u0935\u093e\u0908 \u091c\u0947\u0921").split(" ")[i]]));
|
| 392 |
+
// Hinglish policy letter names (bhc/hinglish baseline): f -> एफ़, z -> ज़ेड
|
| 393 |
+
const LETTERS_H = { ...LETTER, f: "\u090f\u092b\u093c", z: "\u091c\u093c\u0947\u0921" };
|
| 394 |
+
const VAR_SWAPS = [["\u0949", "\u094b"], ["\u094b", "\u0949"], ["\u093e", "\u0949"], ["\u0949", "\u093e"], ["\u0903", ""], ["\u092b\u093c", "\u092b"], ["\u092b", "\u092b\u093c"],
|
| 395 |
+
["\u091c\u093c", "\u091c"], ["\u091c", "\u091c\u093c"], ["\u0901", "\u0902"], ["\u0902", "\u0901"]];
|
| 396 |
+
export const FEATS = ["sc", "scn", "inlex", "uni", "free0", "infree", "incon", "aw", "visarga", "nukta", "chandra", "acro", "variant", "frank",
|
| 397 |
+
"skel", "skmatch", "lev", "sc_rel", "scn_rel", "uni_rel", "lenr", "visr", "hfin", "acro_nv"];
|
| 398 |
+
const BRANDS = new Set(`whatsapp google meet paytm amazon flipkart youtube instagram facebook gmail excel uber ola swiggy zomato
|
| 399 |
+
netflix linkedin github python java jira slack zoom iphone android windows microsoft apple samsung twitter telegram
|
| 400 |
+
chrome firefox safari office365 outlook teams spotify hotstar jio airtel phonepe gpay`.split(/\s+/));
|
| 401 |
+
const KEEP_RE = /^(https?:\/\/|www\.|[@#])|@.+\.|_|\d.*[A-Za-z]|[A-Za-z].*\d|^[a-z]+[A-Z]/;
|
| 402 |
+
const isUpper = (t) => /[A-Z]/.test(t) && t === t.toUpperCase();
|
| 403 |
+
const DEFAULTS = { beam: 8, nbest: 8, cbeam: 8, variants: true, acro: true, w: null, mu: null, sd: null, w_lm: 0.8, oov_pen_s: 4.0, w_ch_s: 1.0, use_lm: true,
|
| 404 |
+
skel: false, skel_k: 200, skel_m: 16, skel_wu: 0.03, visr: false, acro_v: false };
|
| 405 |
+
const parseTSV = (txt) => { const m = new Map(); for (const l of txt.split("\n")) { const i = l.indexOf("\t"); if (i > 0) m.set(l.slice(0, i).trim(), l.slice(i + 1).trim()); } return m; };
|
| 406 |
+
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
| 407 |
+
|
| 408 |
+
async function fetchBytes(base, name, fetchImpl) {
|
| 409 |
+
const url = base.endsWith("/") ? base + name : base + "/" + name;
|
| 410 |
+
const r = await fetchImpl(url); if (!r.ok) throw new Error(`fetch ${url}: ${r.status}`);
|
| 411 |
+
if (name.endsWith(".gz") && typeof DecompressionStream !== "undefined") return new Uint8Array(await new Response(r.body.pipeThrough(new DecompressionStream("gzip"))).arrayBuffer());
|
| 412 |
+
return new Uint8Array(await r.arrayBuffer());
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
// ------------------------------------------------------------------ consonant-skeleton index (bhc/skel.py; tables generated from it)
|
| 416 |
+
const SK_DEV = {"\u0915": "K", "\u0916": "K", "\u0917": "G", "\u0918": "G", "\u091a": "C", "\u091b": "C", "\u091c": "J", "\u091d": "J", "\u091f": "T", "\u0920": "T", "\u0924": "T", "\u0925": "T", "\u0921": "D", "\u0922": "D", "\u0926": "D", "\u0927": "D", "\u0919": "N", "\u091e": "N", "\u0923": "N", "\u0928": "N", "\u0929": "N", "\u092e": "N", "\u0902": "N", "\u0901": "N", "\u092a": "P", "\u092b": "P", "\u092c": "B", "\u092d": "B", "\u0930": "R", "\u0931": "R", "\u090b": "R", "\u0943": "R", "\u0932": "L", "\u0933": "L", "\u0935": "V", "\u0936": "S", "\u0937": "S", "\u0938": "S", "\u0939": "H", "\u0903": "H"};
|
| 417 |
+
const SK_ROM1 = {"k": "K", "q": "K", "g": "G", "j": "J", "z": "J", "t": "T", "d": "D", "n": "N", "m": "N", "p": "P", "f": "P", "b": "B", "r": "R", "l": "L", "v": "V", "w": "V", "s": "S", "h": "H"};
|
| 418 |
+
const SK_ASP = "bcdgjkpstz";
|
| 419 |
+
const DR_C = {"\u0915": "k", "\u0916": "kh", "\u0917": "g", "\u0918": "gh", "\u0919": "n", "\u091a": "ch", "\u091b": "chh", "\u091c": "j", "\u091d": "jh", "\u091e": "n", "\u091f": "t", "\u0920": "th", "\u0921": "d", "\u0922": "dh", "\u0923": "n", "\u0924": "t", "\u0925": "th", "\u0926": "d", "\u0927": "dh", "\u0928": "n", "\u092a": "p", "\u092b": "ph", "\u092c": "b", "\u092d": "bh", "\u092e": "m", "\u092f": "y", "\u0930": "r", "\u0932": "l", "\u0935": "v", "\u0936": "sh", "\u0937": "sh", "\u0938": "s", "\u0939": "h", "\u0933": "l"};
|
| 420 |
+
const DR_V = {"\u0905": "a", "\u0906": "aa", "\u0907": "i", "\u0908": "ee", "\u0909": "u", "\u090a": "oo", "\u090b": "ri", "\u090f": "e", "\u0910": "ai", "\u0913": "o", "\u0914": "au", "\u0911": "o"};
|
| 421 |
+
const DR_M = {"\u093e": "a", "\u093f": "i", "\u0940": "ee", "\u0941": "u", "\u0942": "oo", "\u0943": "ri", "\u0947": "e", "\u0948": "ai", "\u094b": "o", "\u094c": "au", "\u0949": "o", "\u0945": "e"};
|
| 422 |
+
const NUKTA_ROM = { k: "q", kh: "kh", g: "g", j: "z", ph: "f", d: "r", dh: "rh" };
|
| 423 |
+
export function devSkel(w) { let o = ""; for (const ch of w) { const c = SK_DEV[ch]; if (c && o[o.length - 1] !== c) o += c; } return o; }
|
| 424 |
+
export function romSkels(w, maxk = 4) {
|
| 425 |
+
w = w.toLowerCase(); let outs = [""]; let i = 0; const n = w.length;
|
| 426 |
+
while (i < n) {
|
| 427 |
+
const ch = w[i]; let step = 1, opts;
|
| 428 |
+
if ((ch === "t" || ch === "s") && w.startsWith("ion", i + 1)) { opts = ch === "t" ? ["SN", "TN"] : ["SN"]; step = 4; }
|
| 429 |
+
else if (ch === "c") {
|
| 430 |
+
const nx = i + 1 < n ? w[i + 1] : "";
|
| 431 |
+
if (nx === "h") { opts = ["C", "K"]; step = 2; while (i + step < n && (w[i + step] === "c" || w[i + step] === "h")) step++; }
|
| 432 |
+
else if (nx === "e" || nx === "i" || nx === "y") opts = ["S", "K"];
|
| 433 |
+
else if (nx === "k") { opts = ["K"]; step = 2; }
|
| 434 |
+
else opts = ["K", "S"];
|
| 435 |
+
} else if (ch === "x") opts = ["KS"];
|
| 436 |
+
else if (SK_ASP.includes(ch) && i + 1 < n && w[i + 1] === "h") { opts = [SK_ROM1[ch] || ""]; step = 2; while (i + step < n && w[i + step] === "h") step++; }
|
| 437 |
+
else opts = [SK_ROM1[ch] || ""];
|
| 438 |
+
const nw = [];
|
| 439 |
+
for (const o of outs) for (const q of opts) { let s = o; for (const c of q) if (!s || s[s.length - 1] !== c) s += c; nw.push(s); }
|
| 440 |
+
outs = [...new Set(nw)].slice(0, maxk); i += step;
|
| 441 |
+
}
|
| 442 |
+
return outs;
|
| 443 |
+
}
|
| 444 |
+
export function devRom(w) {
|
| 445 |
+
const out = [], a = [...w], L = a.length;
|
| 446 |
+
for (let j = 0; j < L; j++) {
|
| 447 |
+
const ch = a[j];
|
| 448 |
+
if (DR_C[ch] !== undefined) {
|
| 449 |
+
out.push(DR_C[ch]); let nx = j + 1 < L ? a[j + 1] : "";
|
| 450 |
+
if (nx === "\u093c") nx = j + 2 < L ? a[j + 2] : "";
|
| 451 |
+
if (nx && DR_M[nx] === undefined && nx !== "\u094d" && j + 1 < L - 1) out.push("a");
|
| 452 |
+
} else if (DR_V[ch] !== undefined) out.push(DR_V[ch]);
|
| 453 |
+
else if (DR_M[ch] !== undefined) out.push(DR_M[ch]);
|
| 454 |
+
else if (ch === "\u0902" || ch === "\u0901") out.push("n");
|
| 455 |
+
else if (ch === "\u0903") out.push("h");
|
| 456 |
+
else if (ch === "\u093c" && out.length) { const l = out[out.length - 1]; out[out.length - 1] = NUKTA_ROM[l] ?? l; }
|
| 457 |
+
}
|
| 458 |
+
return out.join("");
|
| 459 |
+
}
|
| 460 |
+
export function lev(a, b) {
|
| 461 |
+
if (a.length < b.length) [a, b] = [b, a];
|
| 462 |
+
let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
|
| 463 |
+
for (let i = 1; i <= a.length; i++) {
|
| 464 |
+
const cur = [i];
|
| 465 |
+
for (let j = 1; j <= b.length; j++) cur.push(Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] !== b[j - 1] ? 1 : 0)));
|
| 466 |
+
prev = cur;
|
| 467 |
+
}
|
| 468 |
+
return prev[b.length];
|
| 469 |
+
}
|
| 470 |
+
class SkelIndex {
|
| 471 |
+
constructor(lm) {
|
| 472 |
+
const b = new Map(), N = lm.words.length;
|
| 473 |
+
for (let i = 0; i < N; i++) { const k = devSkel(lm.words[i]); if (k) { let v = b.get(k); if (!v) b.set(k, (v = [])); v.push(i); } }
|
| 474 |
+
for (const v of b.values()) v.sort((x, y) => (lm.uni[y] - lm.uni[x]) || (x - y));
|
| 475 |
+
this.b = b;
|
| 476 |
+
}
|
| 477 |
+
lookup(roman, topk = 24) {
|
| 478 |
+
const seen = [], S = new Set();
|
| 479 |
+
for (const k of romSkels(roman)) { const v = this.b.get(k); if (!v) continue; for (const i of v.slice(0, topk)) if (!S.has(i)) { S.add(i); seen.push(i); } }
|
| 480 |
+
return seen;
|
| 481 |
+
}
|
| 482 |
+
}
|
| 483 |
+
const VIS_RE = /[aeiou]h$/;
|
| 484 |
+
|
| 485 |
+
// ------------------------------------------------------------------ the engine
|
| 486 |
+
export class BhashaCore {
|
| 487 |
+
/**
|
| 488 |
+
* Load a bundle (directory with manifest.json) from a URL (browser / worker) or via a custom fetch (Node: file loader).
|
| 489 |
+
* dict: true (default) = also load the dictionary pack and wait for it; false = core only (call loadDict() later).
|
| 490 |
+
* cache: Cache API cache name for the dictionary pack (browser / worker; default "aksharalp-dict"), or false.
|
| 491 |
+
*/
|
| 492 |
+
static async load(base, { fetch: fetchImpl = globalThis.fetch, onProgress, dict = true, cache = "aksharalp-dict" } = {}) {
|
| 493 |
+
const t0 = now(); const txt = (b) => new TextDecoder().decode(b);
|
| 494 |
+
let man; try { man = JSON.parse(txt(await fetchBytes(base, "manifest.json", fetchImpl))); } catch { man = { files: { model: "xlit.q4", lex: "lex.bin", lm: "lm.bin", params: "params.json", lid: "lid.int8", loan: "loan.tsv", natural: "natural_hi.tsv" } }; }
|
| 495 |
+
const F = man.files, get = async (n, opt) => { if (!n) return null; try { const b = await fetchBytes(base, n, fetchImpl); onProgress && onProgress(n); return b; } catch (e) { if (opt) return null; throw e; } };
|
| 496 |
+
const [mb, lexb, lmb, pb, lidb, loanb, natb] = await Promise.all([get(F.model), get(F.lex, true), get(F.lm, true), get(F.params, true), get(F.lid, true), get(F.loan, true), get(F.natural, true)]);
|
| 497 |
+
const e = new BhashaCore({ model: mb, lex: lexb, lm: lmb, params: pb ? JSON.parse(txt(pb)) : {}, lid: lidb, loan: loanb ? txt(loanb) : null, natural: natb ? txt(natb) : null, manifest: man });
|
| 498 |
+
e.base = base; e.fetchImpl = fetchImpl;
|
| 499 |
+
if (dict && man.packs && man.packs.dict) await e.loadDict({ onProgress, cache });
|
| 500 |
+
e.loadMs = now() - t0; return e;
|
| 501 |
+
}
|
| 502 |
+
/** Fetch (or read from cache) the dictionary pack and attach it. Returns true on success; on any failure the engine
|
| 503 |
+
* keeps working in core-only mode and the error is kept in this.dictError. */
|
| 504 |
+
async loadDict({ onProgress, cache = "aksharalp-dict" } = {}) {
|
| 505 |
+
const pk = this.manifest && this.manifest.packs && this.manifest.packs.dict; if (!pk) return false;
|
| 506 |
+
const dir = pk.dir.endsWith("/") ? pk.dir : pk.dir + "/", fetchImpl = this.fetchImpl || globalThis.fetch;
|
| 507 |
+
const useCache = cache && typeof caches !== "undefined";
|
| 508 |
+
const get = async (n) => {
|
| 509 |
+
if (!n) return null;
|
| 510 |
+
const ver = (pk.sizes && pk.sizes[n] && pk.sizes[n].sha256) || "";
|
| 511 |
+
if (useCache) {
|
| 512 |
+
try {
|
| 513 |
+
const url = new URL(dir + n, new URL(this.base.endsWith("/") ? this.base : this.base + "/", globalThis.location && globalThis.location.href)).href;
|
| 514 |
+
const c = await caches.open(cache), key = url + "?v=" + ver.slice(0, 16), hit = await c.match(key);
|
| 515 |
+
if (hit) { onProgress && onProgress(n, "cache"); return new Uint8Array(await hit.arrayBuffer()); }
|
| 516 |
+
const r = await fetchImpl(url); if (!r.ok) throw new Error(`fetch ${url}: ${r.status}`);
|
| 517 |
+
const b = new Uint8Array(await r.arrayBuffer()); try { await c.put(key, new Response(b)); } catch (_) {}
|
| 518 |
+
onProgress && onProgress(n, "network"); return b;
|
| 519 |
+
} catch (e) { if (String(e).includes("fetch ")) throw e; }
|
| 520 |
+
}
|
| 521 |
+
const b = await fetchBytes(this.base, dir + n, fetchImpl); onProgress && onProgress(n, "network"); return b;
|
| 522 |
+
};
|
| 523 |
+
try {
|
| 524 |
+
const [lexb, lmb, pb] = await Promise.all([get(pk.files.lex), get(pk.files.lm), get(pk.files.params)]);
|
| 525 |
+
this.attachDict({ lex: lexb, lm: lmb, params: pb ? JSON.parse(new TextDecoder().decode(pb)) : {} });
|
| 526 |
+
this.dictInfo = { name: pk.name || "dict", words: this.lm.N, bytes: pk.bytes, gz: pk.gz }; return true;
|
| 527 |
+
} catch (e) { this.dictError = String(e && e.message || e); return false; }
|
| 528 |
+
}
|
| 529 |
+
/** attach an already-fetched dictionary pack: {lex, lm, params} (params override the core params) */
|
| 530 |
+
attachDict({ lex, lm = null, params = {} }) {
|
| 531 |
+
this.p = { ...DEFAULTS, ...this.coreParams, ...params };
|
| 532 |
+
this._setLex(lex, lm); this.cache = new Map(); this.hasDict = this.lm.N > 0;
|
| 533 |
+
}
|
| 534 |
+
_setLex(lex, lm) {
|
| 535 |
+
this.lm = new LexLM(lex, lm && this.p.use_lm ? lm : null);
|
| 536 |
+
if (!this.lm.N) { this.p.cbeam = 0; this.p.skel = false; }
|
| 537 |
+
// the trie never contains the empty string (as in Python's LazyTrie), otherwise "" would take a constrained-beam slot
|
| 538 |
+
const sw = this.lm.sortedWords, tw = sw.length && sw[0] === "" ? sw.slice(1) : sw;
|
| 539 |
+
this.trie = this.p.cbeam ? new LazyTrie(tw) : null;
|
| 540 |
+
this.skix = this.p.skel ? new SkelIndex(this.lm) : null;
|
| 541 |
+
}
|
| 542 |
+
constructor({ model, lex = null, lm = null, params = {}, lid = null, loan = null, natural = null, manifest = null }) {
|
| 543 |
+
this.coreParams = params; this.p = { ...DEFAULTS, ...params }; this.manifest = manifest;
|
| 544 |
+
this.model = new XlitModel(parseWeights(model));
|
| 545 |
+
this._setLex(lex, lm); this.hasDict = this.lm.N > 0; this.dictInfo = null; this.dictError = null;
|
| 546 |
+
this.lid = lid ? new LID(parseWeights(lid)) : null;
|
| 547 |
+
this.loan = loan ? parseTSV(loan) : new Map();
|
| 548 |
+
this.natural = natural ? parseTSV(natural) : new Map();
|
| 549 |
+
this.cache = new Map();
|
| 550 |
+
}
|
| 551 |
+
info() {
|
| 552 |
+
const s = this.manifest && this.manifest.sizes ? this.manifest.sizes : {};
|
| 553 |
+
const used = Object.values(this.manifest ? this.manifest.files : {}).filter((f) => f && s[f]);
|
| 554 |
+
return { params: this.model.nParams + (this.lid ? this.lid.nParams : 0), xlitParams: this.model.nParams, lidParams: this.lid ? this.lid.nParams : 0,
|
| 555 |
+
lexWords: this.lm.N, bytes: used.reduce((a, f) => a + s[f].bytes, 0), gz: used.reduce((a, f) => a + s[f].gz, 0), hasLID: !!this.lid, hasLM: this.lm.hasLM,
|
| 556 |
+
hasDict: this.hasDict, dict: this.dictInfo, dictError: this.dictError, hasLoan: this.loan.size > 0, hasNatural: this.natural.size > 0 };
|
| 557 |
+
}
|
| 558 |
+
|
| 559 |
+
/** candidate rows with reranker features for one (lower-cased) Latin word: [[devanagari, fv, wid], ...] */
|
| 560 |
+
candFeats(word) {
|
| 561 |
+
const w = word.toLowerCase(); const hit = this.cache.get(w); if (hit) return hit;
|
| 562 |
+
const p = this.p, m = this.model, ids = encSrc(w), enc = m.encode(ids), S = ids.length;
|
| 563 |
+
const free = m.beam(enc, S, { beam: p.beam, nbest: p.nbest });
|
| 564 |
+
const con = p.cbeam && this.trie ? m.beam(enc, S, { beam: p.beam, nbest: p.nbest, trie: this.trie }) : [];
|
| 565 |
+
const d = new Map();
|
| 566 |
+
free.forEach(([s, sc], i) => { if (s) d.set(s, { sc, infree: 1, frank: i, free0: +(i === 0), beamEntry: 1 }); });
|
| 567 |
+
for (const [s, sc] of con) if (s) { if (!d.has(s)) d.set(s, { sc, infree: 0, frank: p.nbest, free0: 0, beamEntry: 1 }); d.get(s).incon = 1; }
|
| 568 |
+
if (p.variants) {
|
| 569 |
+
const top = [...d.keys()].sort((a, b) => d.get(b).sc - d.get(a).sc).slice(0, 4);
|
| 570 |
+
for (const s of top) for (const [a, b] of VAR_SWAPS) if (s.includes(a)) {
|
| 571 |
+
const v = s.split(a).join(b); if (!d.has(v) && this.lm.id(v) !== null) d.set(v, { sc: m.scorePair(enc, v), infree: 0, frank: p.nbest, free0: 0, variant: 1 });
|
| 572 |
+
}
|
| 573 |
+
}
|
| 574 |
+
if (p.acro && (RE_ACRO.test(w) || (p.acro_v && w.length >= 2 && w.length <= 4))) {
|
| 575 |
+
const v = [...w].map((c) => LETTER[c]).join("");
|
| 576 |
+
if (!d.has(v)) d.set(v, { sc: m.scorePair(enc, v), infree: 0, frank: p.nbest, free0: 0, acro: 1 }); else d.get(v).acro = 1;
|
| 577 |
+
}
|
| 578 |
+
if (p.visr && VIS_RE.test(w)) { // Aksharantar convention: literal word-final h -> visarga
|
| 579 |
+
const top = [...d.keys()].filter((x) => d.get(x).beamEntry).sort((x, y) => d.get(y).sc - d.get(x).sc).slice(0, 2);
|
| 580 |
+
for (const s of top) {
|
| 581 |
+
const v = s.endsWith("\u0939") ? s.slice(0, -1) + "\u0903" : (!s.endsWith("\u0903") ? s + "\u0903" : null);
|
| 582 |
+
if (v && !d.has(v)) d.set(v, { sc: m.scorePair(enc, v), infree: 0, frank: p.nbest, free0: 0, visr: 1 });
|
| 583 |
+
}
|
| 584 |
+
}
|
| 585 |
+
if (this.skix) {
|
| 586 |
+
const L = w.length + 1, words = this.lm.words, uni = this.lm.uni;
|
| 587 |
+
const ids = this.skix.lookup(w, p.skel_k).map((i) => [i, lev(w, devRom(words[i])) / L - p.skel_wu * uni[i]])
|
| 588 |
+
.sort((x, y) => x[1] - y[1]).slice(0, p.skel_m);
|
| 589 |
+
for (const [i] of ids) { const v = words[i]; if (!d.has(v)) d.set(v, { sc: m.scorePair(enc, v), infree: 0, frank: p.nbest, free0: 0, skel: 1 }); else d.get(v).skel = 1; }
|
| 590 |
+
}
|
| 591 |
+
const rows = [], sks = new Set(romSkels(w)), Lw = w.length + 1, vis = VIS_RE.test(w), novow = !/[aeiou]/.test(w);
|
| 592 |
+
for (const [s, e] of d) {
|
| 593 |
+
const wid = this.lm.id(s), L = [...s].length;
|
| 594 |
+
rows.push([s, [e.sc, e.sc / (L + 1), +(wid !== null), wid !== null ? this.lm.unigram(wid) : 0, e.free0 || 0, e.infree || 0, e.incon || 0,
|
| 595 |
+
+(s.includes("\u0949") || s.includes("\u0911")), +s.includes("\u0903"), +s.includes("\u093c"), +s.includes("\u0901"), e.acro || 0, e.variant || 0, (e.frank ?? p.nbest) / p.nbest,
|
| 596 |
+
e.skel || 0, +sks.has(devSkel(s)), lev(w, devRom(s)) / Lw, 0, 0, 0, L / Lw, e.visr || 0, +(vis && s.endsWith("\u0903")), +(!!e.acro && novow)], wid]);
|
| 597 |
+
}
|
| 598 |
+
if (rows.length) {
|
| 599 |
+
let msc = -Infinity, mscn = -Infinity, mu = null;
|
| 600 |
+
for (const [, fv] of rows) { msc = Math.max(msc, fv[0]); mscn = Math.max(mscn, fv[1]); if (fv[2]) mu = mu === null ? fv[3] : Math.max(mu, fv[3]); }
|
| 601 |
+
for (const [, fv] of rows) { fv[17] = fv[0] - msc; fv[18] = fv[1] - mscn; fv[19] = fv[2] ? fv[3] - (mu ?? 0) : 0; }
|
| 602 |
+
}
|
| 603 |
+
if (this.cache.size > 20000) this.cache.clear();
|
| 604 |
+
this.cache.set(w, rows); return rows;
|
| 605 |
+
}
|
| 606 |
+
score(fv) {
|
| 607 |
+
const p = this.p; if (!p.w && !p.w1) return fv[0] + 0.2 * (fv[2] ? fv[3] : -25.0);
|
| 608 |
+
const n = p.mu.length, z = new Array(n); for (let i = 0; i < n; i++) z[i] = (fv[i] - p.mu[i]) / p.sd[i];
|
| 609 |
+
if (p.w1) { // 1-hidden-layer tanh MLP reranker (fit on VALID only)
|
| 610 |
+
let s = p.b2 || 0;
|
| 611 |
+
for (let h = 0; h < p.w1.length; h++) { const r = p.w1[h]; let a = p.b1[h]; for (let i = 0; i < n; i++) a += r[i] * z[i]; s += p.w2[h] * Math.tanh(a); }
|
| 612 |
+
return s;
|
| 613 |
+
}
|
| 614 |
+
let s = 0; for (let i = 0; i < Math.min(n, p.w.length); i++) s += p.w[i] * z[i]; return s;
|
| 615 |
+
}
|
| 616 |
+
/** word mode: top-k Devanagari candidates for a romanized word */
|
| 617 |
+
word(w, k = 8) {
|
| 618 |
+
if (!RE_LATIN.test(w)) return [{ text: w, score: 0 }];
|
| 619 |
+
const rows = this.candFeats(w).map(([s, fv]) => ({ text: s, score: this.score(fv) }));
|
| 620 |
+
return rows.sort((a, b) => b.score - a.score).slice(0, k);
|
| 621 |
+
}
|
| 622 |
+
/** sentence Viterbi over candidate lattices with the bigram LM (bhc/translit2.py decode_slots) */
|
| 623 |
+
decodeSlots(slots, context = true) {
|
| 624 |
+
const p = this.p, lm = this.lm, lat = [];
|
| 625 |
+
for (const [kind, t] of slots) {
|
| 626 |
+
if (kind === "x") {
|
| 627 |
+
let sc = this.candFeats(t).map(([s, fv, wid]) => [s, this.score(fv), wid]);
|
| 628 |
+
if (sc.length) {
|
| 629 |
+
const mx = Math.max(...sc.map((x) => x[1])), lse = mx + Math.log(sc.reduce((a, x) => a + Math.exp(x[1] - mx), 0));
|
| 630 |
+
sc = sc.map(([s, v, wid]) => [s, p.w_ch_s * (v - lse), wid]).sort((a, b) => b[1] - a[1]).slice(0, 12);
|
| 631 |
+
}
|
| 632 |
+
lat.push(sc.length ? sc : [[t, 0, null]]);
|
| 633 |
+
} else {
|
| 634 |
+
const wid = RE_DEVA.test(t) ? lm.id(t) ?? -1 : -2; lat.push([[t, 0, wid]]);
|
| 635 |
+
}
|
| 636 |
+
}
|
| 637 |
+
const post = lat.map((o) => o.map(([s, v]) => [s, v])); // per-slot candidate list (for UI chips)
|
| 638 |
+
if (!context || !p.use_lm || !lm.hasLM) return { out: lat.map((o) => o.reduce((a, b) => (b[1] > a[1] ? b : a))[0]), lat: post };
|
| 639 |
+
let beams = [[0, null, []]];
|
| 640 |
+
for (const opts of lat) {
|
| 641 |
+
if (opts[0][2] === -2 && opts.length === 1) { beams = beams.map(([s, h, ch]) => [s, h, ch.concat([opts[0][0]])]); continue; }
|
| 642 |
+
const best = new Map();
|
| 643 |
+
for (const [s, h, ch] of beams) for (const [cand, csc, wid] of opts) {
|
| 644 |
+
const w = wid === null || wid === -1 ? null : wid;
|
| 645 |
+
const tot = s + csc + p.w_lm * (lm.logp(h, w) - (w === null ? p.oov_pen_s : 0));
|
| 646 |
+
if (!best.has(cand) || tot > best.get(cand)[0]) best.set(cand, [tot, w, ch.concat([cand])]);
|
| 647 |
+
}
|
| 648 |
+
beams = [...best.values()].sort((a, b) => b[0] - a[0]).slice(0, 16);
|
| 649 |
+
}
|
| 650 |
+
let bb = null, bv = -Infinity;
|
| 651 |
+
for (const b of beams) { const v = b[0] + p.w_lm * lm.logp(b[1], lm.N); if (v > bv) { bv = v; bb = b; } }
|
| 652 |
+
return { out: bb[2], lat: post };
|
| 653 |
+
}
|
| 654 |
+
/** plain Track-B sentence conversion (bhc/translit2.py convert) */
|
| 655 |
+
convertPlain(text) {
|
| 656 |
+
const spans = [...text.matchAll(TOKEN_RE)].map((m) => [m.index, m.index + m[0].length, m[0]]);
|
| 657 |
+
const { out } = this.decodeSlots(spans.map(([, , t]) => (RE_LATIN.test(t) ? ["x", t] : ["fix", t])));
|
| 658 |
+
if (out.length && out[out.length - 1] === ".") out[out.length - 1] = "\u0964";
|
| 659 |
+
let s = "", pos = 0; spans.forEach(([a, b], i) => { s += text.slice(pos, a) + out[i]; pos = b; }); return s + text.slice(pos);
|
| 660 |
+
}
|
| 661 |
+
|
| 662 |
+
/**
|
| 663 |
+
* Full pipeline: tokenise -> language ID -> policy (keep / acronym / loanword / glossary) -> contextual decoding.
|
| 664 |
+
* @param {string} text
|
| 665 |
+
* @param {{mode?: 'conversational'|'natural'|'strict', k?: number, context?: boolean, overrides?: Object<number,string>}} opt
|
| 666 |
+
* context: false = word-by-word (no sentence LM)
|
| 667 |
+
* overrides: {tokenStartOffset: chosenDevanagari} pins a user-picked suggestion (re-decodes the rest in context)
|
| 668 |
+
* @returns {{output: string, tokens: Array<{text,start,end,output,lang,source,candidates:Array<{text,score}>}>, sentence: string|null, ms: number}}
|
| 669 |
+
*/
|
| 670 |
+
transliterate(text, { mode = "conversational", k = 5, overrides = {}, context = true } = {}) {
|
| 671 |
+
const t0 = now(); const policy = mode === "strict" ? "strict" : "conversational";
|
| 672 |
+
const spans = [...text.matchAll(TOKEN_RE)].map((m) => [m.index, m.index + m[0].length, m[0]]);
|
| 673 |
+
const toks = spans.map((s) => s[2]);
|
| 674 |
+
const tags = this.lid ? this.lid.tag(toks) : toks.map((t) => (RE_DEVA.test(t) ? "DEV" : RE_LATIN_APOS.test(t) ? (this.loan.has(t.toLowerCase()) ? "EN" : "HI") : "OTHER"));
|
| 675 |
+
const slots = [], src = []; let prevBrand = false;
|
| 676 |
+
for (let i = 0; i < toks.length; i++) {
|
| 677 |
+
const t = toks[i], tag = tags[i], nxt = toks[i + 1] || "", low = t.toLowerCase(), ov = overrides[spans[i][0]];
|
| 678 |
+
if (ov !== undefined) { slots.push(["fix", ov]); src.push("user"); prevBrand = false; continue; }
|
| 679 |
+
if (!RE_LATIN_APOS.test(t) || KEEP_RE.test(t) || nxt === "(") {
|
| 680 |
+
if (t === "." && (i === toks.length - 1 || /^[A-Z]/.test(toks[i + 1] || ""))) slots.push(["fix", "\u0964"]); else slots.push(["fix", t]);
|
| 681 |
+
src.push(RE_DEVA.test(t) ? "devanagari" : KEEP_RE.test(t) ? "keep" : "punct"); prevBrand = false; continue;
|
| 682 |
+
}
|
| 683 |
+
const isBrand = BRANDS.has(low) || (prevBrand && /^[A-Z]/.test(t)); prevBrand = isBrand;
|
| 684 |
+
if (policy === "strict" && isBrand) { slots.push(["fix", t]); src.push("brand"); continue; }
|
| 685 |
+
if (mode === "natural" && tag === "EN" && this.natural.has(low)) { slots.push(["fix", this.natural.get(low)]); src.push("glossary"); continue; }
|
| 686 |
+
if (isUpper(t) && t.length >= 2 && t.length <= 5 && !this.loan.has(low)) { slots.push(["fix", [...low].map((c) => LETTERS_H[c]).join("")]); src.push("acronym"); continue; }
|
| 687 |
+
if ((tag === "EN" || isBrand) && this.loan.has(low)) { slots.push(["fix", this.loan.get(low)]); src.push("loanword"); continue; }
|
| 688 |
+
slots.push(["x", t]); src.push("model");
|
| 689 |
+
}
|
| 690 |
+
const { out, lat } = this.decodeSlots(slots, context);
|
| 691 |
+
let output = "", pos = 0; spans.forEach(([a, b], i) => { output += text.slice(pos, a) + out[i]; pos = b; }); output = (output + text.slice(pos)).trim();
|
| 692 |
+
const tokens = spans.map(([a, b, t], i) => {
|
| 693 |
+
let cands = [];
|
| 694 |
+
if (slots[i][0] === "x") {
|
| 695 |
+
const mx = lat[i][0] ? lat[i][0][1] : 0;
|
| 696 |
+
cands = lat[i].slice(0, k).map(([s, v]) => ({ text: s, score: Math.exp(v - mx) }));
|
| 697 |
+
} else if (RE_LATIN_APOS.test(t) && !KEEP_RE.test(t)) {
|
| 698 |
+
cands = [{ text: out[i], score: 1 }];
|
| 699 |
+
for (const c of this.word(t, k)) if (c.text !== out[i]) cands.push({ text: c.text, score: null });
|
| 700 |
+
if (out[i] !== t) cands.push({ text: t, score: null });
|
| 701 |
+
cands = cands.slice(0, k);
|
| 702 |
+
}
|
| 703 |
+
const isW = RE_LATIN_APOS.test(t) || RE_DEVA.test(t);
|
| 704 |
+
return { text: t, start: a, end: b, output: out[i], lang: isW ? tags[i] : "OTHER", source: src[i], candidates: cands };
|
| 705 |
+
});
|
| 706 |
+
let sentence = null; if (this.lid && toks.length) try { sentence = this.lid.mode(toks); } catch { sentence = null; }
|
| 707 |
+
return { output, tokens, sentence, ms: now() - t0 };
|
| 708 |
+
}
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
/** Node helper: load a bundle from a local directory. */
|
| 712 |
+
export async function loadFromDir(dir, opts = {}) {
|
| 713 |
+
const fs = await import("node:fs/promises"), path = await import("node:path");
|
| 714 |
+
const f = async (u) => { try { const b = await fs.readFile(path.resolve(u)); return new Response(b); } catch { return new Response(null, { status: 404 }); } };
|
| 715 |
+
return BhashaCore.load(dir, { fetch: f, cache: false, ...opts });
|
| 716 |
+
}
|
| 717 |
+
export { BhashaCore as AksharaLP };
|
| 718 |
+
export default BhashaCore;
|
js/app.js
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*! AksharaLP Space UI — AksharaLP by Sourojit Dhua — https://huggingface.co/sourojitdotcom/AksharaLP-1M · Copyright 2026 Sourojit Dhua · Apache-2.0 (attribution required, see NOTICE) */
|
| 2 |
+
// runtime (aksharalp.mjs) size, stamped by the release build so the sizes shown match the model card (0 in a dev checkout)
|
| 3 |
+
const RUNTIME_BYTES = Number("51518") || 0, RUNTIME_GZ = Number("17259") || 0;
|
| 4 |
+
// All inference runs in ./worker.js; this file only renders.
|
| 5 |
+
|
| 6 |
+
/* Reference sizes of a widely used open model, measured by us (see model card for method). */
|
| 7 |
+
const REF = [
|
| 8 |
+
{ name: "IndicXlit", sub: "model weights only (fp32)", bytes: 46043828 },
|
| 9 |
+
{ name: "IndicXlit + dictionary", sub: "official package with rescoring dictionary", bytes: 46043828 + 358e6 },
|
| 10 |
+
];
|
| 11 |
+
|
| 12 |
+
const EXAMPLES = [
|
| 13 |
+
{ tag: "Everyday", text: "aap kaise ho? sab theek hai na" },
|
| 14 |
+
{ tag: "Context: main → मैं / में", text: "main theek hoon, tum ghar main ho?" },
|
| 15 |
+
{ tag: "English words, Hindi script", text: "kal subah meeting hai, office jaldi aana" },
|
| 16 |
+
{ tag: "Acronyms & brands", text: "SBI ka statement whatsapp pe bhej do" },
|
| 17 |
+
{ tag: "Strict (brands in Latin)", text: "whatsapp aur paytm dono kaam nahi kar rahe", mode: "strict" },
|
| 18 |
+
];
|
| 19 |
+
|
| 20 |
+
const FEATURES = [
|
| 21 |
+
{ ic: "◆", title: "Extremely small", body: "A sub-megabyte core that works on its own, plus an optional dictionary pack (lexicon + sentence language model) fetched once and cached.", size: true },
|
| 22 |
+
{ ic: "↹", title: "Understands context", body: "A compact bigram LM resolves ambiguous spellings from the words around them — the same “main” becomes मैं or में.", demos: ["main theek hoon", "ghar main kaun hai"] },
|
| 23 |
+
{ ic: "≋", title: "English words, phonetically", body: "English words typed inside Hindi sentences are written phonetically in Devanagari.", demos: ["meeting office mein hai", "whatsapp pe message karo"] },
|
| 24 |
+
{ ic: "Aa", title: "Acronyms & English", body: "Bank names, initialisms and English words are spelled letter-by-letter or phonetically.", demos: ["SBI ka ATM", "PNR status check karo"] },
|
| 25 |
+
{ ic: "☰", title: "Top-k suggestions", body: "Every word comes with ranked alternatives — perfect for keyboard suggestion bars.", chips: "kaise" },
|
| 26 |
+
{ ic: "◐", title: "Core first, dictionary later", body: "Typing starts as soon as the small core has loaded; the dictionary pack attaches in the background. If it cannot be fetched, the core keeps working on its own.", dict: true },
|
| 27 |
+
];
|
| 28 |
+
|
| 29 |
+
const SENT = { romanized_hindi: ["Hindi (romanized)", "var(--hi)"], english: ["English", "var(--en)"], devanagari: ["Devanagari", "var(--dev)"], mixed_script: ["Mixed script", "var(--dev)"] };
|
| 30 |
+
const SRC = { model: "model", loanword: "loanword", acronym: "acronym", brand: "kept (brand)", glossary: "natural Hindi", keep: "kept", user: "your pick", devanagari: "Devanagari input" };
|
| 31 |
+
|
| 32 |
+
const $ = (s) => document.querySelector(s);
|
| 33 |
+
const el = (tag, cls, txt) => { const e = document.createElement(tag); if (cls) e.className = cls; if (txt != null) e.textContent = txt; return e; };
|
| 34 |
+
const fmtMB = (b) => (b >= 100e6 ? Math.round(b / 1e6) + " MB" : b >= 10e6 ? (b / 1e6).toFixed(1) + " MB" : (b / 1e6).toFixed(2) + " MB");
|
| 35 |
+
const fmtParams = (n) => (n >= 1e6 ? (n / 1e6).toFixed(2) + " M" : Math.round(n / 1e3) + " K");
|
| 36 |
+
const fmtWords = (n) => (n >= 1e6 ? (n / 1e6).toFixed(1) + "M" : Math.round(n / 1e3) + "K") + " words";
|
| 37 |
+
|
| 38 |
+
/* ---------------------------------------------------------------- worker bridge */
|
| 39 |
+
const wurl = new URL("./worker.js", import.meta.url); if (new URLSearchParams(location.search).get("dict") === "0") wurl.search = "?dict=0";
|
| 40 |
+
const worker = new Worker(wurl, { type: "module" });
|
| 41 |
+
let seq = 0; const pending = new Map();
|
| 42 |
+
const call = (msg) => new Promise((res, rej) => { const id = ++seq; pending.set(id, { res, rej }); worker.postMessage({ ...msg, id }); });
|
| 43 |
+
|
| 44 |
+
const state = { dict: null, dictDone: false, mode: "conversational", ctx: true, text: "", overrides: [], res: null, sel: null, lat: [], ready: false, info: null, busy: false, again: false, prevKeys: [] };
|
| 45 |
+
const input = $("#input"), output = $("#output"), chips = $("#chips");
|
| 46 |
+
|
| 47 |
+
worker.onmessage = ({ data }) => {
|
| 48 |
+
if (data.type === "progress") $("#loader-text").textContent = "Loaded " + data.file;
|
| 49 |
+
else if (data.type === "ready") onReady(data);
|
| 50 |
+
else if (data.type === "dict") onDict(data);
|
| 51 |
+
else if (data.type === "error" && !data.id) { $("#status-text").textContent = "Model failed to load"; $("#loader-text").textContent = data.message; console.error(data.message); }
|
| 52 |
+
else if (pending.has(data.id)) { const p = pending.get(data.id); pending.delete(data.id); data.type === "error" ? p.rej(new Error(data.message)) : p.res(data); }
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
/* ---------------------------------------------------------------- live transliteration */
|
| 56 |
+
function opts() {
|
| 57 |
+
const ov = {}; for (const o of state.overrides) ov[o.start] = o.pick;
|
| 58 |
+
return { mode: state.mode, context: state.ctx, k: 6, overrides: ov };
|
| 59 |
+
}
|
| 60 |
+
async function run() {
|
| 61 |
+
if (!state.ready) return;
|
| 62 |
+
if (state.busy) { state.again = true; return; }
|
| 63 |
+
state.busy = true;
|
| 64 |
+
const text = input.value;
|
| 65 |
+
try {
|
| 66 |
+
const { res } = await call({ type: "run", text, opts: opts() });
|
| 67 |
+
if (text === input.value || !state.again) render(res, text);
|
| 68 |
+
if (text.trim()) { state.lat.push(res.ms); if (state.lat.length > 50) state.lat.shift(); updateLatency(res.ms); updateCapLatency(); }
|
| 69 |
+
} catch (e) { console.error(e); }
|
| 70 |
+
state.busy = false;
|
| 71 |
+
if (state.again) { state.again = false; run(); }
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
function shiftOverrides(oldT, newT) {
|
| 75 |
+
let p = 0; const n = Math.min(oldT.length, newT.length);
|
| 76 |
+
while (p < n && oldT[p] === newT[p]) p++;
|
| 77 |
+
let s = 0; while (s < n - p && oldT[oldT.length - 1 - s] === newT[newT.length - 1 - s]) s++;
|
| 78 |
+
const oEnd = oldT.length - s, d = newT.length - oldT.length;
|
| 79 |
+
state.overrides = state.overrides.flatMap((o) => (o.end < p ? [o] : o.start > oEnd ? [{ ...o, start: o.start + d, end: o.end + d }] : []));
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
function render(res, text) {
|
| 83 |
+
state.res = res;
|
| 84 |
+
const out = output; out.textContent = "";
|
| 85 |
+
$("#copy").disabled = !res.output;
|
| 86 |
+
if (!res.tokens.length) { out.append(el("span", "ph", "आपका देवनागरी पाठ यहाँ दिखेगा")); state.prevKeys = []; renderChips(); setSentence(null); return; }
|
| 87 |
+
let pos = 0; const keys = []; let prevW = null; const tags = false;
|
| 88 |
+
res.tokens.forEach((t, i) => {
|
| 89 |
+
const gap = text.slice(pos, t.start);
|
| 90 |
+
const key = t.text + "|" + t.output; keys.push(key);
|
| 91 |
+
const isNew = state.prevKeys[i] !== key;
|
| 92 |
+
if (t.lang === "OTHER" && !t.candidates.length) {
|
| 93 |
+
// punctuation: glue to the previous word so it never wraps onto its own line
|
| 94 |
+
if (prevW && !gap) { prevW.querySelector(".row").append(el("span", "pn", t.output)); pos = t.end; return; }
|
| 95 |
+
if (gap) out.append(document.createTextNode(gap)); out.append(el("span", "pn", t.output)); pos = t.end; prevW = null; return;
|
| 96 |
+
}
|
| 97 |
+
if (gap) out.append(document.createTextNode(gap));
|
| 98 |
+
pos = t.end;
|
| 99 |
+
const w = el("span", `w lang-${t.lang}` + (isNew ? " new" : "") + (t.source === "user" ? " pinned" : "") + (state.sel === t.start ? " sel" : ""));
|
| 100 |
+
const row = el("span", "row"); row.append(el("span", "wt", t.output)); w.append(row);
|
| 101 |
+
w.dataset.start = t.start; w.title = `${t.text} · ${SRC[t.source] || t.source}`;
|
| 102 |
+
if (tags) w.append(el("span", "tg tg-" + t.lang, t.lang));
|
| 103 |
+
w.addEventListener("click", () => { state.sel = t.start; render(state.res, input.value); });
|
| 104 |
+
out.append(w); prevW = w;
|
| 105 |
+
});
|
| 106 |
+
if (pos < text.length) out.append(document.createTextNode(text.slice(pos)));
|
| 107 |
+
state.prevKeys = keys;
|
| 108 |
+
renderChips();
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
function activeToken() {
|
| 112 |
+
const r = state.res; if (!r || !r.tokens.length) return null;
|
| 113 |
+
const words = r.tokens.filter((t) => t.candidates.length);
|
| 114 |
+
if (state.sel != null) { const t = words.find((x) => x.start === state.sel); if (t) return t; }
|
| 115 |
+
const c = input.selectionStart ?? input.value.length;
|
| 116 |
+
return words.find((t) => t.start <= c && c <= t.end) || [...words].reverse().find((t) => t.end <= c) || words[words.length - 1] || null;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
function renderChips() {
|
| 120 |
+
const t = activeToken(); chips.textContent = "";
|
| 121 |
+
if (!t) { chips.append(el("span", "hint", "Click any word in the output — or just keep typing — to see ranked alternatives.")); return; }
|
| 122 |
+
const src = el("span", "src", t.text + " →"); chips.append(src);
|
| 123 |
+
const pinned = state.overrides.find((o) => o.start === t.start);
|
| 124 |
+
t.candidates.forEach((c, i) => {
|
| 125 |
+
const latin = /^[A-Za-z']+$/.test(c.text);
|
| 126 |
+
const b = el("button", "chip" + (c.text === t.output ? " on" : "") + (latin ? " latin" : ""), c.text);
|
| 127 |
+
b.style.animationDelay = i * 35 + "ms";
|
| 128 |
+
if (c.score != null) { const p = el("span", "p"); p.style.width = Math.max(6, Math.round(c.score * 100)) + "%"; b.append(p); }
|
| 129 |
+
b.title = c.score != null ? `relative probability ${(c.score * 100).toFixed(0)}%` : "alternative";
|
| 130 |
+
b.addEventListener("click", () => pick(t, c.text));
|
| 131 |
+
chips.append(b);
|
| 132 |
+
});
|
| 133 |
+
if (pinned) { const r = el("button", "ghost-btn reset", "↺ Auto"); r.addEventListener("click", () => { state.overrides = state.overrides.filter((o) => o !== pinned); run(); }); chips.append(r); }
|
| 134 |
+
const meta = el("span", "meta", SRC[t.source] || t.source); chips.append(meta);
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
function pick(t, text) {
|
| 138 |
+
state.overrides = state.overrides.filter((o) => o.start !== t.start);
|
| 139 |
+
state.overrides.push({ start: t.start, end: t.end, word: t.text, pick: text });
|
| 140 |
+
state.sel = t.start; run();
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
function setSentence(s) {
|
| 144 |
+
const b = $("#sent-lang");
|
| 145 |
+
if (!s || !SENT[s]) { b.hidden = true; return; }
|
| 146 |
+
const [label, c] = SENT[s]; if (b.textContent !== label) { b.hidden = false; b.textContent = label; b.style.setProperty("--c", c); b.style.animation = "none"; void b.offsetWidth; b.style.animation = ""; }
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
function updateLatency(ms) {
|
| 150 |
+
const a = [...state.lat].sort((x, y) => x - y), p50 = a[Math.floor(a.length / 2)];
|
| 151 |
+
$("#m-lat").innerHTML = `${ms < 10 ? ms.toFixed(1) : Math.round(ms)}<small>ms</small> <small>p50 ${p50 < 10 ? p50.toFixed(1) : Math.round(p50)}</small>`;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
/* ---------------------------------------------------------------- ready: stats, gallery, features */
|
| 155 |
+
function showSizes(info) {
|
| 156 |
+
const sz = (state.dictDone && info.dict ? info.gz + info.dict.gz : info.gz || info.bytes) + RUNTIME_GZ;
|
| 157 |
+
$("#hero-size").textContent = fmtMB(sz);
|
| 158 |
+
const short = (sz / 1e6).toFixed(1) + " MB"; $("#hero-size-short").textContent = short; $("#stat-size").textContent = short;
|
| 159 |
+
$("#m-size").innerHTML = `${fmtMB(sz).replace(" MB", "<small>MB</small>")}`;
|
| 160 |
+
$("#m-params").innerHTML = fmtParams(info.params).replace(" M", "<small>M</small>").replace(" K", "<small>K</small>");
|
| 161 |
+
}
|
| 162 |
+
function setDictStatus(txt, cls) { const d = $("#m-lex"); d.textContent = txt; d.className = "v dict-" + cls; }
|
| 163 |
+
async function onReady({ info, loadMs, name }) {
|
| 164 |
+
if (name && /^AksharaLP/.test(name)) $(".brand-tag").textContent = name.replace(/^AksharaLP-?/, "") + " · Hindi";
|
| 165 |
+
state.ready = true; state.info = info;
|
| 166 |
+
$("#status").classList.add("ready"); $("#status-text").textContent = "Core running on-device";
|
| 167 |
+
$("#loader-text").textContent = "Core ready — fetching the dictionary pack…";
|
| 168 |
+
input.disabled = false; $("#copy").disabled = true;
|
| 169 |
+
showSizes(info); setDictStatus("loading…", "loading");
|
| 170 |
+
$("#m-lat").innerHTML = `${Math.round(loadMs)}<small>ms load</small>`;
|
| 171 |
+
renderSizes(info);
|
| 172 |
+
if (input.value) run();
|
| 173 |
+
}
|
| 174 |
+
async function onDict({ ok, info, from, error, skipped }) {
|
| 175 |
+
state.info = info; state.dictDone = true; state.dict = ok ? info.dict : null;
|
| 176 |
+
$("#loader").classList.add("gone");
|
| 177 |
+
if (ok) { setDictStatus(fmtWords(info.dict.words) + (from === "cache" ? " · cached" : ""), "ok"); $("#status-text").textContent = "Running on-device"; }
|
| 178 |
+
else { setDictStatus("core only", "off"); $("#status-text").textContent = "Core only (no dictionary)"; if (error) console.warn("dictionary pack not loaded:", error); }
|
| 179 |
+
showSizes(info); renderSizes(info);
|
| 180 |
+
await fillExamples(); await fillCaps(); await fillFeatures();
|
| 181 |
+
if ("serviceWorker" in navigator && location.protocol !== "file:" && !navigator.webdriver) navigator.serviceWorker.register("./sw.js").then(() => { $("#status-text").textContent = (ok ? "On-device" : "Core only") + " · works offline"; }).catch(() => {});
|
| 182 |
+
if (input.value) run();
|
| 183 |
+
document.dispatchEvent(new CustomEvent("bhc-ready"));
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
async function batch(items) { const { out } = await call({ type: "batch", items }); return out; }
|
| 187 |
+
|
| 188 |
+
function buildExamples() {
|
| 189 |
+
const g = $("#examples");
|
| 190 |
+
EXAMPLES.forEach((ex, i) => {
|
| 191 |
+
const b = el("button", "ex"); b.append(el("span", "tag", ex.tag), el("span", "ro", ex.text));
|
| 192 |
+
const dv = el("span", "dv"); dv.append(el("span", "shimmer")); b.append(dv); b.dataset.i = i;
|
| 193 |
+
b.addEventListener("click", () => typeIn(ex));
|
| 194 |
+
g.append(b);
|
| 195 |
+
});
|
| 196 |
+
}
|
| 197 |
+
async function fillExamples() {
|
| 198 |
+
const out = await batch(EXAMPLES.map((e) => ({ text: e.text, opts: { mode: e.mode || "conversational" } })));
|
| 199 |
+
document.querySelectorAll(".ex .dv").forEach((d, i) => { d.textContent = out[i].output; d.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 500 }); });
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
function buildFeatures() {
|
| 203 |
+
const g = $("#features");
|
| 204 |
+
FEATURES.forEach((f) => {
|
| 205 |
+
const c = el("div", "feat"); c.append(el("div", "ic", f.ic), el("h3", "", f.title), el("p", "", f.body));
|
| 206 |
+
const slot = el("div", "fslot"); slot.append(el("div", "demo-line", "")); slot.firstChild.append(el("span", "shimmer"));
|
| 207 |
+
c.append(slot); g.append(c); f.slot = slot;
|
| 208 |
+
});
|
| 209 |
+
}
|
| 210 |
+
async function fillFeatures() {
|
| 211 |
+
for (const f of FEATURES) {
|
| 212 |
+
const s = f.slot; s.textContent = "";
|
| 213 |
+
if (f.size) {
|
| 214 |
+
const d = el("div", "demo-line big");
|
| 215 |
+
d.append(el("span", "d grad", fmtMB(state.info.gz)), el("span", "r", `core · ${fmtParams(state.info.params)} parameters`)); s.append(d);
|
| 216 |
+
if (state.info.dict) { const e = el("div", "demo-line"); e.append(el("span", "d", "+ " + fmtMB(state.info.dict.gz)), el("span", "r", `dictionary pack · ${fmtWords(state.info.dict.words)}`)); s.append(e); }
|
| 217 |
+
} else if (f.demos) {
|
| 218 |
+
const out = await batch(f.demos.map((t) => ({ text: t, opts: { mode: "conversational" } })));
|
| 219 |
+
f.demos.forEach((t, i) => { const d = el("div", "demo-line"); d.append(el("span", "r", t), el("span", "arrow", "→"), el("span", "d", out[i].output)); s.append(d); });
|
| 220 |
+
} else if (f.chips) {
|
| 221 |
+
const [r] = await batch([{ text: f.chips, opts: { k: 5 } }]);
|
| 222 |
+
const d = el("div", "demo-line"); d.append(el("span", "r", f.chips + " →"));
|
| 223 |
+
r.tokens[0].candidates.forEach((c, i) => d.append(el("span", "mini-chip" + (i === 0 ? " on" : ""), c.text))); s.append(d);
|
| 224 |
+
} else if (f.dict) {
|
| 225 |
+
const d = el("div", "demo-line"); const st = state.dict ? `Dictionary attached · ${fmtWords(state.dict.words)}` : "Dictionary not loaded · running core-only";
|
| 226 |
+
d.append(el("span", "r", st)); s.append(d);
|
| 227 |
+
}
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
function renderSizes(info) {
|
| 232 |
+
const box = $("#sizes"); box.textContent = "";
|
| 233 |
+
const core = info.bytes + RUNTIME_BYTES, ours = core + (info.dict ? info.dict.bytes : 0);
|
| 234 |
+
const rows = [{ name: "AksharaLP core", sub: "model + reranker + runtime, works on its own", bytes: core, us: true }];
|
| 235 |
+
if (info.dict) rows.push({ name: "AksharaLP core + dictionary", sub: `adds the ${fmtWords(info.dict.words)} lexicon and sentence LM`, bytes: ours, us: true });
|
| 236 |
+
rows.push(...REF);
|
| 237 |
+
const max = Math.max(...rows.map((r) => r.bytes));
|
| 238 |
+
rows.forEach((r) => {
|
| 239 |
+
const row = el("div", "srow" + (r.us ? " us" : "")); const nm = el("div", "nm", r.name); nm.append(el("small", "", r.sub));
|
| 240 |
+
const bar = el("div", "sbar"); const sp = el("span"); bar.append(sp);
|
| 241 |
+
row.append(nm, bar, el("div", "val", fmtMB(r.bytes))); box.append(row);
|
| 242 |
+
requestAnimationFrame(() => requestAnimationFrame(() => { sp.style.width = (100 * Math.sqrt(r.bytes / max)).toFixed(2) + "%"; }));
|
| 243 |
+
});
|
| 244 |
+
const x = Math.round(REF[0].bytes / ours);
|
| 245 |
+
box.append(el("div", "note", `Uncompressed on-disk sizes. AksharaLP is ~${x}× smaller than IndicXlit’s model weights alone. Bars use a square-root scale so the smallest bar stays visible.`));
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
/* On-device capabilities. Every Devanagari string shown in these cards is computed live by the worker. */
|
| 250 |
+
const IC = {
|
| 251 |
+
offline: '<path class="f" d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5z"/>',
|
| 252 |
+
private: '<rect x="5" y="11" width="14" height="10" rx="2.5"/><path d="M8 11V7.5a4 4 0 0 1 8 0V11M12 15v2.5"/>',
|
| 253 |
+
anywhere: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.6 2.6 3.8 5.6 3.8 9s-1.2 6.4-3.8 9M12 3C9.4 5.6 8.2 8.6 8.2 12s1.2 6.4 3.8 9"/>',
|
| 254 |
+
realtime: '<path class="f" d="M13 2 4.5 13.5H11L10 22l8.5-11.5H12z"/>',
|
| 255 |
+
ime: '<rect x="2.5" y="6" width="19" height="12" rx="2.5"/><path d="M6.5 10h.01M10 10h.01M13.5 10h.01M17 10h.01M7.5 14h9"/>',
|
| 256 |
+
brands: '<path d="M20.5 12a8.5 8.5 0 0 1-12.3 7.6L3.5 21l1.3-4.4A8.5 8.5 0 1 1 20.5 12z"/><path d="M8.5 10.5h7M8.5 13.5h4.5"/>',
|
| 257 |
+
topk: '<path d="M9 6h11M9 12h11M9 18h11"/><circle class="f" cx="4.5" cy="6" r="1.3"/><circle class="f" cx="4.5" cy="12" r="1.3"/><circle class="f" cx="4.5" cy="18" r="1.3"/>',
|
| 258 |
+
bharat: '<path class="bar1" d="M5 20v-3"/><path class="bar2" d="M10 20v-6.5"/><path class="bar3" d="M15 20V10"/><path class="bar4" d="M20 20V5.5"/>',
|
| 259 |
+
scale: '<path d="M7 4.5h11M7 9h11M7 4.5h3.2a4.5 4.5 0 0 1 0 9H7l8.5 7"/>',
|
| 260 |
+
};
|
| 261 |
+
const CAPS = [
|
| 262 |
+
{ key: "offline", title: "Fully offline", body: "After the first visit nothing is fetched. Switch on airplane mode and keep typing — on a flight, in a lift, on a train.", demos: ["flight mein hoon, land karke call karta hoon"], net: true },
|
| 263 |
+
{ key: "private", title: "Private by design", body: "Text never leaves the device: no API call, no logging server. Built for banking, health and personal chat.", demos: ["mera account balance kitna hai", "doctor ne din mein do baar dawai lene ko kaha"] },
|
| 264 |
+
{ key: "anywhere", title: "Runs wherever JavaScript runs", body: "A browser tab, an Android or iOS WebView, an installable PWA, or Node.js. CPU only — no GPU, no server, no inference bill.", pills: ["Browser tab", "WebView", "PWA", "Node.js"], demos: ["namaste, aapka swagat hai"] },
|
| 265 |
+
{ key: "realtime", title: "Real-time, as you type", body: "The sentence is re-decoded on every keystroke in a Web Worker, so earlier words are corrected as context arrives.", steps: ["main", "main theek", "main theek hoon"] },
|
| 266 |
+
{ key: "ime", title: "Keyboard & input-box integration", body: "Wire it to any input or textarea: chat, search, forms, CRM notes, customer-support replies.", pills: ["Chat", "Search", "Forms", "CRM", "Support"], ime: "aapka refund teen din mein aa jayega" },
|
| 267 |
+
{ key: "brands", title: "Brands your way", body: "Default writes everything in Devanagari; Strict keeps well-known brand and product names in Latin script.", mix: "kal whatsapp pe meeting hai" },
|
| 268 |
+
{ key: "topk", title: "Top-k suggestions", body: "Ranked candidates for every word, ready for a suggestion bar or candidate picker. A pick re-decodes the rest of the sentence.", chips: "main" },
|
| 269 |
+
{ key: "bharat", title: "Built for Bharat", body: "", size: true, demos: ["signal nahi aa raha, baad mein baat karte hain"] },
|
| 270 |
+
{ key: "scale", title: "₹0 per call at scale", body: "Inference runs on your users’ devices: no per-request API fees, no GPU servers to scale — just static files on any CDN. Apache-2.0, free for commercial use.", demos: ["mera order kab tak deliver hoga"] },
|
| 271 |
+
];
|
| 272 |
+
const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches || navigator.webdriver;
|
| 273 |
+
const io = "IntersectionObserver" in window && !reduced ? new IntersectionObserver((es) => es.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }), { threshold: 0.15 }) : null;
|
| 274 |
+
const reveal = (n, i = 0) => { n.classList.add("rv"); n.style.setProperty("--d", (i % 3) * 90 + "ms"); if (io) io.observe(n); else n.classList.add("in"); };
|
| 275 |
+
const icon = (k) => `<svg viewBox="0 0 24 24" aria-hidden="true">${IC[k]}</svg>`;
|
| 276 |
+
|
| 277 |
+
function buildCaps() {
|
| 278 |
+
const g = $("#caps");
|
| 279 |
+
CAPS.forEach((c, i) => {
|
| 280 |
+
const n = el("article", "cap cap-" + c.key); const ic = el("div", "cic"); ic.innerHTML = icon(c.key);
|
| 281 |
+
n.append(ic, el("h3", "", c.title), c.body ? el("p", "", c.body) : el("p", "cap-body"));
|
| 282 |
+
if (c.pills) { const pr = el("div", "pills"); c.pills.forEach((p) => pr.append(el("span", "pl", p))); n.append(pr); }
|
| 283 |
+
if (c.net) { const nb = el("div", "net"); n.append(nb); c.netEl = nb; }
|
| 284 |
+
const slot = el("div", "fslot"); const sh = el("div", "demo-line"); sh.append(el("span", "shimmer")); slot.append(sh); n.append(slot); c.slot = slot;
|
| 285 |
+
g.append(n); reveal(n, i);
|
| 286 |
+
});
|
| 287 |
+
const net = () => CAPS.forEach((c) => { if (!c.netEl) return; const on = navigator.onLine; c.netEl.className = "net " + (on ? "on" : "off");
|
| 288 |
+
c.netEl.textContent = on ? "Network: online — try airplane mode, then type above" : "Network: offline — and still transliterating"; });
|
| 289 |
+
addEventListener("online", net); addEventListener("offline", net); net();
|
| 290 |
+
}
|
| 291 |
+
const line = (t, o) => { const d = el("div", "demo-line"); d.append(el("span", "r", t), el("span", "arrow", "→"), el("span", "d", o)); return d; };
|
| 292 |
+
async function fillCaps() {
|
| 293 |
+
for (const c of CAPS) {
|
| 294 |
+
const s = c.slot;
|
| 295 |
+
if (c.size) s.parentNode.querySelector(".cap-body").textContent = `A ${fmtMB(state.info.gz + (state.info.dict ? state.info.dict.gz : 0))} one-time download that caches (${fmtMB(state.info.gz)} core${state.info.dict ? " + " + fmtMB(state.info.dict.gz) + " dictionary" : ""}); after that, patchy or missing connectivity does not matter. Pure JavaScript on the CPU, designed with entry-level Android phones in mind.`;
|
| 296 |
+
if (c.demos) { const out = await batch(c.demos.map((t) => ({ text: t, opts: { mode: "conversational" } }))); s.textContent = ""; c.demos.forEach((t, i) => s.append(line(t, out[i].output))); }
|
| 297 |
+
else if (c.steps) {
|
| 298 |
+
const out = await batch(c.steps.map((t) => ({ text: t, opts: { mode: "conversational" } }))); s.textContent = "";
|
| 299 |
+
const box = el("div", "steps-live"); c.steps.forEach((t, i) => { const r = line(t, out[i].output); r.classList.add("st"); r.style.setProperty("--i", i); box.append(r); });
|
| 300 |
+
const lat = el("div", "lat-live"); lat.id = "cap-lat"; lat.textContent = "Type in the playground to measure latency in this tab";
|
| 301 |
+
s.append(box, lat); updateCapLatency();
|
| 302 |
+
} else if (c.ime) {
|
| 303 |
+
const words = c.ime.split(" "), prefixes = words.map((_, i) => words.slice(0, i + 1).join(" "));
|
| 304 |
+
const out = await batch(prefixes.map((t) => ({ text: t, opts: { mode: "conversational" } }))); s.textContent = "";
|
| 305 |
+
const box = el("div", "ime"); const top = el("div", "ime-in"); const caret = el("span", "caret"); const typed = el("span", "ime-r");
|
| 306 |
+
top.append(typed, caret); const bot = el("div", "ime-out"); box.append(el("span", "ime-lbl", "Support reply"), top, bot); s.append(box);
|
| 307 |
+
let k = reduced ? prefixes.length - 1 : 0;
|
| 308 |
+
const tick = () => { typed.textContent = prefixes[k]; bot.textContent = out[k].output; bot.animate && !reduced && bot.animate([{ opacity: .55 }, { opacity: 1 }], { duration: 260 }); };
|
| 309 |
+
tick(); if (!reduced) setInterval(() => { k = (k + 1) % (prefixes.length + 2); if (k < prefixes.length) tick(); }, 650);
|
| 310 |
+
} else if (c.mix) {
|
| 311 |
+
const modes = [["conversational", "Default"], ["strict", "Strict"]];
|
| 312 |
+
const out = await batch(modes.map(([m]) => ({ text: c.mix, opts: { mode: m } }))); s.textContent = "";
|
| 313 |
+
s.append(line(c.mix, ""));
|
| 314 |
+
modes.forEach(([, lab], i) => { const r = el("div", "demo-line mode-row"); r.append(el("span", "mlab", lab), el("span", "d", out[i].output)); s.append(r); });
|
| 315 |
+
} else if (c.chips) {
|
| 316 |
+
const [r] = await batch([{ text: c.chips, opts: { k: 5 } }]); s.textContent = "";
|
| 317 |
+
const d = el("div", "demo-line"); d.append(el("span", "r", c.chips + " →"));
|
| 318 |
+
r.tokens[0].candidates.forEach((x, i) => { const m = el("span", "mini-chip" + (i === 0 ? " on" : ""), x.text); m.style.animationDelay = i * 60 + "ms"; d.append(m); }); s.append(d);
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
}
|
| 322 |
+
function updateCapLatency() {
|
| 323 |
+
const e = document.getElementById("cap-lat"); if (!e || !state.lat.length) return;
|
| 324 |
+
const a = [...state.lat].sort((x, y) => x - y), p50 = a[Math.floor(a.length / 2)];
|
| 325 |
+
e.innerHTML = `Measured in this tab: <b>${p50 < 10 ? p50.toFixed(1) : Math.round(p50)} ms</b> per update (p50 of ${a.length})`;
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
/* "Best in class for its size": tiles come only from claims that passed in build_release.py (see build_report.json). */
|
| 329 |
+
function buildBest() {
|
| 330 |
+
let C; try { C = JSON.parse($("#claims-data").textContent); } catch { return; }
|
| 331 |
+
if (!C || !C.tiles || !C.tiles.length) return;
|
| 332 |
+
$("#best").hidden = false; $("#best-h").textContent = C.heading;
|
| 333 |
+
const g = $("#tiles");
|
| 334 |
+
C.tiles.forEach((t, i) => {
|
| 335 |
+
const n = el("div", "tile"); const v = el("div", "tv"); const num = el("span", "num", fmtNum(t.value, t.dec)); v.append(num, el("span", "tu", t.unit));
|
| 336 |
+
n.append(v, el("div", "tl", t.label), el("div", "ts", t.sub)); g.append(n); reveal(n, i);
|
| 337 |
+
const go = () => countUp(num, t.value, t.dec);
|
| 338 |
+
if (io) new IntersectionObserver((es, o) => { if (es[0].isIntersecting) { go(); o.disconnect(); } }, { threshold: 0.4 }).observe(n);
|
| 339 |
+
});
|
| 340 |
+
if (C.board && C.board.length) {
|
| 341 |
+
const b = $("#board"); b.hidden = false; b.append(el("div", "bh", "Accuracy per MB · top-1 on Aksharantar Hindi test ÷ on-disk size"));
|
| 342 |
+
const max = C.board[0].per_mb;
|
| 343 |
+
C.board.forEach((r, i) => { const row = el("div", "brow" + (r.us ? " us" : "")); const bar = el("div", "sbar"); const sp = el("span"); bar.append(sp);
|
| 344 |
+
row.append(el("span", "rk", "#" + (i + 1)), el("span", "nm", r.name), bar, el("span", "val", r.per_mb.toFixed(2) + " pts/MB")); b.append(row);
|
| 345 |
+
requestAnimationFrame(() => requestAnimationFrame(() => { sp.style.width = Math.max(1.5, 100 * Math.sqrt(r.per_mb / max)).toFixed(2) + "%"; })); });
|
| 346 |
+
}
|
| 347 |
+
if (C.highlight) { const h = $("#best-hl"); h.hidden = false; h.textContent = "🏆 " + C.highlight; }
|
| 348 |
+
}
|
| 349 |
+
const fmtNum = (v, dec) => v.toLocaleString("en-US", { minimumFractionDigits: dec, maximumFractionDigits: dec });
|
| 350 |
+
function countUp(node, to, dec) {
|
| 351 |
+
if (reduced) return; const t0 = performance.now(), dur = 1100;
|
| 352 |
+
const step = (t) => { const p = Math.min(1, (t - t0) / dur), e = 1 - Math.pow(1 - p, 3); node.textContent = fmtNum(to * e, dec); if (p < 1) requestAnimationFrame(step); };
|
| 353 |
+
requestAnimationFrame(step);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
/* ---------------------------------------------------------------- interactions */
|
| 357 |
+
let lastText = "";
|
| 358 |
+
input.addEventListener("input", () => { shiftOverrides(lastText, input.value); lastText = input.value; state.sel = null; autosize(); run(); });
|
| 359 |
+
input.addEventListener("keyup", (e) => { if (e.key.startsWith("Arrow") || e.key === "Home" || e.key === "End") { state.sel = null; renderChips(); } });
|
| 360 |
+
input.addEventListener("click", () => { state.sel = null; renderChips(); });
|
| 361 |
+
function autosize() { input.style.height = "auto"; input.style.height = Math.max(input.scrollHeight, 120) + "px"; }
|
| 362 |
+
|
| 363 |
+
const seg = $("#modes"), glider = seg.querySelector(".seg-glider");
|
| 364 |
+
function placeGlider() { const b = seg.querySelector('[aria-checked="true"]'); glider.style.width = b.offsetWidth + "px"; glider.style.transform = `translateX(${b.offsetLeft - 4}px)`; }
|
| 365 |
+
function setMode(m) { state.mode = m; seg.querySelectorAll("button").forEach((b) => b.setAttribute("aria-checked", String(b.dataset.mode === m))); placeGlider(); }
|
| 366 |
+
seg.querySelectorAll("button").forEach((b) => b.addEventListener("click", () => { setMode(b.dataset.mode); run(); }));
|
| 367 |
+
window.addEventListener("resize", placeGlider); document.fonts && document.fonts.ready.then(placeGlider); placeGlider();
|
| 368 |
+
$("#ctx").addEventListener("change", (e) => { state.ctx = e.target.checked; run(); });
|
| 369 |
+
$("#clear").addEventListener("click", () => { input.value = ""; lastText = ""; state.overrides = []; state.sel = null; autosize(); run(); input.focus(); });
|
| 370 |
+
$("#copy").addEventListener("click", async () => {
|
| 371 |
+
const txt = state.res ? state.res.output : ""; if (!txt) return;
|
| 372 |
+
try { await navigator.clipboard.writeText(txt); } catch { const t = el("textarea"); t.value = txt; document.body.append(t); t.select(); document.execCommand("copy"); t.remove(); }
|
| 373 |
+
const b = $("#copy"); b.classList.add("done"); b.querySelector("span").textContent = "Copied"; toast("Copied Devanagari to clipboard");
|
| 374 |
+
setTimeout(() => { b.classList.remove("done"); b.querySelector("span").textContent = "Copy"; }, 1600);
|
| 375 |
+
});
|
| 376 |
+
function toast(msg) { const t = $("#toast"); t.textContent = msg; t.classList.add("on"); clearTimeout(toast.h); toast.h = setTimeout(() => t.classList.remove("on"), 1800); }
|
| 377 |
+
|
| 378 |
+
document.querySelectorAll(".attr-copy").forEach((b) => b.addEventListener("click", async () => {
|
| 379 |
+
const txt = document.getElementById(b.dataset.copy).textContent;
|
| 380 |
+
try { await navigator.clipboard.writeText(txt); } catch { const t = el("textarea"); t.value = txt; document.body.append(t); t.select(); document.execCommand("copy"); t.remove(); }
|
| 381 |
+
b.textContent = "Copied"; b.classList.add("done"); toast("Copied to clipboard"); setTimeout(() => { b.textContent = "Copy"; b.classList.remove("done"); }, 1600);
|
| 382 |
+
}));
|
| 383 |
+
|
| 384 |
+
const root = document.documentElement;
|
| 385 |
+
$("#theme").addEventListener("click", () => {
|
| 386 |
+
const dark = root.dataset.theme === "dark" || (root.dataset.theme === "auto" && matchMedia("(prefers-color-scheme: dark)").matches);
|
| 387 |
+
root.dataset.theme = dark ? "light" : "dark"; try { localStorage.setItem("aklp-theme", root.dataset.theme); } catch {}
|
| 388 |
+
});
|
| 389 |
+
|
| 390 |
+
let typing = 0;
|
| 391 |
+
async function typeIn(ex, { speed = 32 } = {}) {
|
| 392 |
+
const my = ++typing; if (ex.mode) setMode(ex.mode); else setMode("conversational");
|
| 393 |
+
state.overrides = []; state.sel = null;
|
| 394 |
+
$("#playground").scrollIntoView({ behavior: "smooth", block: "center" });
|
| 395 |
+
input.value = ""; lastText = ""; input.focus();
|
| 396 |
+
for (const ch of ex.text) {
|
| 397 |
+
if (my !== typing) return;
|
| 398 |
+
input.value += ch; lastText = input.value; autosize(); run();
|
| 399 |
+
await new Promise((r) => setTimeout(r, speed + (ch === " " ? speed : 0)));
|
| 400 |
+
}
|
| 401 |
+
}
|
| 402 |
+
window.bhcTypeIn = typeIn; window.bhcState = state; window.bhcSetMode = setMode;
|
| 403 |
+
|
| 404 |
+
buildExamples(); buildCaps(); buildBest(); buildFeatures();
|
| 405 |
+
const q = new URLSearchParams(location.search);
|
| 406 |
+
if (q.get("text")) { input.value = q.get("text"); lastText = input.value; }
|
| 407 |
+
if (q.get("mode") && seg.querySelector(`[data-mode="${q.get("mode")}"]`)) setMode(q.get("mode"));
|
js/worker.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// AksharaLP Space — inference worker (keeps the UI thread at 60 fps).
|
| 2 |
+
// Two-tier load: the small core (model + reranker) first, so typing works immediately; then the dictionary pack
|
| 3 |
+
// (lexicon + sentence LM), read from the Cache API after the first visit. If the pack cannot be fetched, the engine
|
| 4 |
+
// keeps running core-only.
|
| 5 |
+
import BhashaCore from "./aksharalp.mjs";
|
| 6 |
+
|
| 7 |
+
let engine = null;
|
| 8 |
+
const base = new URL("../model/", self.location.href).href;
|
| 9 |
+
const q = new URLSearchParams(self.location.search);
|
| 10 |
+
|
| 11 |
+
(async () => {
|
| 12 |
+
try {
|
| 13 |
+
engine = await BhashaCore.load(base, { dict: false, onProgress: (file) => postMessage({ type: "progress", file }) });
|
| 14 |
+
const t0 = performance.now();
|
| 15 |
+
engine.transliterate("main ghar ja raha hoon", { k: 5 });
|
| 16 |
+
postMessage({ type: "ready", info: engine.info(), loadMs: engine.loadMs, warmMs: performance.now() - t0, note: engine.manifest && engine.manifest.note, name: engine.manifest && engine.manifest.name });
|
| 17 |
+
if (q.get("dict") === "0") { postMessage({ type: "dict", ok: false, skipped: true, info: engine.info() }); return; }
|
| 18 |
+
const t1 = performance.now(); let src = null;
|
| 19 |
+
const ok = await engine.loadDict({ onProgress: (file, from) => { src = from; postMessage({ type: "progress", file: "dictionary/" + file, from }); } });
|
| 20 |
+
if (ok) engine.transliterate("main ghar ja raha hoon", { k: 5 });
|
| 21 |
+
postMessage({ type: "dict", ok, from: src, ms: performance.now() - t1, error: engine.dictError, info: engine.info() });
|
| 22 |
+
} catch (e) {
|
| 23 |
+
postMessage({ type: "error", message: String(e && e.message || e) });
|
| 24 |
+
}
|
| 25 |
+
})();
|
| 26 |
+
|
| 27 |
+
onmessage = ({ data }) => {
|
| 28 |
+
if (!engine) return postMessage({ type: "error", id: data.id, message: "model not loaded" });
|
| 29 |
+
try {
|
| 30 |
+
if (data.type === "run") {
|
| 31 |
+
const res = engine.transliterate(data.text, data.opts || {});
|
| 32 |
+
postMessage({ type: "result", id: data.id, tag: data.tag, res });
|
| 33 |
+
} else if (data.type === "batch") {
|
| 34 |
+
const out = data.items.map((it) => engine.transliterate(it.text, it.opts || {}));
|
| 35 |
+
postMessage({ type: "batch", id: data.id, out });
|
| 36 |
+
}
|
| 37 |
+
} catch (e) {
|
| 38 |
+
postMessage({ type: "error", id: data.id, message: String(e && e.message || e) });
|
| 39 |
+
}
|
| 40 |
+
};
|
model/dict/lex.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8220fbc4c5d9ce06888182c6d8f8d53920987acf08449ccf4f7062b0158f4fa2
|
| 3 |
+
size 5647376
|
model/dict/lm.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:01090665a81a4df02113720b755f3e884d5dccf0a9e24ea413606e0d3f132f0d
|
| 3 |
+
size 2372806
|
model/dict/params.json
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"skel": true,
|
| 3 |
+
"visr": true,
|
| 4 |
+
"acro_v": true,
|
| 5 |
+
"beam": 16,
|
| 6 |
+
"nbest": 16,
|
| 7 |
+
"cbeam": 12,
|
| 8 |
+
"model_src": "models/xlit/v2S/best.pt step 36000",
|
| 9 |
+
"w1": [
|
| 10 |
+
[
|
| 11 |
+
0.17813511192798615,
|
| 12 |
+
0.08036437630653381,
|
| 13 |
+
0.19679796695709229,
|
| 14 |
+
0.01708296313881874,
|
| 15 |
+
0.03845738619565964,
|
| 16 |
+
0.0380135253071785,
|
| 17 |
+
-0.09296119213104248,
|
| 18 |
+
0.050487861037254333,
|
| 19 |
+
-0.08029724657535553,
|
| 20 |
+
0.04498514533042908,
|
| 21 |
+
-0.021634582430124283,
|
| 22 |
+
-0.004892073571681976,
|
| 23 |
+
-0.002368832938373089,
|
| 24 |
+
-0.0911487340927124,
|
| 25 |
+
0.05593618005514145,
|
| 26 |
+
0.08526270091533661,
|
| 27 |
+
0.12243881821632385,
|
| 28 |
+
0.18907511234283447,
|
| 29 |
+
0.10099691152572632,
|
| 30 |
+
-0.038430821150541306,
|
| 31 |
+
-0.11288196593523026,
|
| 32 |
+
-0.0007177454535849392,
|
| 33 |
+
0.0035953472834080458,
|
| 34 |
+
0.021397588774561882
|
| 35 |
+
],
|
| 36 |
+
[
|
| 37 |
+
-0.006028763949871063,
|
| 38 |
+
-0.12106657773256302,
|
| 39 |
+
0.042146626859903336,
|
| 40 |
+
-0.4276510179042816,
|
| 41 |
+
0.012659783475100994,
|
| 42 |
+
0.06286242604255676,
|
| 43 |
+
0.22930926084518433,
|
| 44 |
+
0.07123792916536331,
|
| 45 |
+
-0.020782090723514557,
|
| 46 |
+
0.11607885360717773,
|
| 47 |
+
0.14936329424381256,
|
| 48 |
+
0.09462408721446991,
|
| 49 |
+
0.16972823441028595,
|
| 50 |
+
0.04129566624760628,
|
| 51 |
+
0.14494967460632324,
|
| 52 |
+
-0.020984815433621407,
|
| 53 |
+
-0.10806243121623993,
|
| 54 |
+
-0.10849157720804214,
|
| 55 |
+
-0.19437053799629211,
|
| 56 |
+
-0.31409937143325806,
|
| 57 |
+
-0.586150050163269,
|
| 58 |
+
0.0009765241993591189,
|
| 59 |
+
-0.04616982117295265,
|
| 60 |
+
0.018640238791704178
|
| 61 |
+
],
|
| 62 |
+
[
|
| 63 |
+
0.18020284175872803,
|
| 64 |
+
0.24925513565540314,
|
| 65 |
+
-0.3156750202178955,
|
| 66 |
+
0.7410120368003845,
|
| 67 |
+
0.05266919732093811,
|
| 68 |
+
0.023455671966075897,
|
| 69 |
+
-0.10111861675977707,
|
| 70 |
+
-0.052379947155714035,
|
| 71 |
+
-0.019208308309316635,
|
| 72 |
+
-0.24292567372322083,
|
| 73 |
+
-0.32397910952568054,
|
| 74 |
+
-0.29089751839637756,
|
| 75 |
+
-0.04565871134400368,
|
| 76 |
+
0.029478222131729126,
|
| 77 |
+
0.06633909791707993,
|
| 78 |
+
-0.24604307115077972,
|
| 79 |
+
0.2161150425672531,
|
| 80 |
+
0.051885999739170074,
|
| 81 |
+
0.07496750354766846,
|
| 82 |
+
0.24305206537246704,
|
| 83 |
+
0.03907898813486099,
|
| 84 |
+
0.004860813729465008,
|
| 85 |
+
-0.005158992484211922,
|
| 86 |
+
-0.009064738638699055
|
| 87 |
+
],
|
| 88 |
+
[
|
| 89 |
+
0.6659682393074036,
|
| 90 |
+
0.6271504759788513,
|
| 91 |
+
0.8267438411712646,
|
| 92 |
+
-0.0196339413523674,
|
| 93 |
+
-0.0030769642908126116,
|
| 94 |
+
0.07327580451965332,
|
| 95 |
+
-0.1458965241909027,
|
| 96 |
+
0.03747393563389778,
|
| 97 |
+
0.021843524649739265,
|
| 98 |
+
-0.06475707143545151,
|
| 99 |
+
-0.000621478189714253,
|
| 100 |
+
-0.06723200529813766,
|
| 101 |
+
0.05655393749475479,
|
| 102 |
+
0.10602056980133057,
|
| 103 |
+
-0.18477147817611694,
|
| 104 |
+
0.00010097643098561093,
|
| 105 |
+
0.1388845443725586,
|
| 106 |
+
0.6009563207626343,
|
| 107 |
+
0.4833626449108124,
|
| 108 |
+
0.3857249915599823,
|
| 109 |
+
-0.06341658532619476,
|
| 110 |
+
-0.006819506175816059,
|
| 111 |
+
-0.0049257464706897736,
|
| 112 |
+
0.02972896583378315
|
| 113 |
+
],
|
| 114 |
+
[
|
| 115 |
+
0.1958463191986084,
|
| 116 |
+
0.060451485216617584,
|
| 117 |
+
-0.1030188724398613,
|
| 118 |
+
0.06920769810676575,
|
| 119 |
+
0.020387552678585052,
|
| 120 |
+
-0.34019315242767334,
|
| 121 |
+
0.37711480259895325,
|
| 122 |
+
0.11028768122196198,
|
| 123 |
+
0.08611816167831421,
|
| 124 |
+
-0.0002559171407483518,
|
| 125 |
+
0.0328388549387455,
|
| 126 |
+
-0.008063660003244877,
|
| 127 |
+
0.05640581250190735,
|
| 128 |
+
-0.09801948070526123,
|
| 129 |
+
-0.292701780796051,
|
| 130 |
+
0.25763431191444397,
|
| 131 |
+
0.4377913773059845,
|
| 132 |
+
0.11875400692224503,
|
| 133 |
+
0.07167524099349976,
|
| 134 |
+
-0.44701263308525085,
|
| 135 |
+
0.1679624617099762,
|
| 136 |
+
-0.013724947348237038,
|
| 137 |
+
-0.002409612061455846,
|
| 138 |
+
0.018655171617865562
|
| 139 |
+
],
|
| 140 |
+
[
|
| 141 |
+
-0.4902501702308655,
|
| 142 |
+
-0.1282314509153366,
|
| 143 |
+
-0.33340755105018616,
|
| 144 |
+
0.19906993210315704,
|
| 145 |
+
0.08487821370363235,
|
| 146 |
+
-0.3559322953224182,
|
| 147 |
+
-0.3382606506347656,
|
| 148 |
+
-0.001005868660286069,
|
| 149 |
+
-0.04727927967905998,
|
| 150 |
+
-0.06208423525094986,
|
| 151 |
+
-0.04709282144904137,
|
| 152 |
+
0.018225908279418945,
|
| 153 |
+
-0.04079766198992729,
|
| 154 |
+
0.19882585108280182,
|
| 155 |
+
0.11422300338745117,
|
| 156 |
+
-0.13318148255348206,
|
| 157 |
+
0.21266044676303864,
|
| 158 |
+
-0.366843044757843,
|
| 159 |
+
-0.2040664702653885,
|
| 160 |
+
0.33902281522750854,
|
| 161 |
+
-0.10848524421453476,
|
| 162 |
+
0.00449015898630023,
|
| 163 |
+
0.007850070483982563,
|
| 164 |
+
-0.0006993354763835669
|
| 165 |
+
],
|
| 166 |
+
[
|
| 167 |
+
0.026607975363731384,
|
| 168 |
+
-0.3412873446941376,
|
| 169 |
+
-0.10275707393884659,
|
| 170 |
+
0.062105849385261536,
|
| 171 |
+
-0.0532095842063427,
|
| 172 |
+
0.34755098819732666,
|
| 173 |
+
0.12969380617141724,
|
| 174 |
+
-0.2929081916809082,
|
| 175 |
+
0.021593520417809486,
|
| 176 |
+
0.04590011015534401,
|
| 177 |
+
0.2509603798389435,
|
| 178 |
+
-0.2497452050447464,
|
| 179 |
+
0.022632254287600517,
|
| 180 |
+
-0.18051375448703766,
|
| 181 |
+
-0.10409258306026459,
|
| 182 |
+
0.25614461302757263,
|
| 183 |
+
0.5726763010025024,
|
| 184 |
+
-0.03362720087170601,
|
| 185 |
+
-0.27375736832618713,
|
| 186 |
+
0.042891211807727814,
|
| 187 |
+
-0.228028804063797,
|
| 188 |
+
0.011015079915523529,
|
| 189 |
+
-0.015549133531749249,
|
| 190 |
+
0.08396020531654358
|
| 191 |
+
],
|
| 192 |
+
[
|
| 193 |
+
0.3212287425994873,
|
| 194 |
+
0.0899890661239624,
|
| 195 |
+
0.49252521991729736,
|
| 196 |
+
0.2562199831008911,
|
| 197 |
+
-0.002049004193395376,
|
| 198 |
+
0.0033560586161911488,
|
| 199 |
+
0.1140650138258934,
|
| 200 |
+
-0.010557741858065128,
|
| 201 |
+
0.0027649865951389074,
|
| 202 |
+
-0.019670777022838593,
|
| 203 |
+
0.08739964663982391,
|
| 204 |
+
0.013221975415945053,
|
| 205 |
+
0.006536773405969143,
|
| 206 |
+
-0.11335998773574829,
|
| 207 |
+
0.5197339653968811,
|
| 208 |
+
-0.0663549154996872,
|
| 209 |
+
-0.02756597474217415,
|
| 210 |
+
0.24392786622047424,
|
| 211 |
+
0.15097546577453613,
|
| 212 |
+
0.14113834500312805,
|
| 213 |
+
0.16664031147956848,
|
| 214 |
+
-0.0027184777427464724,
|
| 215 |
+
-0.019448233768343925,
|
| 216 |
+
-0.01375599391758442
|
| 217 |
+
],
|
| 218 |
+
[
|
| 219 |
+
0.07800205796957016,
|
| 220 |
+
0.034818798303604126,
|
| 221 |
+
0.05502532050013542,
|
| 222 |
+
-2.590376615524292,
|
| 223 |
+
0.02294650301337242,
|
| 224 |
+
-0.11992327123880386,
|
| 225 |
+
-0.09393031895160675,
|
| 226 |
+
0.00041266169864684343,
|
| 227 |
+
-0.004656890872865915,
|
| 228 |
+
0.00025705998996272683,
|
| 229 |
+
-0.3377724587917328,
|
| 230 |
+
0.00022986403200775385,
|
| 231 |
+
-0.01075729914009571,
|
| 232 |
+
-0.09341470152139664,
|
| 233 |
+
-0.06531170010566711,
|
| 234 |
+
0.016492702066898346,
|
| 235 |
+
-0.01895187422633171,
|
| 236 |
+
0.1475711315870285,
|
| 237 |
+
0.05689940229058266,
|
| 238 |
+
-0.14803127944469452,
|
| 239 |
+
0.09427160024642944,
|
| 240 |
+
-0.009358881041407585,
|
| 241 |
+
-0.0029688519425690174,
|
| 242 |
+
-0.04647454619407654
|
| 243 |
+
],
|
| 244 |
+
[
|
| 245 |
+
0.4999156892299652,
|
| 246 |
+
0.2220914363861084,
|
| 247 |
+
0.33505380153656006,
|
| 248 |
+
-0.49453970789909363,
|
| 249 |
+
-0.06474141031503677,
|
| 250 |
+
-0.1383964568376541,
|
| 251 |
+
-0.011427058838307858,
|
| 252 |
+
-0.2955826222896576,
|
| 253 |
+
-0.018822673708200455,
|
| 254 |
+
-0.007339491043239832,
|
| 255 |
+
-0.46729031205177307,
|
| 256 |
+
-0.011370798572897911,
|
| 257 |
+
-0.0015873261727392673,
|
| 258 |
+
-0.07475392520427704,
|
| 259 |
+
0.2003595232963562,
|
| 260 |
+
0.05121266096830368,
|
| 261 |
+
0.018622763454914093,
|
| 262 |
+
0.25806617736816406,
|
| 263 |
+
0.1493949294090271,
|
| 264 |
+
-0.533134400844574,
|
| 265 |
+
-0.05132618173956871,
|
| 266 |
+
-0.006106889806687832,
|
| 267 |
+
-0.01681436225771904,
|
| 268 |
+
0.02741990238428116
|
| 269 |
+
],
|
| 270 |
+
[
|
| 271 |
+
0.0681074932217598,
|
| 272 |
+
0.038069501519203186,
|
| 273 |
+
0.10067056864500046,
|
| 274 |
+
-0.008472531102597713,
|
| 275 |
+
0.02333664335310459,
|
| 276 |
+
-0.00102467299439013,
|
| 277 |
+
-0.01994895562529564,
|
| 278 |
+
0.01857077144086361,
|
| 279 |
+
-0.047107942402362823,
|
| 280 |
+
0.04690350964665413,
|
| 281 |
+
-0.03669547289609909,
|
| 282 |
+
-0.006082897540181875,
|
| 283 |
+
-0.012960744090378284,
|
| 284 |
+
-0.04504256695508957,
|
| 285 |
+
0.030808277428150177,
|
| 286 |
+
0.006868493743240833,
|
| 287 |
+
0.006323779933154583,
|
| 288 |
+
0.0695348009467125,
|
| 289 |
+
0.04156721383333206,
|
| 290 |
+
-0.02024010196328163,
|
| 291 |
+
-0.028812535107135773,
|
| 292 |
+
-0.0014116355450823903,
|
| 293 |
+
-0.0018215596210211515,
|
| 294 |
+
0.028311712667346
|
| 295 |
+
],
|
| 296 |
+
[
|
| 297 |
+
0.1624487191438675,
|
| 298 |
+
-0.20145384967327118,
|
| 299 |
+
0.2947416603565216,
|
| 300 |
+
-0.18476316332817078,
|
| 301 |
+
0.10492225736379623,
|
| 302 |
+
0.02244037389755249,
|
| 303 |
+
0.08404528349637985,
|
| 304 |
+
-0.25871041417121887,
|
| 305 |
+
-0.04818446561694145,
|
| 306 |
+
-0.010960616171360016,
|
| 307 |
+
0.1961546391248703,
|
| 308 |
+
0.10029289871454239,
|
| 309 |
+
0.1505267322063446,
|
| 310 |
+
0.07109440118074417,
|
| 311 |
+
-0.12312804162502289,
|
| 312 |
+
0.34896931052207947,
|
| 313 |
+
-0.2323760688304901,
|
| 314 |
+
0.0922774225473404,
|
| 315 |
+
-0.13451746106147766,
|
| 316 |
+
0.1011989414691925,
|
| 317 |
+
0.5111384391784668,
|
| 318 |
+
-0.006019487511366606,
|
| 319 |
+
-0.004957660101354122,
|
| 320 |
+
-0.046582095324993134
|
| 321 |
+
],
|
| 322 |
+
[
|
| 323 |
+
0.04909073933959007,
|
| 324 |
+
0.030656171962618828,
|
| 325 |
+
0.15804661810398102,
|
| 326 |
+
0.10214020311832428,
|
| 327 |
+
0.16083794832229614,
|
| 328 |
+
0.0853763297200203,
|
| 329 |
+
0.03564980998635292,
|
| 330 |
+
0.09763889014720917,
|
| 331 |
+
-0.10411129146814346,
|
| 332 |
+
0.05565249174833298,
|
| 333 |
+
-0.06129959598183632,
|
| 334 |
+
0.016972968354821205,
|
| 335 |
+
0.0011989623308181763,
|
| 336 |
+
-0.07131221890449524,
|
| 337 |
+
-0.009343582205474377,
|
| 338 |
+
0.15363125503063202,
|
| 339 |
+
-0.10034770518541336,
|
| 340 |
+
0.11451990902423859,
|
| 341 |
+
0.09195035696029663,
|
| 342 |
+
0.05555299296975136,
|
| 343 |
+
-0.0026579059194773436,
|
| 344 |
+
-0.00019085707026533782,
|
| 345 |
+
-0.00809928122907877,
|
| 346 |
+
-0.003035692498087883
|
| 347 |
+
],
|
| 348 |
+
[
|
| 349 |
+
-0.4292859435081482,
|
| 350 |
+
-0.30912452936172485,
|
| 351 |
+
-0.2200385481119156,
|
| 352 |
+
-0.116905577480793,
|
| 353 |
+
-0.025338981300592422,
|
| 354 |
+
0.06098977103829384,
|
| 355 |
+
0.3440200388431549,
|
| 356 |
+
-0.05883513391017914,
|
| 357 |
+
-0.1605994701385498,
|
| 358 |
+
0.17751748859882355,
|
| 359 |
+
-0.008709670975804329,
|
| 360 |
+
0.010275691747665405,
|
| 361 |
+
0.02400972694158554,
|
| 362 |
+
0.08755376935005188,
|
| 363 |
+
-0.22082173824310303,
|
| 364 |
+
-0.07206287980079651,
|
| 365 |
+
-0.040061041712760925,
|
| 366 |
+
-0.46672096848487854,
|
| 367 |
+
-0.28407829999923706,
|
| 368 |
+
0.11538465321063995,
|
| 369 |
+
0.1171279102563858,
|
| 370 |
+
0.011859945952892303,
|
| 371 |
+
-0.001572370994836092,
|
| 372 |
+
-0.040817804634571075
|
| 373 |
+
],
|
| 374 |
+
[
|
| 375 |
+
0.1292542964220047,
|
| 376 |
+
0.05990736559033394,
|
| 377 |
+
0.15684916079044342,
|
| 378 |
+
0.027777886018157005,
|
| 379 |
+
-0.018983762711286545,
|
| 380 |
+
0.02759557031095028,
|
| 381 |
+
-0.05131753534078598,
|
| 382 |
+
-0.0059871189296245575,
|
| 383 |
+
-0.08437316864728928,
|
| 384 |
+
0.06277438253164291,
|
| 385 |
+
-0.03361068293452263,
|
| 386 |
+
-0.012865407392382622,
|
| 387 |
+
-0.007676516659557819,
|
| 388 |
+
-0.09351667761802673,
|
| 389 |
+
0.06732753664255142,
|
| 390 |
+
0.024253742769360542,
|
| 391 |
+
0.045625172555446625,
|
| 392 |
+
0.13008730113506317,
|
| 393 |
+
0.08235563337802887,
|
| 394 |
+
-0.03187905624508858,
|
| 395 |
+
-0.05381424352526665,
|
| 396 |
+
-0.002394674578681588,
|
| 397 |
+
0.0015019901329651475,
|
| 398 |
+
0.029919074848294258
|
| 399 |
+
],
|
| 400 |
+
[
|
| 401 |
+
0.07045336067676544,
|
| 402 |
+
0.03842192888259888,
|
| 403 |
+
0.10945315659046173,
|
| 404 |
+
0.011984778568148613,
|
| 405 |
+
-0.004143330734223127,
|
| 406 |
+
0.013621147722005844,
|
| 407 |
+
-0.03646434098482132,
|
| 408 |
+
-0.003110044403001666,
|
| 409 |
+
-0.06586327403783798,
|
| 410 |
+
0.03978915140032768,
|
| 411 |
+
-0.05047072842717171,
|
| 412 |
+
-0.01864797994494438,
|
| 413 |
+
-0.021004721522331238,
|
| 414 |
+
-0.05321501940488815,
|
| 415 |
+
0.03387031704187393,
|
| 416 |
+
0.028345610946416855,
|
| 417 |
+
0.01672627031803131,
|
| 418 |
+
0.0735769271850586,
|
| 419 |
+
0.04922883212566376,
|
| 420 |
+
-0.023395273834466934,
|
| 421 |
+
-0.024696746841073036,
|
| 422 |
+
-0.0015744910342618823,
|
| 423 |
+
-0.0015623833751305938,
|
| 424 |
+
0.02748068980872631
|
| 425 |
+
]
|
| 426 |
+
],
|
| 427 |
+
"b1": [
|
| 428 |
+
-0.4892691373825073,
|
| 429 |
+
-0.5365275144577026,
|
| 430 |
+
-0.7306413650512695,
|
| 431 |
+
-1.6562087535858154,
|
| 432 |
+
-0.5151417851448059,
|
| 433 |
+
0.708844780921936,
|
| 434 |
+
0.7126868367195129,
|
| 435 |
+
-0.3240874707698822,
|
| 436 |
+
-1.7912263870239258,
|
| 437 |
+
0.7072461843490601,
|
| 438 |
+
-0.12453608959913254,
|
| 439 |
+
0.5035669803619385,
|
| 440 |
+
-0.040696702897548676,
|
| 441 |
+
1.397632122039795,
|
| 442 |
+
-0.16429384052753448,
|
| 443 |
+
0.12540210783481598
|
| 444 |
+
],
|
| 445 |
+
"w2": [
|
| 446 |
+
0.4470292627811432,
|
| 447 |
+
-0.7432265281677246,
|
| 448 |
+
-0.9799825549125671,
|
| 449 |
+
1.462009072303772,
|
| 450 |
+
0.7532961964607239,
|
| 451 |
+
-0.946394145488739,
|
| 452 |
+
-0.8859969973564148,
|
| 453 |
+
0.9506633281707764,
|
| 454 |
+
-2.2269387245178223,
|
| 455 |
+
1.2120633125305176,
|
| 456 |
+
0.21145373582839966,
|
| 457 |
+
0.8740106225013733,
|
| 458 |
+
0.4242953956127167,
|
| 459 |
+
-0.8897668123245239,
|
| 460 |
+
0.3393680155277252,
|
| 461 |
+
0.22115716338157654
|
| 462 |
+
],
|
| 463 |
+
"b2": -0.06786252558231354,
|
| 464 |
+
"mu": [
|
| 465 |
+
-10.59149414686468,
|
| 466 |
+
-1.6581433637635177,
|
| 467 |
+
0.7237200583211831,
|
| 468 |
+
-12.3009989777537,
|
| 469 |
+
0.02630701937096438,
|
| 470 |
+
0.4139387627577588,
|
| 471 |
+
0.4209123099354301,
|
| 472 |
+
0.02563215996667361,
|
| 473 |
+
0.004328264944803166,
|
| 474 |
+
0.0609081441366382,
|
| 475 |
+
0.012364090814413664,
|
| 476 |
+
0.0024453238908560718,
|
| 477 |
+
0.0026619454280358257,
|
| 478 |
+
0.7775174442824412,
|
| 479 |
+
0.3690856071651739,
|
| 480 |
+
0.7192209956259112,
|
| 481 |
+
0.34080003067104875,
|
| 482 |
+
-9.126102225106102,
|
| 483 |
+
-1.4507808667211526,
|
| 484 |
+
-5.180230198802364,
|
| 485 |
+
0.7058964616693312,
|
| 486 |
+
0.00014580295771714227,
|
| 487 |
+
0.0010414496979795876,
|
| 488 |
+
0.00020828993959591752
|
| 489 |
+
],
|
| 490 |
+
"sd": [
|
| 491 |
+
7.073135913287144,
|
| 492 |
+
1.0987393915943025,
|
| 493 |
+
0.44715794728364644,
|
| 494 |
+
8.142382377773437,
|
| 495 |
+
0.1600477434927935,
|
| 496 |
+
0.49253877869736523,
|
| 497 |
+
0.49370651676030625,
|
| 498 |
+
0.15803628828118246,
|
| 499 |
+
0.0656480187243049,
|
| 500 |
+
0.2391627488529239,
|
| 501 |
+
0.11050538938222514,
|
| 502 |
+
0.04939071838272889,
|
| 503 |
+
0.05152632847625885,
|
| 504 |
+
0.32244279318200153,
|
| 505 |
+
0.4825581694084105,
|
| 506 |
+
0.44938074484411195,
|
| 507 |
+
0.21476388807955527,
|
| 508 |
+
7.099387943262964,
|
| 509 |
+
1.1012014396087357,
|
| 510 |
+
4.397275599530713,
|
| 511 |
+
0.19354262566657165,
|
| 512 |
+
0.012075009243560244,
|
| 513 |
+
0.032255690829585425,
|
| 514 |
+
0.01443175032345713
|
| 515 |
+
],
|
| 516 |
+
"feats": [
|
| 517 |
+
"sc",
|
| 518 |
+
"scn",
|
| 519 |
+
"inlex",
|
| 520 |
+
"uni",
|
| 521 |
+
"free0",
|
| 522 |
+
"infree",
|
| 523 |
+
"incon",
|
| 524 |
+
"aw",
|
| 525 |
+
"visarga",
|
| 526 |
+
"nukta",
|
| 527 |
+
"chandra",
|
| 528 |
+
"acro",
|
| 529 |
+
"variant",
|
| 530 |
+
"frank",
|
| 531 |
+
"skel",
|
| 532 |
+
"skmatch",
|
| 533 |
+
"lev",
|
| 534 |
+
"sc_rel",
|
| 535 |
+
"scn_rel",
|
| 536 |
+
"uni_rel",
|
| 537 |
+
"lenr",
|
| 538 |
+
"visr",
|
| 539 |
+
"hfin",
|
| 540 |
+
"acro_nv"
|
| 541 |
+
],
|
| 542 |
+
"rerank_hid": 16,
|
| 543 |
+
"reranker_fit_on": "Aksharantar hin_valid (all distinct romans)",
|
| 544 |
+
"val_rerank_cv2": 69.3
|
| 545 |
+
}
|
model/manifest.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "bhashacore-bundle/1",
|
| 3 |
+
"name": "AksharaLP-1M",
|
| 4 |
+
"note": "AksharaLP-1M v1.0.0",
|
| 5 |
+
"files": {
|
| 6 |
+
"model": "xlit.q4",
|
| 7 |
+
"lex": null,
|
| 8 |
+
"lm": null,
|
| 9 |
+
"params": "params.json",
|
| 10 |
+
"lid": null,
|
| 11 |
+
"loan": null,
|
| 12 |
+
"natural": null
|
| 13 |
+
},
|
| 14 |
+
"sizes": {
|
| 15 |
+
"params.json": {
|
| 16 |
+
"bytes": 12120,
|
| 17 |
+
"gz": 5316,
|
| 18 |
+
"sha256": "67a2a1477eafe7fc34bd20fb93c16fbd23b8353a35bef9dc88814ea6b2705c1d"
|
| 19 |
+
},
|
| 20 |
+
"xlit.q4": {
|
| 21 |
+
"bytes": 588891,
|
| 22 |
+
"gz": 543767,
|
| 23 |
+
"sha256": "cf8ff5255105f556b1865c9db1c837bdafaa8b1b93c9e3e5e6e38afb994e34e2"
|
| 24 |
+
}
|
| 25 |
+
},
|
| 26 |
+
"model_name": "AksharaLP-1M",
|
| 27 |
+
"version": "1.0.0",
|
| 28 |
+
"dict_name": "dict-1.5M",
|
| 29 |
+
"packs": {
|
| 30 |
+
"dict": {
|
| 31 |
+
"dir": "dict/",
|
| 32 |
+
"name": "dict-1.5M",
|
| 33 |
+
"files": {
|
| 34 |
+
"lex": "lex.bin",
|
| 35 |
+
"lm": "lm.bin",
|
| 36 |
+
"params": "params.json"
|
| 37 |
+
},
|
| 38 |
+
"sizes": {
|
| 39 |
+
"lex.bin": {
|
| 40 |
+
"bytes": 5647376,
|
| 41 |
+
"gz": 3137141,
|
| 42 |
+
"sha256": "8220fbc4c5d9ce06888182c6d8f8d53920987acf08449ccf4f7062b0158f4fa2"
|
| 43 |
+
},
|
| 44 |
+
"lm.bin": {
|
| 45 |
+
"bytes": 2372806,
|
| 46 |
+
"gz": 825559,
|
| 47 |
+
"sha256": "01090665a81a4df02113720b755f3e884d5dccf0a9e24ea413606e0d3f132f0d"
|
| 48 |
+
},
|
| 49 |
+
"params.json": {
|
| 50 |
+
"bytes": 12034,
|
| 51 |
+
"gz": 5261,
|
| 52 |
+
"sha256": "0031609f902ec3d5be042b855d8801eb57a5ae54a32a1fa035a59f98629c2857"
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"bytes": 8032216,
|
| 56 |
+
"gz": 3967961
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
}
|
model/params.json
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"visr": true,
|
| 3 |
+
"acro_v": true,
|
| 4 |
+
"beam": 16,
|
| 5 |
+
"nbest": 16,
|
| 6 |
+
"model_file": "xlit.q4",
|
| 7 |
+
"model_src": "models/xlit/v2S/best.pt step 36000",
|
| 8 |
+
"w1": [
|
| 9 |
+
[
|
| 10 |
+
-0.015561956912279129,
|
| 11 |
+
-0.2590724527835846,
|
| 12 |
+
-4.91664104629308e-05,
|
| 13 |
+
-4.396255826577544e-05,
|
| 14 |
+
-0.044401731342077255,
|
| 15 |
+
0.03714057803153992,
|
| 16 |
+
-1.183583208330674e-06,
|
| 17 |
+
-0.08884930610656738,
|
| 18 |
+
-0.045074667781591415,
|
| 19 |
+
-0.08021057397127151,
|
| 20 |
+
0.07171142846345901,
|
| 21 |
+
-0.18331405520439148,
|
| 22 |
+
-5.70711272303015e-05,
|
| 23 |
+
-0.22631709277629852,
|
| 24 |
+
-2.46238851104863e-05,
|
| 25 |
+
0.055078305304050446,
|
| 26 |
+
0.8362643122673035,
|
| 27 |
+
0.24692192673683167,
|
| 28 |
+
-0.2144010215997696,
|
| 29 |
+
-2.6011599402409047e-05,
|
| 30 |
+
0.14259004592895508,
|
| 31 |
+
-0.0004840311303269118,
|
| 32 |
+
-0.04343048110604286,
|
| 33 |
+
-0.015337128192186356
|
| 34 |
+
],
|
| 35 |
+
[
|
| 36 |
+
-0.3434857726097107,
|
| 37 |
+
-0.12918725609779358,
|
| 38 |
+
5.408696597442031e-05,
|
| 39 |
+
-5.541890277527273e-05,
|
| 40 |
+
0.04218575730919838,
|
| 41 |
+
0.10622035712003708,
|
| 42 |
+
-2.3284759663511068e-05,
|
| 43 |
+
-0.16739186644554138,
|
| 44 |
+
-0.0073206983506679535,
|
| 45 |
+
-0.1622564047574997,
|
| 46 |
+
0.07639061659574509,
|
| 47 |
+
0.012584622949361801,
|
| 48 |
+
-3.4871758543886244e-05,
|
| 49 |
+
0.17102842032909393,
|
| 50 |
+
2.6655099645722657e-05,
|
| 51 |
+
0.11252907663583755,
|
| 52 |
+
0.0712190493941307,
|
| 53 |
+
-0.11443258821964264,
|
| 54 |
+
-0.031135937198996544,
|
| 55 |
+
-5.5775875807739794e-05,
|
| 56 |
+
-0.10498590022325516,
|
| 57 |
+
0.012443359941244125,
|
| 58 |
+
-0.03877473995089531,
|
| 59 |
+
-0.047652486711740494
|
| 60 |
+
],
|
| 61 |
+
[
|
| 62 |
+
-0.32081305980682373,
|
| 63 |
+
0.14551419019699097,
|
| 64 |
+
3.820210986305028e-05,
|
| 65 |
+
5.938495451118797e-05,
|
| 66 |
+
-0.20604437589645386,
|
| 67 |
+
-0.012057994492352009,
|
| 68 |
+
4.005451046396047e-05,
|
| 69 |
+
-0.2183503955602646,
|
| 70 |
+
0.0041027250699698925,
|
| 71 |
+
-0.15540724992752075,
|
| 72 |
+
-0.09696532040834427,
|
| 73 |
+
-0.15008299052715302,
|
| 74 |
+
2.703051723074168e-05,
|
| 75 |
+
0.3145005702972412,
|
| 76 |
+
-3.53828800143674e-05,
|
| 77 |
+
-0.046421173959970474,
|
| 78 |
+
-0.23587073385715485,
|
| 79 |
+
-0.15307018160820007,
|
| 80 |
+
0.02828281745314598,
|
| 81 |
+
1.3840537576470524e-05,
|
| 82 |
+
0.22715377807617188,
|
| 83 |
+
0.0005053964559920132,
|
| 84 |
+
-0.021614709869027138,
|
| 85 |
+
0.028349272906780243
|
| 86 |
+
],
|
| 87 |
+
[
|
| 88 |
+
0.22036844491958618,
|
| 89 |
+
-0.1495584100484848,
|
| 90 |
+
5.1986484322696924e-05,
|
| 91 |
+
5.271370173431933e-05,
|
| 92 |
+
-0.0721922442317009,
|
| 93 |
+
0.1422671228647232,
|
| 94 |
+
5.49514516023919e-06,
|
| 95 |
+
-0.32195183634757996,
|
| 96 |
+
-0.09321869909763336,
|
| 97 |
+
-0.23727498948574066,
|
| 98 |
+
0.0014756782911717892,
|
| 99 |
+
-0.20423376560211182,
|
| 100 |
+
1.11804147309158e-05,
|
| 101 |
+
-0.06835587322711945,
|
| 102 |
+
-9.829884220380336e-06,
|
| 103 |
+
0.06813204288482666,
|
| 104 |
+
0.13348449766635895,
|
| 105 |
+
0.10155773907899857,
|
| 106 |
+
-0.08579937368631363,
|
| 107 |
+
3.0208364478312433e-05,
|
| 108 |
+
0.657234787940979,
|
| 109 |
+
-0.00018066636403091252,
|
| 110 |
+
-0.06816288083791733,
|
| 111 |
+
0.012126388028264046
|
| 112 |
+
],
|
| 113 |
+
[
|
| 114 |
+
0.22822436690330505,
|
| 115 |
+
0.48054882884025574,
|
| 116 |
+
-4.6600878704339266e-05,
|
| 117 |
+
-3.439883585087955e-05,
|
| 118 |
+
-0.03180981054902077,
|
| 119 |
+
0.07301792502403259,
|
| 120 |
+
-2.6048139261547476e-05,
|
| 121 |
+
0.2848097085952759,
|
| 122 |
+
-0.02384837530553341,
|
| 123 |
+
-0.006694837473332882,
|
| 124 |
+
0.17171575129032135,
|
| 125 |
+
0.19061139225959778,
|
| 126 |
+
-3.2914358598645777e-06,
|
| 127 |
+
-0.019714917987585068,
|
| 128 |
+
-2.4464614398311824e-05,
|
| 129 |
+
-0.10351742058992386,
|
| 130 |
+
-0.4626687467098236,
|
| 131 |
+
0.30317893624305725,
|
| 132 |
+
0.34827369451522827,
|
| 133 |
+
-5.0375922000966966e-05,
|
| 134 |
+
0.22715719044208527,
|
| 135 |
+
-0.0019869711250066757,
|
| 136 |
+
0.01730377785861492,
|
| 137 |
+
0.021236998960375786
|
| 138 |
+
],
|
| 139 |
+
[
|
| 140 |
+
-0.35157841444015503,
|
| 141 |
+
-0.15391534566879272,
|
| 142 |
+
-2.9147995519451797e-05,
|
| 143 |
+
2.8266847948543727e-05,
|
| 144 |
+
-0.07769758254289627,
|
| 145 |
+
-0.07346295565366745,
|
| 146 |
+
-1.49544830492232e-05,
|
| 147 |
+
0.0257745198905468,
|
| 148 |
+
0.045600246638059616,
|
| 149 |
+
0.1594177633523941,
|
| 150 |
+
-0.05174051225185394,
|
| 151 |
+
-0.10748539865016937,
|
| 152 |
+
-3.891884989570826e-05,
|
| 153 |
+
-0.2300061136484146,
|
| 154 |
+
4.276317486073822e-05,
|
| 155 |
+
0.3480663597583771,
|
| 156 |
+
0.1923782080411911,
|
| 157 |
+
-0.32707351446151733,
|
| 158 |
+
-0.08953503519296646,
|
| 159 |
+
3.798186662606895e-05,
|
| 160 |
+
0.004443146288394928,
|
| 161 |
+
0.0027272962033748627,
|
| 162 |
+
-1.0397139703854918e-05,
|
| 163 |
+
-0.006435581482946873
|
| 164 |
+
],
|
| 165 |
+
[
|
| 166 |
+
-0.0968092828989029,
|
| 167 |
+
-0.021128321066498756,
|
| 168 |
+
4.0671322494745255e-05,
|
| 169 |
+
-3.8725966078345664e-07,
|
| 170 |
+
-0.01838799938559532,
|
| 171 |
+
0.0019020137842744589,
|
| 172 |
+
-5.590620276052505e-05,
|
| 173 |
+
-0.01308813039213419,
|
| 174 |
+
0.01992219313979149,
|
| 175 |
+
-0.020882558077573776,
|
| 176 |
+
0.043948717415332794,
|
| 177 |
+
-0.01846550777554512,
|
| 178 |
+
3.7261590478010476e-05,
|
| 179 |
+
0.033619239926338196,
|
| 180 |
+
-1.2629399861907586e-05,
|
| 181 |
+
-0.020962243899703026,
|
| 182 |
+
0.007218125741928816,
|
| 183 |
+
-0.10624664276838303,
|
| 184 |
+
-0.021414361894130707,
|
| 185 |
+
-5.157808482181281e-05,
|
| 186 |
+
0.0351666584610939,
|
| 187 |
+
0.004914436023682356,
|
| 188 |
+
0.0009687513811513782,
|
| 189 |
+
-0.018581906333565712
|
| 190 |
+
],
|
| 191 |
+
[
|
| 192 |
+
0.10835482180118561,
|
| 193 |
+
0.06843508780002594,
|
| 194 |
+
5.253354902379215e-05,
|
| 195 |
+
-2.4364875571336597e-05,
|
| 196 |
+
0.14761097729206085,
|
| 197 |
+
0.08214167505502701,
|
| 198 |
+
-5.3904863307252526e-05,
|
| 199 |
+
0.09664969891309738,
|
| 200 |
+
-0.04199868068099022,
|
| 201 |
+
-0.05236470699310303,
|
| 202 |
+
-0.08479249477386475,
|
| 203 |
+
0.003061349969357252,
|
| 204 |
+
6.410497007891536e-06,
|
| 205 |
+
-0.13751299679279327,
|
| 206 |
+
4.266103496775031e-05,
|
| 207 |
+
0.3822084069252014,
|
| 208 |
+
0.2888137400150299,
|
| 209 |
+
0.3472263813018799,
|
| 210 |
+
0.01722201518714428,
|
| 211 |
+
-1.2563064956339076e-05,
|
| 212 |
+
-0.10046061128377914,
|
| 213 |
+
-0.0014096840750426054,
|
| 214 |
+
0.0015327114379033446,
|
| 215 |
+
-0.00038207584293559194
|
| 216 |
+
],
|
| 217 |
+
[
|
| 218 |
+
-0.23380811512470245,
|
| 219 |
+
-0.03130961209535599,
|
| 220 |
+
-4.211945633869618e-05,
|
| 221 |
+
-3.28843598254025e-05,
|
| 222 |
+
0.17667055130004883,
|
| 223 |
+
-0.06306526809930801,
|
| 224 |
+
-3.5599005059339106e-05,
|
| 225 |
+
0.24570702016353607,
|
| 226 |
+
0.05341082438826561,
|
| 227 |
+
0.25450292229652405,
|
| 228 |
+
0.22926999628543854,
|
| 229 |
+
-0.12199188768863678,
|
| 230 |
+
-3.4688186133280396e-05,
|
| 231 |
+
0.0721987634897232,
|
| 232 |
+
-2.1470805222634226e-05,
|
| 233 |
+
0.10122892260551453,
|
| 234 |
+
0.24094152450561523,
|
| 235 |
+
-0.281928688287735,
|
| 236 |
+
-0.10936792194843292,
|
| 237 |
+
-1.1808137060143054e-05,
|
| 238 |
+
0.3210824728012085,
|
| 239 |
+
0.004107347689568996,
|
| 240 |
+
0.008137108758091927,
|
| 241 |
+
-0.0287738386541605
|
| 242 |
+
],
|
| 243 |
+
[
|
| 244 |
+
0.10402468591928482,
|
| 245 |
+
0.014269252307713032,
|
| 246 |
+
4.823542258236557e-05,
|
| 247 |
+
-4.848210664931685e-05,
|
| 248 |
+
0.006701572798192501,
|
| 249 |
+
-0.023116495460271835,
|
| 250 |
+
2.1578460291493684e-05,
|
| 251 |
+
0.04466652497649193,
|
| 252 |
+
-0.008599045686423779,
|
| 253 |
+
0.027766602113842964,
|
| 254 |
+
-0.03312336280941963,
|
| 255 |
+
0.02025029808282852,
|
| 256 |
+
-2.004284760914743e-05,
|
| 257 |
+
-0.029677756130695343,
|
| 258 |
+
6.53383722237777e-07,
|
| 259 |
+
-0.007501651998609304,
|
| 260 |
+
-0.012901795096695423,
|
| 261 |
+
0.08347664773464203,
|
| 262 |
+
0.004463751334697008,
|
| 263 |
+
-3.77678225049749e-05,
|
| 264 |
+
-0.006038411054760218,
|
| 265 |
+
-0.004326044116169214,
|
| 266 |
+
0.011772082187235355,
|
| 267 |
+
0.023333216086030006
|
| 268 |
+
],
|
| 269 |
+
[
|
| 270 |
+
0.13031642138957977,
|
| 271 |
+
0.0029603540897369385,
|
| 272 |
+
-1.9229766621720046e-05,
|
| 273 |
+
9.563422054270632e-08,
|
| 274 |
+
0.14972083270549774,
|
| 275 |
+
0.018399246037006378,
|
| 276 |
+
4.318736318964511e-05,
|
| 277 |
+
0.1394825577735901,
|
| 278 |
+
-0.009943442419171333,
|
| 279 |
+
0.05047810822725296,
|
| 280 |
+
-0.11288079619407654,
|
| 281 |
+
-0.08239683508872986,
|
| 282 |
+
4.939647624269128e-05,
|
| 283 |
+
-0.07140836119651794,
|
| 284 |
+
-3.546756488503888e-05,
|
| 285 |
+
-0.2619844675064087,
|
| 286 |
+
-0.19682355225086212,
|
| 287 |
+
0.04883984848856926,
|
| 288 |
+
0.041489358991384506,
|
| 289 |
+
-3.986437513958663e-05,
|
| 290 |
+
-0.015265467576682568,
|
| 291 |
+
-0.0024833392817527056,
|
| 292 |
+
0.015719031915068626,
|
| 293 |
+
0.015553155913949013
|
| 294 |
+
],
|
| 295 |
+
[
|
| 296 |
+
-0.09164544194936752,
|
| 297 |
+
-0.020419778302311897,
|
| 298 |
+
-1.6692949429852888e-05,
|
| 299 |
+
1.7647056665737182e-05,
|
| 300 |
+
0.002488643629476428,
|
| 301 |
+
0.027437882497906685,
|
| 302 |
+
-2.8264359571039677e-05,
|
| 303 |
+
-0.03701603412628174,
|
| 304 |
+
0.009159324690699577,
|
| 305 |
+
-0.020621521398425102,
|
| 306 |
+
0.03447571396827698,
|
| 307 |
+
0.0011249551316723228,
|
| 308 |
+
5.2376475650817156e-05,
|
| 309 |
+
0.017352906987071037,
|
| 310 |
+
-6.795644367230125e-06,
|
| 311 |
+
0.008722764439880848,
|
| 312 |
+
0.01097520999610424,
|
| 313 |
+
-0.0790662169456482,
|
| 314 |
+
-0.01081581600010395,
|
| 315 |
+
4.761465243063867e-05,
|
| 316 |
+
0.00738158356398344,
|
| 317 |
+
0.005967006087303162,
|
| 318 |
+
-0.009170559234917164,
|
| 319 |
+
-0.027141228318214417
|
| 320 |
+
],
|
| 321 |
+
[
|
| 322 |
+
0.1246870830655098,
|
| 323 |
+
0.016494568437337875,
|
| 324 |
+
-3.6376790376380086e-05,
|
| 325 |
+
2.020174724748358e-05,
|
| 326 |
+
0.05191154405474663,
|
| 327 |
+
0.03699144348502159,
|
| 328 |
+
-1.3433265849016607e-05,
|
| 329 |
+
-0.05896291136741638,
|
| 330 |
+
-0.03726135939359665,
|
| 331 |
+
0.044923651963472366,
|
| 332 |
+
-0.06443153321743011,
|
| 333 |
+
0.024894172325730324,
|
| 334 |
+
-2.8819398721680045e-05,
|
| 335 |
+
-0.06437183916568756,
|
| 336 |
+
-3.1028001103550196e-05,
|
| 337 |
+
0.10513761639595032,
|
| 338 |
+
-0.040632519870996475,
|
| 339 |
+
0.15700025856494904,
|
| 340 |
+
0.02873876690864563,
|
| 341 |
+
2.544223389122635e-05,
|
| 342 |
+
-0.050497379153966904,
|
| 343 |
+
-0.0029438186902552843,
|
| 344 |
+
-0.01204095222055912,
|
| 345 |
+
-0.0032614609226584435
|
| 346 |
+
],
|
| 347 |
+
[
|
| 348 |
+
-0.108024001121521,
|
| 349 |
+
-0.028248196467757225,
|
| 350 |
+
2.2672298655379564e-05,
|
| 351 |
+
3.978270979132503e-05,
|
| 352 |
+
-0.03387359157204628,
|
| 353 |
+
-0.016672611236572266,
|
| 354 |
+
2.4699060304556042e-05,
|
| 355 |
+
0.002938284073024988,
|
| 356 |
+
0.02763514779508114,
|
| 357 |
+
-0.026506410911679268,
|
| 358 |
+
0.05401856079697609,
|
| 359 |
+
-0.025770967826247215,
|
| 360 |
+
4.1366132791154087e-05,
|
| 361 |
+
0.04225965589284897,
|
| 362 |
+
3.5108641895931214e-05,
|
| 363 |
+
-0.042118534445762634,
|
| 364 |
+
0.005915872752666473,
|
| 365 |
+
-0.13225020468235016,
|
| 366 |
+
-0.030211828649044037,
|
| 367 |
+
-5.136957042850554e-05,
|
| 368 |
+
0.05410256236791611,
|
| 369 |
+
0.0035985622089356184,
|
| 370 |
+
0.004466131795197725,
|
| 371 |
+
-0.009501196444034576
|
| 372 |
+
],
|
| 373 |
+
[
|
| 374 |
+
0.07347481697797775,
|
| 375 |
+
-0.02266073226928711,
|
| 376 |
+
5.2228133426979184e-05,
|
| 377 |
+
4.62813040940091e-05,
|
| 378 |
+
-0.11873267590999603,
|
| 379 |
+
-0.09743958711624146,
|
| 380 |
+
4.904656088910997e-05,
|
| 381 |
+
0.1482430398464203,
|
| 382 |
+
-0.044910795986652374,
|
| 383 |
+
0.2667579650878906,
|
| 384 |
+
-0.09406531602144241,
|
| 385 |
+
-0.08873501420021057,
|
| 386 |
+
-3.744564310181886e-05,
|
| 387 |
+
0.17381106317043304,
|
| 388 |
+
-2.094046794809401e-05,
|
| 389 |
+
0.3961288332939148,
|
| 390 |
+
-0.06043681502342224,
|
| 391 |
+
0.24953748285770416,
|
| 392 |
+
0.1394886076450348,
|
| 393 |
+
2.5415887648705393e-05,
|
| 394 |
+
-0.33052584528923035,
|
| 395 |
+
-0.007915235124528408,
|
| 396 |
+
0.013453835621476173,
|
| 397 |
+
0.11794132739305496
|
| 398 |
+
],
|
| 399 |
+
[
|
| 400 |
+
0.03664092719554901,
|
| 401 |
+
0.18091842532157898,
|
| 402 |
+
-4.797168367076665e-05,
|
| 403 |
+
4.716057446785271e-05,
|
| 404 |
+
-0.1518329530954361,
|
| 405 |
+
-0.04683017358183861,
|
| 406 |
+
4.785861528944224e-05,
|
| 407 |
+
-0.09540998190641403,
|
| 408 |
+
0.01912587322294712,
|
| 409 |
+
0.10115578025579453,
|
| 410 |
+
-0.026265788823366165,
|
| 411 |
+
-0.10423006862401962,
|
| 412 |
+
-4.515917680691928e-05,
|
| 413 |
+
0.20828509330749512,
|
| 414 |
+
-5.7712546549737453e-05,
|
| 415 |
+
-0.1024600937962532,
|
| 416 |
+
0.3419700264930725,
|
| 417 |
+
-0.023042183369398117,
|
| 418 |
+
0.17009925842285156,
|
| 419 |
+
4.6127388486638665e-05,
|
| 420 |
+
0.22005531191825867,
|
| 421 |
+
0.0006003690650686622,
|
| 422 |
+
0.07457850128412247,
|
| 423 |
+
0.03790649399161339
|
| 424 |
+
]
|
| 425 |
+
],
|
| 426 |
+
"b1": [
|
| 427 |
+
-0.5934574007987976,
|
| 428 |
+
1.7688686847686768,
|
| 429 |
+
1.6331863403320312,
|
| 430 |
+
0.6320905685424805,
|
| 431 |
+
-1.6366946697235107,
|
| 432 |
+
0.45766252279281616,
|
| 433 |
+
-0.014123601838946342,
|
| 434 |
+
-0.08012986928224564,
|
| 435 |
+
-0.3310701847076416,
|
| 436 |
+
-0.44332027435302734,
|
| 437 |
+
-0.9740999937057495,
|
| 438 |
+
0.35315409302711487,
|
| 439 |
+
0.417784720659256,
|
| 440 |
+
-0.14263728260993958,
|
| 441 |
+
0.40707024931907654,
|
| 442 |
+
0.3663896918296814
|
| 443 |
+
],
|
| 444 |
+
"w2": [
|
| 445 |
+
0.7841601967811584,
|
| 446 |
+
-0.5244224667549133,
|
| 447 |
+
-0.6873168349266052,
|
| 448 |
+
0.8126538395881653,
|
| 449 |
+
0.8223074674606323,
|
| 450 |
+
-0.6758157014846802,
|
| 451 |
+
-0.19274172186851501,
|
| 452 |
+
0.641558825969696,
|
| 453 |
+
-0.6333699822425842,
|
| 454 |
+
0.18355154991149902,
|
| 455 |
+
0.42537039518356323,
|
| 456 |
+
-0.15498623251914978,
|
| 457 |
+
0.29152750968933105,
|
| 458 |
+
-0.23573102056980133,
|
| 459 |
+
0.6270305514335632,
|
| 460 |
+
0.41381654143333435
|
| 461 |
+
],
|
| 462 |
+
"b2": -0.06786282360553741,
|
| 463 |
+
"mu": [
|
| 464 |
+
-5.227207906607518,
|
| 465 |
+
-0.8422915469418415,
|
| 466 |
+
0.0,
|
| 467 |
+
0.0,
|
| 468 |
+
0.06320372316468999,
|
| 469 |
+
0.9945053295301006,
|
| 470 |
+
0.0,
|
| 471 |
+
0.03328829505079317,
|
| 472 |
+
0.004113496472001201,
|
| 473 |
+
0.06248311064404744,
|
| 474 |
+
0.01726467497372767,
|
| 475 |
+
0.0058749937446829804,
|
| 476 |
+
0.0,
|
| 477 |
+
0.46547627983786216,
|
| 478 |
+
0.0,
|
| 479 |
+
0.8586198268528249,
|
| 480 |
+
0.28142605827852935,
|
| 481 |
+
-3.7420752639781365,
|
| 482 |
+
-0.6289379733718058,
|
| 483 |
+
0.0,
|
| 484 |
+
0.7304234069567472,
|
| 485 |
+
0.0003402892458589801,
|
| 486 |
+
0.0018615823449932443,
|
| 487 |
+
0.0005004253615573238
|
| 488 |
+
],
|
| 489 |
+
"sd": [
|
| 490 |
+
1.8052377132935122,
|
| 491 |
+
0.549715606696829,
|
| 492 |
+
1e-06,
|
| 493 |
+
1e-06,
|
| 494 |
+
0.2433300211683481,
|
| 495 |
+
0.07392311486649306,
|
| 496 |
+
1e-06,
|
| 497 |
+
0.17938936211796294,
|
| 498 |
+
0.06400549686371873,
|
| 499 |
+
0.2420319309327287,
|
| 500 |
+
0.13025692490079885,
|
| 501 |
+
0.07642402135598905,
|
| 502 |
+
1e-06,
|
| 503 |
+
0.2880909253656169,
|
| 504 |
+
1e-06,
|
| 505 |
+
0.3484142887647117,
|
| 506 |
+
0.2384648076717676,
|
| 507 |
+
1.9471261794389574,
|
| 508 |
+
0.5453126573397205,
|
| 509 |
+
1e-06,
|
| 510 |
+
0.18576650509517462,
|
| 511 |
+
0.01844479161365384,
|
| 512 |
+
0.043106879600848774,
|
| 513 |
+
0.022365591121132802
|
| 514 |
+
],
|
| 515 |
+
"feats": [
|
| 516 |
+
"sc",
|
| 517 |
+
"scn",
|
| 518 |
+
"inlex",
|
| 519 |
+
"uni",
|
| 520 |
+
"free0",
|
| 521 |
+
"infree",
|
| 522 |
+
"incon",
|
| 523 |
+
"aw",
|
| 524 |
+
"visarga",
|
| 525 |
+
"nukta",
|
| 526 |
+
"chandra",
|
| 527 |
+
"acro",
|
| 528 |
+
"variant",
|
| 529 |
+
"frank",
|
| 530 |
+
"skel",
|
| 531 |
+
"skmatch",
|
| 532 |
+
"lev",
|
| 533 |
+
"sc_rel",
|
| 534 |
+
"scn_rel",
|
| 535 |
+
"uni_rel",
|
| 536 |
+
"lenr",
|
| 537 |
+
"visr",
|
| 538 |
+
"hfin",
|
| 539 |
+
"acro_nv"
|
| 540 |
+
],
|
| 541 |
+
"rerank_hid": 16,
|
| 542 |
+
"reranker_fit_on": "Aksharantar hin_valid (all distinct romans)",
|
| 543 |
+
"val_rerank_cv2": 53.92
|
| 544 |
+
}
|
model/xlit.q4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cf8ff5255105f556b1865c9db1c837bdafaa8b1b93c9e3e5e6e38afb994e34e2
|
| 3 |
+
size 588891
|
sw.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// AksharaLP Space — offline cache (cache-first for app shell + core model files).
|
| 2 |
+
// The dictionary pack (model/dict/) is cached by the runtime itself (Cache API "aksharalp-dict"), so it is left alone here.
|
| 3 |
+
const CACHE = "aksharalp-v2", DICT_CACHE = "aksharalp-dict";
|
| 4 |
+
const SHELL = ["./", "./index.html", "./css/app.css", "./js/app.js", "./js/worker.js", "./js/aksharalp.mjs",
|
| 5 |
+
"./fonts/Inter-var.woff2", "./fonts/NotoSansDevanagari-var.woff2", "./assets/favicon.svg", "./model/manifest.json"];
|
| 6 |
+
|
| 7 |
+
self.addEventListener("install", (e) => {
|
| 8 |
+
e.waitUntil((async () => {
|
| 9 |
+
const c = await caches.open(CACHE);
|
| 10 |
+
await c.addAll(SHELL);
|
| 11 |
+
try { // precache exactly the files the bundle manifest references
|
| 12 |
+
const man = await (await c.match("./model/manifest.json")).json();
|
| 13 |
+
await c.addAll(Object.values(man.files).filter(Boolean).map((f) => "./model/" + f));
|
| 14 |
+
} catch (_) {}
|
| 15 |
+
self.skipWaiting();
|
| 16 |
+
})());
|
| 17 |
+
});
|
| 18 |
+
self.addEventListener("activate", (e) => e.waitUntil((async () => {
|
| 19 |
+
for (const k of await caches.keys()) if (k !== CACHE && k !== DICT_CACHE) await caches.delete(k);
|
| 20 |
+
await self.clients.claim();
|
| 21 |
+
})()));
|
| 22 |
+
self.addEventListener("fetch", (e) => {
|
| 23 |
+
const u = new URL(e.request.url);
|
| 24 |
+
if (e.request.method !== "GET" || u.origin !== location.origin || u.pathname.includes("/model/dict/")) return;
|
| 25 |
+
e.respondWith((async () => {
|
| 26 |
+
const c = await caches.open(CACHE);
|
| 27 |
+
const hit = await c.match(e.request, { ignoreSearch: true });
|
| 28 |
+
if (hit) return hit;
|
| 29 |
+
const r = await fetch(e.request);
|
| 30 |
+
if (r.ok) c.put(e.request, r.clone());
|
| 31 |
+
return r;
|
| 32 |
+
})());
|
| 33 |
+
});
|