Upload folder using huggingface_hub
Browse files- .gitattributes +1 -34
- .gitignore +5 -0
- CITATION.cff +10 -0
- LICENSE +204 -0
- NOTICE +14 -0
- README.md +294 -0
- SHA256SUMS +27 -0
- UPLOAD.md +29 -0
- assets/veritiana-prompt-classifier-architecture.png +3 -0
- classifier-meta.json +73 -0
- config.json +63 -0
- dataset-manifest.json +88 -0
- evaluation.json +229 -0
- examples/browser/README.md +10 -0
- examples/browser/index.html +13 -0
- examples/browser/package.json +17 -0
- examples/browser/src/main.js +75 -0
- examples/browser/src/style.css +1 -0
- examples/python/classify.py +54 -0
- features.py +57 -0
- model.onnx +3 -0
- prepare_training_set.py +77 -0
- requirements-inference.txt +3 -0
- requirements-training.txt +4 -0
- requirements-upload.txt +1 -0
- train.py +136 -0
- training-config.json +61 -0
- upload_to_hub.py +27 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
node_modules/
|
| 5 |
+
dist/
|
CITATION.cff
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cff-version: 1.2.0
|
| 2 |
+
title: Veritiana Prompt Task & Complexity Classifier
|
| 3 |
+
message: If you use this model, please cite this software release.
|
| 4 |
+
type: software
|
| 5 |
+
authors:
|
| 6 |
+
- name: Veritiana AI
|
| 7 |
+
version: 3.1.0
|
| 8 |
+
date-released: 2026-08-05
|
| 9 |
+
license: Apache-2.0
|
| 10 |
+
url: https://www.veritiana.com/prompt_classifier.html
|
LICENSE
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent 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 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright [yyyy] [name of copyright owner]
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
| 203 |
+
|
| 204 |
+
Copyright 2026 Veritiana
|
NOTICE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Veritiana Prompt Task & Complexity Classifier v3.1.0
|
| 2 |
+
Copyright 2026 Veritiana
|
| 3 |
+
|
| 4 |
+
Model and software release license: Apache License 2.0.
|
| 5 |
+
|
| 6 |
+
Training sources used by the recorded preparation run:
|
| 7 |
+
- OpenAssistant/oasst1 — Apache License 2.0
|
| 8 |
+
- grammarly/coedit — Apache License 2.0
|
| 9 |
+
- evalplus/mbppplus — Apache License 2.0
|
| 10 |
+
- google/IFEval — Apache License 2.0
|
| 11 |
+
|
| 12 |
+
The source datasets are not redistributed in this repository. Their original authors retain attribution and rights in their respective works. Training used prompt/instruction fields only as described in dataset-manifest.json.
|
| 13 |
+
|
| 14 |
+
Provenance limitation: the exact Hugging Face dataset revisions were not captured by the original download run. Exact reproduction of the released ONNX SHA-256 therefore requires the archived dataset.jsonl whose SHA-256 is recorded in dataset-manifest.json.
|
README.md
CHANGED
|
@@ -1,3 +1,297 @@
|
|
| 1 |
---
|
| 2 |
license: apache-2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
pipeline_tag: text-classification
|
| 6 |
+
inference: false
|
| 7 |
+
tags:
|
| 8 |
+
- onnx
|
| 9 |
+
- onnxruntime
|
| 10 |
+
- browser
|
| 11 |
+
- local-inference
|
| 12 |
+
- prompt-classification
|
| 13 |
+
- task-classification
|
| 14 |
+
- complexity-estimation
|
| 15 |
+
- ai-routing
|
| 16 |
+
- green-ai
|
| 17 |
+
- veritiana
|
| 18 |
+
datasets:
|
| 19 |
+
- OpenAssistant/oasst1
|
| 20 |
+
- grammarly/coedit
|
| 21 |
+
- evalplus/mbppplus
|
| 22 |
+
- google/IFEval
|
| 23 |
+
metrics:
|
| 24 |
+
- accuracy
|
| 25 |
+
- f1
|
| 26 |
---
|
| 27 |
+
|
| 28 |
+
# Veritiana Prompt Task & Complexity Classifier
|
| 29 |
+
|
| 30 |
+

|
| 31 |
+
|
| 32 |
+
A compact ONNX classifier from **Veritiana AI** that identifies the type of work requested by an AI prompt and estimates its complexity **before generative execution begins**.
|
| 33 |
+
|
| 34 |
+
The model runs locally, including directly in a browser through ONNX Runtime Web. It does not generate text and does not require prompt content to be sent to a remote classification service.
|
| 35 |
+
|
| 36 |
+
**Live browser test:** https://www.veritiana.com/prompt_classifier.html
|
| 37 |
+
|
| 38 |
+
## What it returns
|
| 39 |
+
|
| 40 |
+
The model produces two independent probability distributions.
|
| 41 |
+
|
| 42 |
+
### Task — 9 classes
|
| 43 |
+
|
| 44 |
+
`general_chat`, `writing`, `translation`, `summarization`, `research`, `coding`, `mathematics`, `document_analysis`, `high_stakes`
|
| 45 |
+
|
| 46 |
+
### Complexity — 3 classes
|
| 47 |
+
|
| 48 |
+
`low`, `medium`, `high`
|
| 49 |
+
|
| 50 |
+
Example result:
|
| 51 |
+
|
| 52 |
+
```text
|
| 53 |
+
task: coding
|
| 54 |
+
complexity: high
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
## Intended role
|
| 58 |
+
|
| 59 |
+
This release is a public recognition layer, not a complete AI router.
|
| 60 |
+
|
| 61 |
+
```text
|
| 62 |
+
Prompt
|
| 63 |
+
→ local feature extraction
|
| 64 |
+
→ ONNX task and complexity classifier
|
| 65 |
+
→ probabilities and confidence
|
| 66 |
+
→ future routing policy
|
| 67 |
+
→ model, tools, context, safeguards and budget
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
The open model answers **what kind of request this is** and **how demanding it appears**. Commercial routing value begins when those signals are combined with provider capabilities, prices, latency, organizational policies, tool access, execution quality and feedback history to decide how the request should be executed.
|
| 71 |
+
|
| 72 |
+
The classifier is also part of the product direction behind **Veritiana AI Meter**, where local recognition helps distinguish the type and estimated complexity of visible AI work.
|
| 73 |
+
|
| 74 |
+
## Model architecture
|
| 75 |
+
|
| 76 |
+
The input is a fixed vector of 1,544 float32 features:
|
| 77 |
+
|
| 78 |
+
- 1,024 hashed word and word-bigram bins
|
| 79 |
+
- 512 hashed character-trigram bins
|
| 80 |
+
- 8 numerical and structural features
|
| 81 |
+
|
| 82 |
+
Two independent multinomial logistic-regression heads produce task and complexity probabilities.
|
| 83 |
+
|
| 84 |
+
```text
|
| 85 |
+
input
|
| 86 |
+
features float32 [batch, 1544]
|
| 87 |
+
|
| 88 |
+
outputs
|
| 89 |
+
task_probabilities float32 [batch, 9]
|
| 90 |
+
complexity_probabilities float32 [batch, 3]
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
The released ONNX model is approximately 75 KB and uses ONNX opset 13.
|
| 94 |
+
|
| 95 |
+
## Feature contract
|
| 96 |
+
|
| 97 |
+
The feature extractor is part of the model contract. Raw text cannot be passed directly to `model.onnx`.
|
| 98 |
+
|
| 99 |
+
The repository includes the exact implementation in `features.py`, with matching browser logic in `examples/browser/src/main.js`.
|
| 100 |
+
|
| 101 |
+
The eight numerical features encode:
|
| 102 |
+
|
| 103 |
+
1. normalized character length
|
| 104 |
+
2. normalized word count
|
| 105 |
+
3. question-mark count
|
| 106 |
+
4. newline count
|
| 107 |
+
5. technical-symbol count
|
| 108 |
+
6. URL presence
|
| 109 |
+
7. document/file-term presence
|
| 110 |
+
8. constant bias value
|
| 111 |
+
|
| 112 |
+
Hashing uses FNV-1a 32-bit over JavaScript UTF-16 code units so Python and browser implementations remain compatible.
|
| 113 |
+
|
| 114 |
+
## Internal evaluation
|
| 115 |
+
|
| 116 |
+
The recorded internal split contains 1,287 examples.
|
| 117 |
+
|
| 118 |
+
| Output | Accuracy | Macro-F1 |
|
| 119 |
+
|---|---:|---:|
|
| 120 |
+
| Task | 91.22% | 91.04% |
|
| 121 |
+
| Complexity | 86.79% | 87.24% |
|
| 122 |
+
|
| 123 |
+
These are **internal weak-label evaluation results**, not independently established real-world accuracy.
|
| 124 |
+
|
| 125 |
+
Important limitations:
|
| 126 |
+
|
| 127 |
+
- labels include source-fixed labels, deterministic weak rules and deterministic lexical augmentation
|
| 128 |
+
- augmented rows are variants, not independent human examples
|
| 129 |
+
- minority-class support is uneven
|
| 130 |
+
- the translation test support is only 4 examples and its reported score is not meaningful as a production claim
|
| 131 |
+
- multilingual behavior has not been independently benchmarked
|
| 132 |
+
- the classifier does not semantically reason like a large language model
|
| 133 |
+
|
| 134 |
+
Full per-class reports and confusion matrices are in `evaluation.json`.
|
| 135 |
+
|
| 136 |
+
## Training data
|
| 137 |
+
|
| 138 |
+
The original normalized import contained 19,087 prompts:
|
| 139 |
+
|
| 140 |
+
| Source | Imported rows | Recorded use |
|
| 141 |
+
|---|---:|---|
|
| 142 |
+
| OpenAssistant/oasst1 | 10,170 | filtered root prompter messages |
|
| 143 |
+
| grammarly/coedit | 8,000 | source text, task fixed to writing |
|
| 144 |
+
| evalplus/mbppplus | 376 | prompt field, task fixed to coding |
|
| 145 |
+
| google/IFEval | 541 | prompt field, weak task labels and instruction-count complexity signal |
|
| 146 |
+
|
| 147 |
+
After filtering, balancing and deterministic augmentation, the prepared set contained 6,349 rows.
|
| 148 |
+
|
| 149 |
+
The datasets themselves are not redistributed. Data provenance, row counts, SHA-256 values and the known revision limitation are documented in `dataset-manifest.json`.
|
| 150 |
+
|
| 151 |
+
## Browser use
|
| 152 |
+
|
| 153 |
+
A complete minimal Vite example is included in `examples/browser`.
|
| 154 |
+
|
| 155 |
+
```bash
|
| 156 |
+
cd examples/browser
|
| 157 |
+
npm install
|
| 158 |
+
npm run dev
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
The example loads `model.onnx`, reproduces the 1,544-feature contract and prints both probability distributions.
|
| 162 |
+
|
| 163 |
+
For the complete production interface, use the live Veritiana test:
|
| 164 |
+
|
| 165 |
+
https://www.veritiana.com/prompt_classifier.html
|
| 166 |
+
|
| 167 |
+
## Python use
|
| 168 |
+
|
| 169 |
+
```bash
|
| 170 |
+
python -m venv .venv
|
| 171 |
+
source .venv/bin/activate
|
| 172 |
+
pip install -r requirements-inference.txt
|
| 173 |
+
python examples/python/classify.py "Refactor this API and add rollback tests."
|
| 174 |
+
```
|
| 175 |
+
|
| 176 |
+
Expected output structure:
|
| 177 |
+
|
| 178 |
+
```json
|
| 179 |
+
{
|
| 180 |
+
"task": {
|
| 181 |
+
"label": "coding",
|
| 182 |
+
"confidence": 0.0,
|
| 183 |
+
"probabilities": {}
|
| 184 |
+
},
|
| 185 |
+
"complexity": {
|
| 186 |
+
"label": "high",
|
| 187 |
+
"confidence": 0.0,
|
| 188 |
+
"probabilities": {}
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
The numerical values depend on the supplied prompt. The example does not send data to an external service.
|
| 194 |
+
|
| 195 |
+
## Reproducing training
|
| 196 |
+
|
| 197 |
+
Exact reproduction requires either:
|
| 198 |
+
|
| 199 |
+
- `dataset.jsonl` with SHA-256 `1d56520b25809488fa8be91bcd14219accdb31146e1ca56686ff805d34c21649`, or
|
| 200 |
+
- prepared `training-balanced.jsonl` with SHA-256 `ab2665fcd75800b2350593b7af4222e81d8cc93a34f2bf67320514a92526f44c`.
|
| 201 |
+
|
| 202 |
+
The datasets are not included in this repository.
|
| 203 |
+
|
| 204 |
+
```bash
|
| 205 |
+
python -m venv .venv
|
| 206 |
+
source .venv/bin/activate
|
| 207 |
+
pip install -r requirements-training.txt
|
| 208 |
+
|
| 209 |
+
python prepare_training_set.py dataset.jsonl \
|
| 210 |
+
--output training-balanced.jsonl \
|
| 211 |
+
--report training-balanced-report.json \
|
| 212 |
+
--seed 42 \
|
| 213 |
+
--confidence 0.65 \
|
| 214 |
+
--target-per-task 800 \
|
| 215 |
+
--max-per-task 2000
|
| 216 |
+
|
| 217 |
+
python train.py training-balanced.jsonl \
|
| 218 |
+
--output-dir reproduced-output \
|
| 219 |
+
--version 3.1.0-multisource-balanced \
|
| 220 |
+
--test-size 0.20 \
|
| 221 |
+
--seed 42 \
|
| 222 |
+
--c 4.0
|
| 223 |
+
```
|
| 224 |
+
|
| 225 |
+
Reference model SHA-256:
|
| 226 |
+
|
| 227 |
+
```text
|
| 228 |
+
dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572
|
| 229 |
+
```
|
| 230 |
+
|
| 231 |
+
Exact byte reproduction can also depend on the numerical environment and BLAS implementation. The feature contract and output probabilities are the primary compatibility target.
|
| 232 |
+
|
| 233 |
+
## Repository contents
|
| 234 |
+
|
| 235 |
+
```text
|
| 236 |
+
README.md
|
| 237 |
+
model.onnx
|
| 238 |
+
config.json
|
| 239 |
+
classifier-meta.json
|
| 240 |
+
evaluation.json
|
| 241 |
+
dataset-manifest.json
|
| 242 |
+
training-config.json
|
| 243 |
+
features.py
|
| 244 |
+
prepare_training_set.py
|
| 245 |
+
train.py
|
| 246 |
+
requirements-inference.txt
|
| 247 |
+
requirements-training.txt
|
| 248 |
+
LICENSE
|
| 249 |
+
NOTICE
|
| 250 |
+
assets/
|
| 251 |
+
veritiana-prompt-classifier-architecture.png
|
| 252 |
+
examples/
|
| 253 |
+
python/
|
| 254 |
+
browser/
|
| 255 |
+
upload_to_hub.py
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
## Appropriate uses
|
| 259 |
+
|
| 260 |
+
- local prompt analytics
|
| 261 |
+
- task-distribution measurement
|
| 262 |
+
- complexity estimation
|
| 263 |
+
- pre-routing signals
|
| 264 |
+
- browser-native AI usage instrumentation
|
| 265 |
+
- research and prototyping around deterministic pre-LLM decision layers
|
| 266 |
+
|
| 267 |
+
## Out-of-scope uses
|
| 268 |
+
|
| 269 |
+
Do not use the classifier as:
|
| 270 |
+
|
| 271 |
+
- a medical, legal, financial or safety decision maker
|
| 272 |
+
- proof that a prompt is safe
|
| 273 |
+
- a factual-answer evaluator
|
| 274 |
+
- an authorization layer
|
| 275 |
+
- a universal language detector
|
| 276 |
+
- a guaranteed model-selection engine
|
| 277 |
+
- a replacement for human review in high-stakes workflows
|
| 278 |
+
|
| 279 |
+
## Privacy
|
| 280 |
+
|
| 281 |
+
Inference can run entirely on the user device. The model itself does not upload, store or transmit prompt content. Integrators remain responsible for the behavior of the surrounding application.
|
| 282 |
+
|
| 283 |
+
## License
|
| 284 |
+
|
| 285 |
+
The model and repository code are released under Apache License 2.0. See `LICENSE` and `NOTICE`.
|
| 286 |
+
|
| 287 |
+
## Citation
|
| 288 |
+
|
| 289 |
+
```bibtex
|
| 290 |
+
@software{veritiana_prompt_classifier_2026,
|
| 291 |
+
title = {Veritiana Prompt Task and Complexity Classifier},
|
| 292 |
+
author = {Veritiana AI},
|
| 293 |
+
year = {2026},
|
| 294 |
+
version = {3.1.0},
|
| 295 |
+
url = {https://www.veritiana.com/prompt_classifier.html}
|
| 296 |
+
}
|
| 297 |
+
```
|
SHA256SUMS
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ffda9ef77ab85b9d12041edee241d106a4761b93a25ab5c312eb16450c844080 .gitattributes
|
| 2 |
+
123fc16609d7b9cc84dabfd9ddd304b9d5b729a52efc6bcf4cec58fdfc2a7624 .gitignore
|
| 3 |
+
7b959ae91f75e218db985d565a35abed62dbf4fa1a1573be3d7484e0f01190a1 CITATION.cff
|
| 4 |
+
601ee540b197abb7f596f6138cc2845158b48bbad1afd364e0aef3a745fe8153 LICENSE
|
| 5 |
+
0e2951233817f9692d784c33f5206f3120e8dbf5fdddf187d32f32a2f1bebf39 NOTICE
|
| 6 |
+
55e89f0b8919d40e57bf52ae8785cce815c74d26df858f8aea88786fe231f536 README.md
|
| 7 |
+
561550c1010619147e6190604adb0f239068eae27439e578c04102b0b2d410b6 UPLOAD.md
|
| 8 |
+
5b533b27eea3e364070f5fb31c1bcab73efcbe02c5a31244c187954fd6845a9c assets/veritiana-prompt-classifier-architecture.png
|
| 9 |
+
794da8ad12b6382117724f9ef84ee7a4869090d604b7ca4b98d32dfc2a781a05 classifier-meta.json
|
| 10 |
+
05c2cc137b882f2fcd787a37a5044da7e162b4bcfc987b5060a89aebde137fac config.json
|
| 11 |
+
cb9e983f679a87479bf4f5cbe47ebcc816a1cb8f31ba8ccfbd0b7f3c856317c1 dataset-manifest.json
|
| 12 |
+
163c7c98362e88a7a6cce2f6523d6f64f58a1f19afe2b0e09d69e319244c4986 evaluation.json
|
| 13 |
+
4aeeafe4041d6489ae6c7caa81802ad48cd0734992f47f5e1d0d669e012489e4 examples/browser/README.md
|
| 14 |
+
5b3ebb10fd2817dca98f6d8a8278062c3d6574ea3f97fc57a1d8a502f4315c08 examples/browser/index.html
|
| 15 |
+
6df3e570901c32423204c6eb672387677840c8226712e221ab259c220fa48f42 examples/browser/package.json
|
| 16 |
+
aa0fefc04cfe62222760b44cadfbf63a519f58ed4de799ac23ca0efb045a9fb2 examples/browser/src/main.js
|
| 17 |
+
e5b1fea5c12849246fb69ce467d0dc38f892bcb7f65ddf1c3af7a1a001a61489 examples/browser/src/style.css
|
| 18 |
+
2e8b8142dc7f29326fa98ca3b2ad43a7e6e8aa07ea7c6bf00bb4232508a8a7f7 examples/python/classify.py
|
| 19 |
+
f232bf95cdb53088b1dc15df7b6a0ca174ba04b930b0f0baaa1d1cbb29bdfa15 features.py
|
| 20 |
+
dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572 model.onnx
|
| 21 |
+
3330c8077f015bb153b3865a5994cdc0151f61975a1a46b9c93c948926be9a1c prepare_training_set.py
|
| 22 |
+
ed89e010a3e30b99e4ffb83898328d98fc471573922d4fc734267ac53a8bada5 requirements-inference.txt
|
| 23 |
+
b893fa86c1d13abad802057d4c0702900f321cd0bec41700b756c3bc32e5ac51 requirements-training.txt
|
| 24 |
+
e661b27c32be22e4b3064eb4b46c4e5453c31bc5f0d1983f223cfa48770446ce requirements-upload.txt
|
| 25 |
+
5df357c377930a256c56d2a3acc2b083feae17a6cd82d375d2e9c86f123903b8 train.py
|
| 26 |
+
a3768583ffae24d9b875fe577eb8a44e09614088460a2a5013a8c9427fe2c7a0 training-config.json
|
| 27 |
+
2bcf8d1d7fafb54f440d3a218760fb0847e39e4c639d1a66a404f0e0937e2471 upload_to_hub.py
|
UPLOAD.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Upload instructions
|
| 2 |
+
|
| 3 |
+
Recommended repository ID:
|
| 4 |
+
|
| 5 |
+
```text
|
| 6 |
+
Veritiana-AI/prompt-task-complexity-classifier
|
| 7 |
+
```
|
| 8 |
+
|
| 9 |
+
## Web upload
|
| 10 |
+
|
| 11 |
+
Create a new **Model** repository on Hugging Face and upload the contents of this directory. Upload the files themselves, not the enclosing ZIP directory.
|
| 12 |
+
|
| 13 |
+
## CLI upload
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
python -m venv .venv
|
| 17 |
+
source .venv/bin/activate
|
| 18 |
+
pip install -r requirements-upload.txt
|
| 19 |
+
huggingface-cli login
|
| 20 |
+
python upload_to_hub.py Veritiana-AI/prompt-task-complexity-classifier
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
After upload, confirm:
|
| 24 |
+
|
| 25 |
+
- `README.md` renders the architecture image
|
| 26 |
+
- `model.onnx` SHA-256 is `dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572`
|
| 27 |
+
- the live demo link opens `https://www.veritiana.com/prompt_classifier.html`
|
| 28 |
+
- the license displays as Apache-2.0
|
| 29 |
+
- the repository does not show an automatic inference widget, because raw text requires the custom feature extractor
|
assets/veritiana-prompt-classifier-architecture.png
ADDED
|
Git LFS Details
|
classifier-meta.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model": "Veritiana Prompt Task & Complexity Classifier",
|
| 3 |
+
"version": "3.1.0-multisource-balanced",
|
| 4 |
+
"engine": "ONNX Runtime Web",
|
| 5 |
+
"architecture": "1544 hashed lexical/character/numeric features; dual multinomial logistic heads",
|
| 6 |
+
"input": {
|
| 7 |
+
"name": "features",
|
| 8 |
+
"dtype": "float32",
|
| 9 |
+
"shape": [
|
| 10 |
+
"batch",
|
| 11 |
+
1544
|
| 12 |
+
]
|
| 13 |
+
},
|
| 14 |
+
"outputs": [
|
| 15 |
+
{
|
| 16 |
+
"name": "task_probabilities",
|
| 17 |
+
"dtype": "float32",
|
| 18 |
+
"shape": [
|
| 19 |
+
"batch",
|
| 20 |
+
9
|
| 21 |
+
]
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"name": "complexity_probabilities",
|
| 25 |
+
"dtype": "float32",
|
| 26 |
+
"shape": [
|
| 27 |
+
"batch",
|
| 28 |
+
3
|
| 29 |
+
]
|
| 30 |
+
}
|
| 31 |
+
],
|
| 32 |
+
"task_labels": [
|
| 33 |
+
"general_chat",
|
| 34 |
+
"writing",
|
| 35 |
+
"translation",
|
| 36 |
+
"summarization",
|
| 37 |
+
"research",
|
| 38 |
+
"coding",
|
| 39 |
+
"mathematics",
|
| 40 |
+
"document_analysis",
|
| 41 |
+
"high_stakes"
|
| 42 |
+
],
|
| 43 |
+
"complexity_labels": [
|
| 44 |
+
"low",
|
| 45 |
+
"medium",
|
| 46 |
+
"high"
|
| 47 |
+
],
|
| 48 |
+
"training_data": {
|
| 49 |
+
"sources": [
|
| 50 |
+
"OpenAssistant/oasst1",
|
| 51 |
+
"grammarly/coedit",
|
| 52 |
+
"evalplus/mbppplus",
|
| 53 |
+
"google/IFEval"
|
| 54 |
+
],
|
| 55 |
+
"balanced_rows": 6349,
|
| 56 |
+
"train_rows": 5062,
|
| 57 |
+
"test_rows": 1287,
|
| 58 |
+
"notes": "Low-confidence weak labels excluded; dominant tasks capped; deterministic lexical augmentations grouped with their source during split."
|
| 59 |
+
},
|
| 60 |
+
"validation": {
|
| 61 |
+
"task_accuracy": 0.9121989121989122,
|
| 62 |
+
"task_macro_f1": 0.9103734961055048,
|
| 63 |
+
"complexity_accuracy": 0.8679098679098679,
|
| 64 |
+
"complexity_macro_f1": 0.8723688079771166,
|
| 65 |
+
"runtime": "AI Meter bundled ONNX Runtime Web 1.22.0",
|
| 66 |
+
"runtime_max_abs_diff": 1.1920928955078125e-07
|
| 67 |
+
},
|
| 68 |
+
"onnx_sha256": "dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572",
|
| 69 |
+
"limitations": "Validation uses weak labels and deterministic augmentations. Do not present these metrics as independent human-ground-truth production accuracy.",
|
| 70 |
+
"model_file": "model.onnx",
|
| 71 |
+
"live_demo": "https://www.veritiana.com/prompt_classifier.html",
|
| 72 |
+
"intended_role": "Local task and complexity recognition before generative execution; input signal for future routing policies."
|
| 73 |
+
}
|
config.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "veritiana_prompt_classifier",
|
| 3 |
+
"model_version": "3.1.0-multisource-balanced",
|
| 4 |
+
"architecture": "dual_multinomial_logistic_regression",
|
| 5 |
+
"model_file": "model.onnx",
|
| 6 |
+
"input": {
|
| 7 |
+
"name": "features",
|
| 8 |
+
"dtype": "float32",
|
| 9 |
+
"shape": [
|
| 10 |
+
"batch",
|
| 11 |
+
1544
|
| 12 |
+
]
|
| 13 |
+
},
|
| 14 |
+
"outputs": {
|
| 15 |
+
"task_probabilities": {
|
| 16 |
+
"dtype": "float32",
|
| 17 |
+
"shape": [
|
| 18 |
+
"batch",
|
| 19 |
+
9
|
| 20 |
+
]
|
| 21 |
+
},
|
| 22 |
+
"complexity_probabilities": {
|
| 23 |
+
"dtype": "float32",
|
| 24 |
+
"shape": [
|
| 25 |
+
"batch",
|
| 26 |
+
3
|
| 27 |
+
]
|
| 28 |
+
}
|
| 29 |
+
},
|
| 30 |
+
"features": {
|
| 31 |
+
"total": 1544,
|
| 32 |
+
"word_bigram_bins": 1024,
|
| 33 |
+
"character_trigram_bins": 512,
|
| 34 |
+
"numeric_features": 8,
|
| 35 |
+
"hash": "FNV-1a 32-bit over JavaScript UTF-16 code units"
|
| 36 |
+
},
|
| 37 |
+
"task_labels": [
|
| 38 |
+
"general_chat",
|
| 39 |
+
"writing",
|
| 40 |
+
"translation",
|
| 41 |
+
"summarization",
|
| 42 |
+
"research",
|
| 43 |
+
"coding",
|
| 44 |
+
"mathematics",
|
| 45 |
+
"document_analysis",
|
| 46 |
+
"high_stakes"
|
| 47 |
+
],
|
| 48 |
+
"complexity_labels": [
|
| 49 |
+
"low",
|
| 50 |
+
"medium",
|
| 51 |
+
"high"
|
| 52 |
+
],
|
| 53 |
+
"thresholds": {
|
| 54 |
+
"task_classified": 0.72,
|
| 55 |
+
"complexity_classified": 0.66,
|
| 56 |
+
"likely": 0.45
|
| 57 |
+
},
|
| 58 |
+
"runtime": {
|
| 59 |
+
"browser": "ONNX Runtime Web 1.22.0",
|
| 60 |
+
"onnx_opset": 13
|
| 61 |
+
},
|
| 62 |
+
"live_demo": "https://www.veritiana.com/prompt_classifier.html"
|
| 63 |
+
}
|
dataset-manifest.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"manifest_version": "1.0",
|
| 3 |
+
"model_version": "3.1.0-multisource-balanced",
|
| 4 |
+
"source_dataset": {
|
| 5 |
+
"file": "dataset.jsonl (not redistributed in this release)",
|
| 6 |
+
"sha256": "1d56520b25809488fa8be91bcd14219accdb31146e1ca56686ff805d34c21649",
|
| 7 |
+
"rows": 19087,
|
| 8 |
+
"source_revisions": "Exact Hugging Face revisions were not captured by the original download run."
|
| 9 |
+
},
|
| 10 |
+
"prepared_dataset": {
|
| 11 |
+
"file": "training-balanced.jsonl (not redistributed in this release)",
|
| 12 |
+
"sha256": "ab2665fcd75800b2350593b7af4222e81d8cc93a34f2bf67320514a92526f44c",
|
| 13 |
+
"rows": 6349
|
| 14 |
+
},
|
| 15 |
+
"sources": [
|
| 16 |
+
{
|
| 17 |
+
"name": "OpenAssistant/oasst1",
|
| 18 |
+
"url": "https://huggingface.co/datasets/OpenAssistant/oasst1",
|
| 19 |
+
"license": "Apache-2.0",
|
| 20 |
+
"rows_after_import": 10170,
|
| 21 |
+
"use": "root prompter messages after filters"
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"name": "grammarly/coedit",
|
| 25 |
+
"url": "https://huggingface.co/datasets/grammarly/coedit",
|
| 26 |
+
"license": "Apache-2.0",
|
| 27 |
+
"rows_after_import": 8000,
|
| 28 |
+
"use": "src field only; task fixed to writing"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"name": "evalplus/mbppplus",
|
| 32 |
+
"url": "https://huggingface.co/datasets/evalplus/mbppplus",
|
| 33 |
+
"license": "Apache-2.0",
|
| 34 |
+
"rows_after_import": 376,
|
| 35 |
+
"use": "prompt field only; task fixed to coding"
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"name": "google/IFEval",
|
| 39 |
+
"url": "https://huggingface.co/datasets/google/IFEval",
|
| 40 |
+
"license": "Apache-2.0",
|
| 41 |
+
"rows_after_import": 541,
|
| 42 |
+
"use": "prompt field; weak task labels; instruction count informs complexity"
|
| 43 |
+
}
|
| 44 |
+
],
|
| 45 |
+
"preparation_report": {
|
| 46 |
+
"input_rows": 19087,
|
| 47 |
+
"accepted_rows": 10696,
|
| 48 |
+
"rejected_low_confidence": 8391,
|
| 49 |
+
"output_rows": 6349,
|
| 50 |
+
"confidence_threshold": 0.65,
|
| 51 |
+
"by_task": {
|
| 52 |
+
"writing": 2000,
|
| 53 |
+
"coding": 1228,
|
| 54 |
+
"general_chat": 800,
|
| 55 |
+
"mathematics": 410,
|
| 56 |
+
"summarization": 139,
|
| 57 |
+
"high_stakes": 425,
|
| 58 |
+
"translation": 92,
|
| 59 |
+
"document_analysis": 455,
|
| 60 |
+
"research": 800
|
| 61 |
+
},
|
| 62 |
+
"by_complexity": {
|
| 63 |
+
"low": 4307,
|
| 64 |
+
"medium": 1816,
|
| 65 |
+
"high": 226
|
| 66 |
+
},
|
| 67 |
+
"by_label_method": {
|
| 68 |
+
"source_fixed": 2216,
|
| 69 |
+
"weak_rule": 1810,
|
| 70 |
+
"deterministic_augmentation": 2323
|
| 71 |
+
},
|
| 72 |
+
"augmented_by_task": {
|
| 73 |
+
"general_chat": 575,
|
| 74 |
+
"translation": 74,
|
| 75 |
+
"summarization": 112,
|
| 76 |
+
"research": 526,
|
| 77 |
+
"mathematics": 328,
|
| 78 |
+
"document_analysis": 367,
|
| 79 |
+
"high_stakes": 341
|
| 80 |
+
},
|
| 81 |
+
"warning": "Augmented rows are lexical variants, not independent human examples."
|
| 82 |
+
},
|
| 83 |
+
"model": {
|
| 84 |
+
"file": "model.onnx",
|
| 85 |
+
"sha256": "dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572",
|
| 86 |
+
"bytes": 75346
|
| 87 |
+
}
|
| 88 |
+
}
|
evaluation.json
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"summary": {
|
| 3 |
+
"task_accuracy": 0.9121989121989122,
|
| 4 |
+
"task_macro_f1": 0.9103734961055048,
|
| 5 |
+
"complexity_accuracy": 0.8679098679098679,
|
| 6 |
+
"complexity_macro_f1": 0.8723688079771166,
|
| 7 |
+
"training_seconds": 13.171398878097534
|
| 8 |
+
},
|
| 9 |
+
"task_report": {
|
| 10 |
+
"general_chat": {
|
| 11 |
+
"precision": 0.9310344827586207,
|
| 12 |
+
"recall": 0.9204545454545454,
|
| 13 |
+
"f1-score": 0.9257142857142857,
|
| 14 |
+
"support": 176.0
|
| 15 |
+
},
|
| 16 |
+
"writing": {
|
| 17 |
+
"precision": 0.974025974025974,
|
| 18 |
+
"recall": 0.9566326530612245,
|
| 19 |
+
"f1-score": 0.9652509652509652,
|
| 20 |
+
"support": 392.0
|
| 21 |
+
},
|
| 22 |
+
"translation": {
|
| 23 |
+
"precision": 1.0,
|
| 24 |
+
"recall": 1.0,
|
| 25 |
+
"f1-score": 1.0,
|
| 26 |
+
"support": 4.0
|
| 27 |
+
},
|
| 28 |
+
"summarization": {
|
| 29 |
+
"precision": 0.9655172413793104,
|
| 30 |
+
"recall": 0.9655172413793104,
|
| 31 |
+
"f1-score": 0.9655172413793104,
|
| 32 |
+
"support": 29.0
|
| 33 |
+
},
|
| 34 |
+
"research": {
|
| 35 |
+
"precision": 0.8372093023255814,
|
| 36 |
+
"recall": 0.8944099378881988,
|
| 37 |
+
"f1-score": 0.8648648648648649,
|
| 38 |
+
"support": 161.0
|
| 39 |
+
},
|
| 40 |
+
"coding": {
|
| 41 |
+
"precision": 0.9132231404958677,
|
| 42 |
+
"recall": 0.9057377049180327,
|
| 43 |
+
"f1-score": 0.9094650205761317,
|
| 44 |
+
"support": 244.0
|
| 45 |
+
},
|
| 46 |
+
"mathematics": {
|
| 47 |
+
"precision": 0.8641975308641975,
|
| 48 |
+
"recall": 0.8536585365853658,
|
| 49 |
+
"f1-score": 0.8588957055214724,
|
| 50 |
+
"support": 82.0
|
| 51 |
+
},
|
| 52 |
+
"document_analysis": {
|
| 53 |
+
"precision": 0.8165137614678899,
|
| 54 |
+
"recall": 0.9081632653061225,
|
| 55 |
+
"f1-score": 0.8599033816425121,
|
| 56 |
+
"support": 98.0
|
| 57 |
+
},
|
| 58 |
+
"high_stakes": {
|
| 59 |
+
"precision": 0.8901098901098901,
|
| 60 |
+
"recall": 0.801980198019802,
|
| 61 |
+
"f1-score": 0.84375,
|
| 62 |
+
"support": 101.0
|
| 63 |
+
},
|
| 64 |
+
"accuracy": 0.9121989121989122,
|
| 65 |
+
"macro avg": {
|
| 66 |
+
"precision": 0.9102034803808147,
|
| 67 |
+
"recall": 0.9118393425125113,
|
| 68 |
+
"f1-score": 0.9103734961055048,
|
| 69 |
+
"support": 1287.0
|
| 70 |
+
},
|
| 71 |
+
"weighted avg": {
|
| 72 |
+
"precision": 0.913815881736539,
|
| 73 |
+
"recall": 0.9121989121989122,
|
| 74 |
+
"f1-score": 0.912490699441833,
|
| 75 |
+
"support": 1287.0
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
+
"complexity_report": {
|
| 79 |
+
"low": {
|
| 80 |
+
"precision": 0.9166666666666666,
|
| 81 |
+
"recall": 0.8856476079346558,
|
| 82 |
+
"f1-score": 0.9008902077151335,
|
| 83 |
+
"support": 857.0
|
| 84 |
+
},
|
| 85 |
+
"medium": {
|
| 86 |
+
"precision": 0.7555555555555555,
|
| 87 |
+
"recall": 0.8225806451612904,
|
| 88 |
+
"f1-score": 0.7876447876447876,
|
| 89 |
+
"support": 372.0
|
| 90 |
+
},
|
| 91 |
+
"high": {
|
| 92 |
+
"precision": 0.9629629629629629,
|
| 93 |
+
"recall": 0.896551724137931,
|
| 94 |
+
"f1-score": 0.9285714285714286,
|
| 95 |
+
"support": 58.0
|
| 96 |
+
},
|
| 97 |
+
"accuracy": 0.8679098679098679,
|
| 98 |
+
"macro avg": {
|
| 99 |
+
"precision": 0.878395061728395,
|
| 100 |
+
"recall": 0.8682599924112924,
|
| 101 |
+
"f1-score": 0.8723688079771166,
|
| 102 |
+
"support": 1287.0
|
| 103 |
+
},
|
| 104 |
+
"weighted avg": {
|
| 105 |
+
"precision": 0.8721848110736999,
|
| 106 |
+
"recall": 0.8679098679098679,
|
| 107 |
+
"f1-score": 0.8694047489299714,
|
| 108 |
+
"support": 1287.0
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
"task_confusion_matrix": [
|
| 112 |
+
[
|
| 113 |
+
162,
|
| 114 |
+
2,
|
| 115 |
+
0,
|
| 116 |
+
0,
|
| 117 |
+
1,
|
| 118 |
+
3,
|
| 119 |
+
4,
|
| 120 |
+
0,
|
| 121 |
+
4
|
| 122 |
+
],
|
| 123 |
+
[
|
| 124 |
+
1,
|
| 125 |
+
375,
|
| 126 |
+
0,
|
| 127 |
+
0,
|
| 128 |
+
5,
|
| 129 |
+
10,
|
| 130 |
+
1,
|
| 131 |
+
0,
|
| 132 |
+
0
|
| 133 |
+
],
|
| 134 |
+
[
|
| 135 |
+
0,
|
| 136 |
+
0,
|
| 137 |
+
4,
|
| 138 |
+
0,
|
| 139 |
+
0,
|
| 140 |
+
0,
|
| 141 |
+
0,
|
| 142 |
+
0,
|
| 143 |
+
0
|
| 144 |
+
],
|
| 145 |
+
[
|
| 146 |
+
0,
|
| 147 |
+
0,
|
| 148 |
+
0,
|
| 149 |
+
28,
|
| 150 |
+
0,
|
| 151 |
+
0,
|
| 152 |
+
1,
|
| 153 |
+
0,
|
| 154 |
+
0
|
| 155 |
+
],
|
| 156 |
+
[
|
| 157 |
+
4,
|
| 158 |
+
1,
|
| 159 |
+
0,
|
| 160 |
+
1,
|
| 161 |
+
144,
|
| 162 |
+
3,
|
| 163 |
+
0,
|
| 164 |
+
5,
|
| 165 |
+
3
|
| 166 |
+
],
|
| 167 |
+
[
|
| 168 |
+
3,
|
| 169 |
+
5,
|
| 170 |
+
0,
|
| 171 |
+
0,
|
| 172 |
+
6,
|
| 173 |
+
221,
|
| 174 |
+
0,
|
| 175 |
+
6,
|
| 176 |
+
3
|
| 177 |
+
],
|
| 178 |
+
[
|
| 179 |
+
0,
|
| 180 |
+
0,
|
| 181 |
+
0,
|
| 182 |
+
0,
|
| 183 |
+
4,
|
| 184 |
+
2,
|
| 185 |
+
70,
|
| 186 |
+
6,
|
| 187 |
+
0
|
| 188 |
+
],
|
| 189 |
+
[
|
| 190 |
+
4,
|
| 191 |
+
0,
|
| 192 |
+
0,
|
| 193 |
+
0,
|
| 194 |
+
5,
|
| 195 |
+
0,
|
| 196 |
+
0,
|
| 197 |
+
89,
|
| 198 |
+
0
|
| 199 |
+
],
|
| 200 |
+
[
|
| 201 |
+
0,
|
| 202 |
+
2,
|
| 203 |
+
0,
|
| 204 |
+
0,
|
| 205 |
+
7,
|
| 206 |
+
3,
|
| 207 |
+
5,
|
| 208 |
+
3,
|
| 209 |
+
81
|
| 210 |
+
]
|
| 211 |
+
],
|
| 212 |
+
"complexity_confusion_matrix": [
|
| 213 |
+
[
|
| 214 |
+
759,
|
| 215 |
+
98,
|
| 216 |
+
0
|
| 217 |
+
],
|
| 218 |
+
[
|
| 219 |
+
64,
|
| 220 |
+
306,
|
| 221 |
+
2
|
| 222 |
+
],
|
| 223 |
+
[
|
| 224 |
+
5,
|
| 225 |
+
1,
|
| 226 |
+
52
|
| 227 |
+
]
|
| 228 |
+
]
|
| 229 |
+
}
|
examples/browser/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Browser example
|
| 2 |
+
|
| 3 |
+
This Vite example performs local ONNX Runtime Web inference and implements the same 1,544-feature contract as the released model.
|
| 4 |
+
|
| 5 |
+
```bash
|
| 6 |
+
npm install
|
| 7 |
+
npm run dev
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
The prompt remains in the browser. No classification API is called.
|
examples/browser/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Veritiana Classifier Example</title></head>
|
| 4 |
+
<body>
|
| 5 |
+
<main>
|
| 6 |
+
<h1>Veritiana Prompt Classifier</h1>
|
| 7 |
+
<textarea id="prompt" rows="8">Refactor this authentication service, preserve API compatibility, migrate the database schema and add rollback tests.</textarea>
|
| 8 |
+
<button id="classify">Classify locally</button>
|
| 9 |
+
<pre id="result">Loading model…</pre>
|
| 10 |
+
</main>
|
| 11 |
+
<script type="module" src="/src/main.js"></script>
|
| 12 |
+
</body>
|
| 13 |
+
</html>
|
examples/browser/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "veritiana-prompt-classifier-browser-example",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "vite build",
|
| 9 |
+
"preview": "vite preview"
|
| 10 |
+
},
|
| 11 |
+
"dependencies": {
|
| 12 |
+
"onnxruntime-web": "1.22.0"
|
| 13 |
+
},
|
| 14 |
+
"devDependencies": {
|
| 15 |
+
"vite": "^7.0.0"
|
| 16 |
+
}
|
| 17 |
+
}
|
examples/browser/src/main.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as ort from "onnxruntime-web";
|
| 2 |
+
import "./style.css";
|
| 3 |
+
|
| 4 |
+
const TASK_LABELS = ["general_chat", "writing", "translation", "summarization", "research", "coding", "mathematics", "document_analysis", "high_stakes"];
|
| 5 |
+
const COMPLEXITY_LABELS = ["low", "medium", "high"];
|
| 6 |
+
const WORD_BINS = 1024;
|
| 7 |
+
const CHAR_BINS = 512;
|
| 8 |
+
const INPUT_SIZE = 1544;
|
| 9 |
+
|
| 10 |
+
function fnv1a(text) {
|
| 11 |
+
let hash = 2166136261;
|
| 12 |
+
for (let i = 0; i < text.length; i += 1) {
|
| 13 |
+
hash ^= text.charCodeAt(i);
|
| 14 |
+
hash = Math.imul(hash, 16777619);
|
| 15 |
+
}
|
| 16 |
+
return hash >>> 0;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
function buildFeatures(text) {
|
| 20 |
+
const source = String(text || "");
|
| 21 |
+
const lower = source.toLocaleLowerCase();
|
| 22 |
+
const values = new Float32Array(INPUT_SIZE);
|
| 23 |
+
const words = lower.match(/[\p{L}\p{N}_]+/gu) || [];
|
| 24 |
+
const grams = [...words];
|
| 25 |
+
for (let i = 0; i + 1 < words.length; i += 1) grams.push(`${words[i]}_${words[i + 1]}`);
|
| 26 |
+
for (const gram of grams) values[fnv1a(gram) % WORD_BINS] += 1;
|
| 27 |
+
|
| 28 |
+
const compact = lower.replace(/\s+/g, " ");
|
| 29 |
+
for (let i = 0; i + 2 < compact.length; i += 1) {
|
| 30 |
+
values[WORD_BINS + (fnv1a(compact.slice(i, i + 3)) % CHAR_BINS)] += 0.25;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
const sparseCount = WORD_BINS + CHAR_BINS;
|
| 34 |
+
let norm = 0;
|
| 35 |
+
for (let i = 0; i < sparseCount; i += 1) norm += values[i] * values[i];
|
| 36 |
+
norm = Math.sqrt(norm);
|
| 37 |
+
if (norm > 0) for (let i = 0; i < sparseCount; i += 1) values[i] /= norm;
|
| 38 |
+
|
| 39 |
+
const base = sparseCount;
|
| 40 |
+
values[base] = Math.min(source.length, 4000) / 4000;
|
| 41 |
+
values[base + 1] = Math.min(words.length, 800) / 800;
|
| 42 |
+
values[base + 2] = Math.min((source.match(/\?/g) || []).length, 10) / 10;
|
| 43 |
+
values[base + 3] = Math.min((source.match(/\n/g) || []).length, 30) / 30;
|
| 44 |
+
values[base + 4] = Math.min((source.match(/[{}[\]();=<>/]/g) || []).length, 100) / 100;
|
| 45 |
+
values[base + 5] = /https?:\/\/|www\./i.test(source) ? 1 : 0;
|
| 46 |
+
values[base + 6] = /\b(pdf|document|dokument|file|súbor|attachment|príloha)\b/i.test(source) ? 1 : 0;
|
| 47 |
+
values[base + 7] = 1;
|
| 48 |
+
return values;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
function argMax(values) {
|
| 52 |
+
let index = 0;
|
| 53 |
+
for (let i = 1; i < values.length; i += 1) if (values[i] > values[index]) index = i;
|
| 54 |
+
return index;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
const result = document.querySelector("#result");
|
| 58 |
+
const modelUrl = new URL("../../../model.onnx", import.meta.url).href;
|
| 59 |
+
ort.env.wasm.numThreads = 1;
|
| 60 |
+
const session = await ort.InferenceSession.create(modelUrl, { executionProviders: ["wasm"] });
|
| 61 |
+
result.textContent = "Model ready.";
|
| 62 |
+
|
| 63 |
+
document.querySelector("#classify").addEventListener("click", async () => {
|
| 64 |
+
const text = document.querySelector("#prompt").value;
|
| 65 |
+
const features = buildFeatures(text);
|
| 66 |
+
const outputs = await session.run({ features: new ort.Tensor("float32", features, [1, INPUT_SIZE]) });
|
| 67 |
+
const task = Array.from(outputs.task_probabilities.data);
|
| 68 |
+
const complexity = Array.from(outputs.complexity_probabilities.data);
|
| 69 |
+
const taskIndex = argMax(task);
|
| 70 |
+
const complexityIndex = argMax(complexity);
|
| 71 |
+
result.textContent = JSON.stringify({
|
| 72 |
+
task: { label: TASK_LABELS[taskIndex], confidence: task[taskIndex], probabilities: Object.fromEntries(TASK_LABELS.map((label, i) => [label, task[i]])) },
|
| 73 |
+
complexity: { label: COMPLEXITY_LABELS[complexityIndex], confidence: complexity[complexityIndex], probabilities: Object.fromEntries(COMPLEXITY_LABELS.map((label, i) => [label, complexity[i]])) }
|
| 74 |
+
}, null, 2);
|
| 75 |
+
});
|
examples/browser/src/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
body{margin:0;background:#06111f;color:#eefbf7;font:16px/1.5 system-ui,sans-serif}main{max-width:850px;margin:60px auto;padding:24px}textarea,pre{box-sizing:border-box;width:100%;border:1px solid #294155;border-radius:12px;background:#0a1928;color:#fff;padding:16px}button{margin:14px 0;padding:12px 18px;border:0;border-radius:9px;background:#24d3a4;color:#06111f;font-weight:800;cursor:pointer}pre{white-space:pre-wrap;overflow:auto}
|
examples/python/classify.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import json
|
| 3 |
+
import sys
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import onnxruntime as ort
|
| 8 |
+
|
| 9 |
+
REPO_ROOT = Path(__file__).resolve().parents[2]
|
| 10 |
+
sys.path.insert(0, str(REPO_ROOT))
|
| 11 |
+
from features import build_features # noqa: E402
|
| 12 |
+
|
| 13 |
+
TASK_LABELS = [
|
| 14 |
+
"general_chat", "writing", "translation", "summarization", "research",
|
| 15 |
+
"coding", "mathematics", "document_analysis", "high_stakes",
|
| 16 |
+
]
|
| 17 |
+
COMPLEXITY_LABELS = ["low", "medium", "high"]
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def distribution(labels, values):
|
| 21 |
+
return {label: float(value) for label, value in zip(labels, values, strict=True)}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def classify(text: str) -> dict:
|
| 25 |
+
model_path = REPO_ROOT / "model.onnx"
|
| 26 |
+
session = ort.InferenceSession(str(model_path), providers=["CPUExecutionProvider"])
|
| 27 |
+
features = build_features(text).astype(np.float32).reshape(1, -1)
|
| 28 |
+
outputs = session.run(None, {"features": features})
|
| 29 |
+
task_probs = outputs[0][0]
|
| 30 |
+
complexity_probs = outputs[1][0]
|
| 31 |
+
task_index = int(np.argmax(task_probs))
|
| 32 |
+
complexity_index = int(np.argmax(complexity_probs))
|
| 33 |
+
return {
|
| 34 |
+
"task": {
|
| 35 |
+
"label": TASK_LABELS[task_index],
|
| 36 |
+
"confidence": float(task_probs[task_index]),
|
| 37 |
+
"probabilities": distribution(TASK_LABELS, task_probs),
|
| 38 |
+
},
|
| 39 |
+
"complexity": {
|
| 40 |
+
"label": COMPLEXITY_LABELS[complexity_index],
|
| 41 |
+
"confidence": float(complexity_probs[complexity_index]),
|
| 42 |
+
"probabilities": distribution(COMPLEXITY_LABELS, complexity_probs),
|
| 43 |
+
},
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def main() -> None:
|
| 48 |
+
if len(sys.argv) < 2:
|
| 49 |
+
raise SystemExit('Usage: python examples/python/classify.py "your prompt"')
|
| 50 |
+
print(json.dumps(classify(" ".join(sys.argv[1:])), indent=2))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
if __name__ == "__main__":
|
| 54 |
+
main()
|
features.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""AI Meter v1.4.9-compatible 1544-dimensional feature extraction."""
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
import re
|
| 5 |
+
from typing import Iterable
|
| 6 |
+
import numpy as np
|
| 7 |
+
import regex
|
| 8 |
+
|
| 9 |
+
WORD_BINS = 1024
|
| 10 |
+
CHAR_BINS = 512
|
| 11 |
+
NUMERIC_FEATURES = 8
|
| 12 |
+
INPUT_SIZE = WORD_BINS + CHAR_BINS + NUMERIC_FEATURES
|
| 13 |
+
|
| 14 |
+
TECH_RE = re.compile(r"[{}\[\]();=<>/]")
|
| 15 |
+
URL_RE = re.compile(r"https?://|www\.", re.I)
|
| 16 |
+
DOC_RE = re.compile(r"\b(pdf|document|dokument|file|súbor|attachment|príloha)\b", re.I)
|
| 17 |
+
|
| 18 |
+
def _utf16_units(text: str) -> Iterable[int]:
|
| 19 |
+
raw = text.encode("utf-16-le", errors="surrogatepass")
|
| 20 |
+
for index in range(0, len(raw), 2):
|
| 21 |
+
yield raw[index] | (raw[index + 1] << 8)
|
| 22 |
+
|
| 23 |
+
def fnv1a_js(text: str) -> int:
|
| 24 |
+
"""32-bit FNV-1a over JavaScript-compatible UTF-16 code units."""
|
| 25 |
+
value = 2166136261
|
| 26 |
+
for unit in _utf16_units(text):
|
| 27 |
+
value ^= unit
|
| 28 |
+
value = (value * 16777619) & 0xFFFFFFFF
|
| 29 |
+
return value
|
| 30 |
+
|
| 31 |
+
def build_features(text: str) -> np.ndarray:
|
| 32 |
+
source = str(text or "")
|
| 33 |
+
lower = source.lower()
|
| 34 |
+
values = np.zeros(INPUT_SIZE, dtype=np.float32)
|
| 35 |
+
words = regex.findall(r"[\p{L}\p{N}_]+", lower)
|
| 36 |
+
grams = list(words)
|
| 37 |
+
grams.extend(f"{words[i]}_{words[i + 1]}" for i in range(len(words) - 1))
|
| 38 |
+
for gram in grams:
|
| 39 |
+
values[fnv1a_js(gram) % WORD_BINS] += 1.0
|
| 40 |
+
compact = regex.sub(r"\s+", " ", lower)
|
| 41 |
+
for index in range(max(0, len(compact) - 2)):
|
| 42 |
+
trigram = compact[index:index + 3]
|
| 43 |
+
values[WORD_BINS + (fnv1a_js(trigram) % CHAR_BINS)] += 0.25
|
| 44 |
+
sparse = values[:WORD_BINS + CHAR_BINS]
|
| 45 |
+
norm = float(np.linalg.norm(sparse))
|
| 46 |
+
if norm > 0:
|
| 47 |
+
sparse /= norm
|
| 48 |
+
base = WORD_BINS + CHAR_BINS
|
| 49 |
+
values[base] = min(len(source), 4000) / 4000
|
| 50 |
+
values[base + 1] = min(len(words), 800) / 800
|
| 51 |
+
values[base + 2] = min(source.count("?"), 10) / 10
|
| 52 |
+
values[base + 3] = min(source.count("\n"), 30) / 30
|
| 53 |
+
values[base + 4] = min(len(TECH_RE.findall(source)), 100) / 100
|
| 54 |
+
values[base + 5] = 1.0 if URL_RE.search(source) else 0.0
|
| 55 |
+
values[base + 6] = 1.0 if DOC_RE.search(source) else 0.0
|
| 56 |
+
values[base + 7] = 1.0
|
| 57 |
+
return values
|
model.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:dca7560742f19207d089d469c2907e7a1b7c06e2bbf14d2404a5d9359043f572
|
| 3 |
+
size 75346
|
prepare_training_set.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
import argparse, json, random, re
|
| 4 |
+
from collections import Counter, defaultdict
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
TASKS=['general_chat','writing','translation','summarization','research','coding','mathematics','document_analysis','high_stakes']
|
| 8 |
+
POLITE_PREFIXES=['Please ','Could you ','I need you to ','Help me to ']
|
| 9 |
+
|
| 10 |
+
def normalize(s): return re.sub(r'\s+',' ',s).strip()
|
| 11 |
+
def variants(text):
|
| 12 |
+
base=normalize(text)
|
| 13 |
+
out=[]
|
| 14 |
+
if base:
|
| 15 |
+
out.append(base)
|
| 16 |
+
if base[0].islower(): out.append(base[0].upper()+base[1:])
|
| 17 |
+
if not base.endswith(('?','.','!')): out.append(base+'.')
|
| 18 |
+
for p in POLITE_PREFIXES:
|
| 19 |
+
if not base.lower().startswith(('please ','could you ','i need you to ','help me to ')):
|
| 20 |
+
out.append(p+base[0].lower()+base[1:])
|
| 21 |
+
seen=[]
|
| 22 |
+
for x in out:
|
| 23 |
+
if x not in seen: seen.append(x)
|
| 24 |
+
return seen
|
| 25 |
+
|
| 26 |
+
def main():
|
| 27 |
+
ap=argparse.ArgumentParser()
|
| 28 |
+
ap.add_argument('input',type=Path)
|
| 29 |
+
ap.add_argument('--output',type=Path,default=Path('data/processed/training-balanced.jsonl'))
|
| 30 |
+
ap.add_argument('--report',type=Path,default=Path('data/processed/training-balanced-report.json'))
|
| 31 |
+
ap.add_argument('--seed',type=int,default=42)
|
| 32 |
+
ap.add_argument('--confidence',type=float,default=.65)
|
| 33 |
+
ap.add_argument('--target-per-task',type=int,default=800)
|
| 34 |
+
ap.add_argument('--max-per-task',type=int,default=2000)
|
| 35 |
+
args=ap.parse_args(); rng=random.Random(args.seed)
|
| 36 |
+
rows=[json.loads(x) for x in args.input.read_text(encoding='utf-8').splitlines() if x.strip()]
|
| 37 |
+
accepted=[]; rejected=[]
|
| 38 |
+
for r in rows:
|
| 39 |
+
fixed=r.get('label_method') in {'source_fixed','human_override'}
|
| 40 |
+
if fixed or float(r.get('label_confidence',0))>=args.confidence:
|
| 41 |
+
accepted.append(r)
|
| 42 |
+
else: rejected.append(r)
|
| 43 |
+
groups=defaultdict(list)
|
| 44 |
+
for r in accepted: groups[r['task']].append(r)
|
| 45 |
+
output=[]; augmented=Counter()
|
| 46 |
+
for task in TASKS:
|
| 47 |
+
group=groups[task]
|
| 48 |
+
rng.shuffle(group)
|
| 49 |
+
selected=group[:args.max_per_task]
|
| 50 |
+
output.extend(selected)
|
| 51 |
+
needed=max(0,args.target_per_task-len(selected))
|
| 52 |
+
if needed and selected:
|
| 53 |
+
pool=[]
|
| 54 |
+
for r in selected:
|
| 55 |
+
for i,v in enumerate(variants(r['text'])[1:],1):
|
| 56 |
+
n=dict(r); n['id']=f"{r['id']}:aug{i}"; n['text']=v
|
| 57 |
+
n['label_method']='deterministic_augmentation'; n['derived_from']=r['id']; n['label_confidence']=r.get('label_confidence',1.0)
|
| 58 |
+
pool.append(n)
|
| 59 |
+
rng.shuffle(pool)
|
| 60 |
+
take=pool[:needed]
|
| 61 |
+
output.extend(take); augmented[task]+=len(take)
|
| 62 |
+
rng.shuffle(output)
|
| 63 |
+
args.output.parent.mkdir(parents=True,exist_ok=True)
|
| 64 |
+
with args.output.open('w',encoding='utf-8') as f:
|
| 65 |
+
for r in output: f.write(json.dumps(r,ensure_ascii=False)+'\n')
|
| 66 |
+
report={
|
| 67 |
+
'input_rows':len(rows),'accepted_rows':len(accepted),'rejected_low_confidence':len(rejected),
|
| 68 |
+
'output_rows':len(output),'confidence_threshold':args.confidence,
|
| 69 |
+
'by_task':dict(Counter(r['task'] for r in output)),
|
| 70 |
+
'by_complexity':dict(Counter(r['complexity'] for r in output)),
|
| 71 |
+
'by_label_method':dict(Counter(r.get('label_method','unknown') for r in output)),
|
| 72 |
+
'augmented_by_task':dict(augmented),
|
| 73 |
+
'warning':'Augmented rows are lexical variants, not independent human examples.'
|
| 74 |
+
}
|
| 75 |
+
args.report.write_text(json.dumps(report,indent=2),encoding='utf-8')
|
| 76 |
+
print(json.dumps(report,indent=2))
|
| 77 |
+
if __name__=='__main__': main()
|
requirements-inference.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
numpy==2.3.5
|
| 2 |
+
onnxruntime>=1.22,<2
|
| 3 |
+
regex==2026.5.9
|
requirements-training.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
numpy==2.3.5
|
| 2 |
+
scikit-learn==1.8.0
|
| 3 |
+
regex==2026.5.9
|
| 4 |
+
onnx>=1.17,<2
|
requirements-upload.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
huggingface_hub>=0.34,<1
|
train.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Reproduce Veritiana AI Meter classifier v3.1.0 from training-balanced.jsonl."""
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
import argparse, hashlib, json, struct, sys, time
|
| 5 |
+
from collections import Counter
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import numpy as np
|
| 8 |
+
from sklearn.linear_model import LogisticRegression
|
| 9 |
+
from sklearn.metrics import classification_report, confusion_matrix
|
| 10 |
+
from sklearn.model_selection import GroupShuffleSplit
|
| 11 |
+
from features import INPUT_SIZE, build_features
|
| 12 |
+
|
| 13 |
+
TASK_LABELS = ["general_chat","writing","translation","summarization","research","coding","mathematics","document_analysis","high_stakes"]
|
| 14 |
+
COMPLEXITY_LABELS = ["low","medium","high"]
|
| 15 |
+
|
| 16 |
+
def sha256(path: Path) -> str:
|
| 17 |
+
return hashlib.sha256(path.read_bytes()).hexdigest()
|
| 18 |
+
|
| 19 |
+
def _varint(number: int) -> bytes:
|
| 20 |
+
number = int(number)
|
| 21 |
+
if number < 0: number = (1 << 64) + number
|
| 22 |
+
output = bytearray()
|
| 23 |
+
while True:
|
| 24 |
+
byte = number & 0x7F; number >>= 7
|
| 25 |
+
output.append(byte | (0x80 if number else 0))
|
| 26 |
+
if not number: return bytes(output)
|
| 27 |
+
def _key(field: int, wire: int) -> bytes: return _varint((field << 3) | wire)
|
| 28 |
+
def _fv(field: int, value: int) -> bytes: return _key(field,0)+_varint(value)
|
| 29 |
+
def _fb(field: int, value: bytes) -> bytes: return _key(field,2)+_varint(len(value))+value
|
| 30 |
+
def _fs(field: int, value: str) -> bytes: return _fb(field,value.encode())
|
| 31 |
+
def _msg(field: int, value: bytes) -> bytes: return _fb(field,value)
|
| 32 |
+
def _packed(field: int, values) -> bytes: return _fb(field,b''.join(_varint(v) for v in values))
|
| 33 |
+
def _tensor(name: str, array: np.ndarray) -> bytes:
|
| 34 |
+
array=np.ascontiguousarray(array.astype(np.float32))
|
| 35 |
+
return _packed(1,array.shape)+_fv(2,1)+_fs(8,name)+_fb(9,array.tobytes(order='C'))
|
| 36 |
+
def _dim(value): return _fs(2,value) if isinstance(value,str) else _fv(1,value)
|
| 37 |
+
def _shape(dims): return b''.join(_msg(1,_dim(value)) for value in dims)
|
| 38 |
+
def _tensor_type(element,dims): return _fv(1,element)+_msg(2,_shape(dims))
|
| 39 |
+
def _type_proto(element,dims): return _msg(1,_tensor_type(element,dims))
|
| 40 |
+
def _value_info(name,dims): return _fs(1,name)+_msg(2,_type_proto(1,dims))
|
| 41 |
+
def _attr_int(name,value): return _fs(1,name)+_fv(3,value)+_fv(20,2)
|
| 42 |
+
def _node(inputs,outputs,operation,name='',attributes=None):
|
| 43 |
+
value=b''.join(_fs(1,item) for item in inputs)+b''.join(_fs(2,item) for item in outputs)
|
| 44 |
+
if name: value += _fs(3,name)
|
| 45 |
+
value += _fs(4,operation)
|
| 46 |
+
for attribute in attributes or []: value += _msg(5,attribute)
|
| 47 |
+
return value
|
| 48 |
+
def _graph(nodes,initializers,inputs,outputs,name):
|
| 49 |
+
return (b''.join(_msg(1,node) for node in nodes)+_fs(2,name)+
|
| 50 |
+
b''.join(_msg(5,item) for item in initializers)+
|
| 51 |
+
b''.join(_msg(11,item) for item in inputs)+
|
| 52 |
+
b''.join(_msg(12,item) for item in outputs))
|
| 53 |
+
def _opset(version): return _fv(2,version)
|
| 54 |
+
def _kv(key,value): return _fs(1,key)+_fs(2,value)
|
| 55 |
+
|
| 56 |
+
def export_onnx(task_model, complexity_model, destination: Path, version: str) -> None:
|
| 57 |
+
initializers=[
|
| 58 |
+
_tensor('task_weights',task_model.coef_.astype(np.float32).T.copy()),
|
| 59 |
+
_tensor('task_bias',task_model.intercept_.astype(np.float32).copy()),
|
| 60 |
+
_tensor('complexity_weights',complexity_model.coef_.astype(np.float32).T.copy()),
|
| 61 |
+
_tensor('complexity_bias',complexity_model.intercept_.astype(np.float32).copy()),
|
| 62 |
+
]
|
| 63 |
+
nodes=[
|
| 64 |
+
_node(['features','task_weights'],['task_mm'],'MatMul','TaskMatMul'),
|
| 65 |
+
_node(['task_mm','task_bias'],['task_logits'],'Add','TaskAdd'),
|
| 66 |
+
_node(['task_logits'],['task_probabilities'],'Softmax','TaskSoftmax',[_attr_int('axis',1)]),
|
| 67 |
+
_node(['features','complexity_weights'],['complexity_mm'],'MatMul','ComplexityMatMul'),
|
| 68 |
+
_node(['complexity_mm','complexity_bias'],['complexity_logits'],'Add','ComplexityAdd'),
|
| 69 |
+
_node(['complexity_logits'],['complexity_probabilities'],'Softmax','ComplexitySoftmax',[_attr_int('axis',1)]),
|
| 70 |
+
]
|
| 71 |
+
graph=_graph(nodes,initializers,[_value_info('features',['batch',1544])],
|
| 72 |
+
[_value_info('task_probabilities',['batch',9]),_value_info('complexity_probabilities',['batch',3])],
|
| 73 |
+
'VeritianaAIMeterClassifier')
|
| 74 |
+
metadata={
|
| 75 |
+
'model':'Veritiana Multilingual Intent Classifier','version':version,'input_size':'1544',
|
| 76 |
+
'task_labels':json.dumps(TASK_LABELS),'complexity_labels':json.dumps(COMPLEXITY_LABELS),
|
| 77 |
+
'training_data':'OASST1 + CoEdIT + MBPP+ + IFEval; filtered, weak-labeled, balanced',
|
| 78 |
+
'feature_contract':'AI Meter v1.4.9 compatible'
|
| 79 |
+
}
|
| 80 |
+
payload=(_fv(1,8)+_fs(2,'veritiana-ai-meter-model-trainer')+_fs(3,version)+
|
| 81 |
+
_msg(7,graph)+_msg(8,_opset(13))+b''.join(_msg(14,_kv(k,v)) for k,v in metadata.items()))
|
| 82 |
+
destination.write_bytes(payload)
|
| 83 |
+
|
| 84 |
+
def main() -> int:
|
| 85 |
+
parser=argparse.ArgumentParser()
|
| 86 |
+
parser.add_argument('dataset',type=Path,help='Prepared training-balanced.jsonl')
|
| 87 |
+
parser.add_argument('--output-dir',type=Path,default=Path('output'))
|
| 88 |
+
parser.add_argument('--version',default='3.1.0-multisource-balanced')
|
| 89 |
+
parser.add_argument('--test-size',type=float,default=0.20)
|
| 90 |
+
parser.add_argument('--seed',type=int,default=42)
|
| 91 |
+
parser.add_argument('--c',type=float,default=4.0)
|
| 92 |
+
args=parser.parse_args()
|
| 93 |
+
rows=[json.loads(line) for line in args.dataset.read_text(encoding='utf-8').splitlines() if line.strip()]
|
| 94 |
+
if not rows: raise ValueError('Empty dataset')
|
| 95 |
+
task_map={label:index for index,label in enumerate(TASK_LABELS)}
|
| 96 |
+
complexity_map={label:index for index,label in enumerate(COMPLEXITY_LABELS)}
|
| 97 |
+
X=np.vstack([build_features(row['text']) for row in rows]).astype(np.float32)
|
| 98 |
+
task_y=np.asarray([task_map[row['task']] for row in rows],dtype=np.int64)
|
| 99 |
+
complexity_y=np.asarray([complexity_map[row['complexity']] for row in rows],dtype=np.int64)
|
| 100 |
+
groups=[row.get('derived_from') or row.get('normalized_hash') or row.get('id') for row in rows]
|
| 101 |
+
splitter=GroupShuffleSplit(n_splits=1,test_size=args.test_size,random_state=args.seed)
|
| 102 |
+
train_index,test_index=next(splitter.split(X,task_y,groups=groups))
|
| 103 |
+
def fit(target):
|
| 104 |
+
model=LogisticRegression(C=args.c,max_iter=3000,solver='lbfgs',class_weight='balanced',random_state=args.seed)
|
| 105 |
+
model.fit(X[train_index],target[train_index]); return model
|
| 106 |
+
started=time.perf_counter(); task_model=fit(task_y); complexity_model=fit(complexity_y); seconds=time.perf_counter()-started
|
| 107 |
+
task_prediction=task_model.predict(X[test_index]); complexity_prediction=complexity_model.predict(X[test_index])
|
| 108 |
+
task_report=classification_report(task_y[test_index],task_prediction,labels=list(range(9)),target_names=TASK_LABELS,output_dict=True,zero_division=0)
|
| 109 |
+
complexity_report=classification_report(complexity_y[test_index],complexity_prediction,labels=list(range(3)),target_names=COMPLEXITY_LABELS,output_dict=True,zero_division=0)
|
| 110 |
+
evaluation={
|
| 111 |
+
'summary':{'task_accuracy':task_report['accuracy'],'task_macro_f1':task_report['macro avg']['f1-score'],
|
| 112 |
+
'complexity_accuracy':complexity_report['accuracy'],'complexity_macro_f1':complexity_report['macro avg']['f1-score'],
|
| 113 |
+
'training_seconds':seconds},
|
| 114 |
+
'task_report':task_report,'complexity_report':complexity_report,
|
| 115 |
+
'task_confusion_matrix':confusion_matrix(task_y[test_index],task_prediction,labels=list(range(9))).tolist(),
|
| 116 |
+
'complexity_confusion_matrix':confusion_matrix(complexity_y[test_index],complexity_prediction,labels=list(range(3))).tolist()
|
| 117 |
+
}
|
| 118 |
+
args.output_dir.mkdir(parents=True,exist_ok=True)
|
| 119 |
+
model_path=args.output_dir/'veritiana-classifier-v2.onnx'; export_onnx(task_model,complexity_model,model_path,args.version)
|
| 120 |
+
(args.output_dir/'evaluation.json').write_text(json.dumps(evaluation,ensure_ascii=False,indent=2),encoding='utf-8')
|
| 121 |
+
meta={
|
| 122 |
+
'model':'Veritiana Multilingual Intent Classifier','version':args.version,'engine':'ONNX Runtime Web',
|
| 123 |
+
'architecture':'1544 hashed lexical/character/numeric features; dual multinomial logistic heads',
|
| 124 |
+
'input':{'name':'features','dtype':'float32','shape':['batch',1544]},
|
| 125 |
+
'outputs':[{'name':'task_probabilities','dtype':'float32','shape':['batch',9]},
|
| 126 |
+
{'name':'complexity_probabilities','dtype':'float32','shape':['batch',3]}],
|
| 127 |
+
'task_labels':TASK_LABELS,'complexity_labels':COMPLEXITY_LABELS,
|
| 128 |
+
'training_data':{'dataset_sha256':sha256(args.dataset),'balanced_rows':len(rows),'train_rows':len(train_index),'test_rows':len(test_index),
|
| 129 |
+
'label_method_counts':dict(Counter(row.get('label_method','unknown') for row in rows))},
|
| 130 |
+
'validation':evaluation['summary'],'onnx_sha256':sha256(model_path),
|
| 131 |
+
'limitations':'Validation uses weak labels and deterministic augmentations; it is not an independent human-ground-truth benchmark.'
|
| 132 |
+
}
|
| 133 |
+
(args.output_dir/'classifier-meta.json').write_text(json.dumps(meta,ensure_ascii=False,indent=2),encoding='utf-8')
|
| 134 |
+
print(json.dumps({'model':str(model_path),'onnx_sha256':sha256(model_path),'evaluation':evaluation['summary']},indent=2))
|
| 135 |
+
return 0
|
| 136 |
+
if __name__=='__main__': raise SystemExit(main())
|
training-config.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"release_version": "3.1.0-multisource-balanced",
|
| 3 |
+
"random_seed": 42,
|
| 4 |
+
"test_size": 0.2,
|
| 5 |
+
"splitter": "GroupShuffleSplit",
|
| 6 |
+
"group_key_priority": [
|
| 7 |
+
"derived_from",
|
| 8 |
+
"normalized_hash",
|
| 9 |
+
"id"
|
| 10 |
+
],
|
| 11 |
+
"classifier": {
|
| 12 |
+
"type": "sklearn.linear_model.LogisticRegression",
|
| 13 |
+
"solver": "lbfgs",
|
| 14 |
+
"C": 4.0,
|
| 15 |
+
"max_iter": 3000,
|
| 16 |
+
"class_weight": "balanced"
|
| 17 |
+
},
|
| 18 |
+
"preparation": {
|
| 19 |
+
"confidence_threshold": 0.65,
|
| 20 |
+
"target_per_task": 800,
|
| 21 |
+
"max_per_task": 2000,
|
| 22 |
+
"accepted_label_methods": [
|
| 23 |
+
"source_fixed",
|
| 24 |
+
"human_override"
|
| 25 |
+
],
|
| 26 |
+
"augmentation": "deterministic lexical variants"
|
| 27 |
+
},
|
| 28 |
+
"features": {
|
| 29 |
+
"input_size": 1544,
|
| 30 |
+
"word_bigram_bins": 1024,
|
| 31 |
+
"character_trigram_bins": 512,
|
| 32 |
+
"numeric_features": 8,
|
| 33 |
+
"hash": "FNV-1a 32-bit over JavaScript UTF-16 code units"
|
| 34 |
+
},
|
| 35 |
+
"labels": {
|
| 36 |
+
"task": [
|
| 37 |
+
"general_chat",
|
| 38 |
+
"writing",
|
| 39 |
+
"translation",
|
| 40 |
+
"summarization",
|
| 41 |
+
"research",
|
| 42 |
+
"coding",
|
| 43 |
+
"mathematics",
|
| 44 |
+
"document_analysis",
|
| 45 |
+
"high_stakes"
|
| 46 |
+
],
|
| 47 |
+
"complexity": [
|
| 48 |
+
"low",
|
| 49 |
+
"medium",
|
| 50 |
+
"high"
|
| 51 |
+
]
|
| 52 |
+
},
|
| 53 |
+
"reference_environment": {
|
| 54 |
+
"python": "3.13.5",
|
| 55 |
+
"numpy": "2.3.5",
|
| 56 |
+
"scikit-learn": "1.8.0",
|
| 57 |
+
"regex": "2026.5.9",
|
| 58 |
+
"onnx_opset": 13,
|
| 59 |
+
"onnx_ir_version": 8
|
| 60 |
+
}
|
| 61 |
+
}
|
upload_to_hub.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import argparse
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from huggingface_hub import HfApi
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def main() -> None:
|
| 8 |
+
parser = argparse.ArgumentParser(description="Upload the Veritiana classifier repository to Hugging Face Hub.")
|
| 9 |
+
parser.add_argument("repo_id", help="Target repository, for example Veritiana-AI/prompt-task-complexity-classifier")
|
| 10 |
+
parser.add_argument("--private", action="store_true", help="Create the repository as private")
|
| 11 |
+
args = parser.parse_args()
|
| 12 |
+
|
| 13 |
+
root = Path(__file__).resolve().parent
|
| 14 |
+
api = HfApi()
|
| 15 |
+
api.create_repo(repo_id=args.repo_id, repo_type="model", private=args.private, exist_ok=True)
|
| 16 |
+
api.upload_folder(
|
| 17 |
+
repo_id=args.repo_id,
|
| 18 |
+
repo_type="model",
|
| 19 |
+
folder_path=str(root),
|
| 20 |
+
ignore_patterns=["*.zip", "__pycache__/*", ".venv/*", "node_modules/*", "dist/*"],
|
| 21 |
+
commit_message="Publish Veritiana Prompt Task & Complexity Classifier v3.1.0",
|
| 22 |
+
)
|
| 23 |
+
print(f"Uploaded to https://huggingface.co/{args.repo_id}")
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
if __name__ == "__main__":
|
| 27 |
+
main()
|