Publish validated dynamic FP32 ONNX Runtime graph
Browse files- .gitattributes +2 -0
- ATTRIBUTION.md +15 -0
- INSTRUCTIONS.md +229 -0
- LICENSE +201 -0
- MODEL_CARD.md +61 -0
- README.md +61 -0
- artifact-manifest.json +97 -0
- chat_template.jinja +154 -0
- examples/inference.py +20 -0
- onnx/model.onnx +3 -0
- onnx/model.onnx.data +3 -0
- pyproject.toml +55 -0
- src/openthai_systemone_onnx/__init__.py +35 -0
- src/openthai_systemone_onnx/artifact.py +81 -0
- src/openthai_systemone_onnx/client.py +164 -0
- src/openthai_systemone_onnx/constants.py +7 -0
- src/openthai_systemone_onnx/export.py +576 -0
- src/openthai_systemone_onnx/upload.py +73 -0
- src/openthai_systemone_onnx/validation.py +121 -0
- src/openthai_systemone_onnx_tools/__init__.py +6 -0
- src/openthai_systemone_onnx_tools/artifact.py +80 -0
- src/openthai_systemone_onnx_tools/constants.py +37 -0
- src/openthai_systemone_onnx_tools/export.py +583 -0
- src/openthai_systemone_onnx_tools/upload.py +73 -0
- src/openthai_systemone_onnx_tools/validation.py +162 -0
- tokenizer.json +3 -0
- tokenizer_config.json +32 -0
- uv.lock +909 -0
- validation-report.json +103 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* 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
|
|
|
|
|
|
|
|
|
| 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
|
| 36 |
+
onnx/model.onnx.data filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
ATTRIBUTION.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Attribution
|
| 2 |
+
|
| 3 |
+
The source model and Python client are from
|
| 4 |
+
[iApp Technology / OpenThai](https://github.com/iapp-technology/openthai-systemone)
|
| 5 |
+
and are distributed under Apache-2.0.
|
| 6 |
+
|
| 7 |
+
- Model: `iapp/OpenThai-SystemOne`
|
| 8 |
+
- Model revision: `f3709948b5e3cc9606a57e74ba62b7a639d17dd3`
|
| 9 |
+
- Client repository: `iapp-technology/openthai-systemone`
|
| 10 |
+
- Client revision: `5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf`
|
| 11 |
+
- Backbone: Qwen3.5 text tower as identified by the source configuration
|
| 12 |
+
|
| 13 |
+
This project modifies the inference implementation by constructing an ONNX
|
| 14 |
+
Runtime-specific graph with dynamic dimensions, internal request state, and the source model's calibrated decision head.
|
| 15 |
+
|
INSTRUCTIONS.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Convert OpenThai-SystemOne to dynamic ONNX
|
| 2 |
+
|
| 3 |
+
These are the maintainer instructions for converting the pinned
|
| 4 |
+
`iapp/OpenThai-SystemOne` checkpoint, validating the result, and uploading it
|
| 5 |
+
to Hugging Face. For application-side `OnnxSystemOneClient` usage, see
|
| 6 |
+
[README.md](README.md).
|
| 7 |
+
|
| 8 |
+
Run every command from the repository root. The conversion and release code is
|
| 9 |
+
kept in `src/openthai_systemone_onnx_tools`; the independent runtime client is
|
| 10 |
+
in `src/openthai_systemone_onnx`.
|
| 11 |
+
|
| 12 |
+
## 1. Create the conversion environment
|
| 13 |
+
|
| 14 |
+
```bash
|
| 15 |
+
uv python pin 3.12
|
| 16 |
+
uv sync --extra tools --extra dev --frozen
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
The first command selects Python 3.12. The second creates `.venv`, installs the
|
| 20 |
+
runtime package, adds the `tools` dependencies used to build and inspect ONNX,
|
| 21 |
+
and adds pytest from the `dev` extra. `--frozen` makes the operation fail if
|
| 22 |
+
`uv.lock` and `pyproject.toml` disagree instead of silently changing versions.
|
| 23 |
+
|
| 24 |
+
Important pinned versions include ONNX Runtime 1.30.0, ONNX Runtime GenAI
|
| 25 |
+
0.16.0, source model revision
|
| 26 |
+
`f3709948b5e3cc9606a57e74ba62b7a639d17dd3`, and upstream client commit
|
| 27 |
+
`5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf`.
|
| 28 |
+
|
| 29 |
+
## 2. Authenticate with Hugging Face
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
uv run hf auth login
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
This interactively stores a Hugging Face token. Downloading the public source
|
| 36 |
+
does not require write access; uploading the finished artifact does.
|
| 37 |
+
|
| 38 |
+
## 3. Export the model
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
uv run openthai-systemone-export \
|
| 42 |
+
--output artifacts/OpenThai-SystemOne-ONNX \
|
| 43 |
+
--cache-dir .cache/huggingface
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
This command downloads the pinned checkpoint, loads its safetensor weights,
|
| 47 |
+
builds the dynamic Qwen3.5 graph, appends the calibrated SystemOne head, and
|
| 48 |
+
writes:
|
| 49 |
+
|
| 50 |
+
- `onnx/model.onnx` for graph structure;
|
| 51 |
+
- `onnx/model.onnx.data` for external FP32 weights;
|
| 52 |
+
- tokenizer files and the separated helper packages;
|
| 53 |
+
- license, attribution, model card, and usage documentation;
|
| 54 |
+
- `artifact-manifest.json` with revisions, limits, tensor schema, operator
|
| 55 |
+
requirements, and checksums.
|
| 56 |
+
|
| 57 |
+
The graph keeps symbolic batch, sequence, and question dimensions. It derives
|
| 58 |
+
MRoPE positions from `attention_mask` and initializes KV, convolution, and
|
| 59 |
+
recurrent state internally for every complete request.
|
| 60 |
+
|
| 61 |
+
## 4. Run fast compatibility and exporter tests
|
| 62 |
+
|
| 63 |
+
```bash
|
| 64 |
+
uv run openthai-systemone-validate \
|
| 65 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 66 |
+
--client
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
This checks upstream constructor/method signatures, response-class identity,
|
| 70 |
+
serialization, typed and raw questions, state formats, validation errors,
|
| 71 |
+
single/batch equivalence, automatic and explicit permutations, accounting,
|
| 72 |
+
exporter graph construction, and validator device diagnostics. It records the
|
| 73 |
+
result as `client_compatibility` in `validation-report.json`.
|
| 74 |
+
|
| 75 |
+
## 5. Run normal PyTorch/ONNX parity
|
| 76 |
+
|
| 77 |
+
On CPU, including macOS:
|
| 78 |
+
|
| 79 |
+
```bash
|
| 80 |
+
PYTORCH_PARITY_DEVICE=cpu \
|
| 81 |
+
ORT_PARITY_DEVICE=cpu \
|
| 82 |
+
uv run openthai-systemone-validate \
|
| 83 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 84 |
+
--normal
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
`PYTORCH_PARITY_DEVICE` selects the reference-model device.
|
| 88 |
+
`ORT_PARITY_DEVICE` selects the ONNX Runtime provider. The command reruns the
|
| 89 |
+
fast tests and then compares FP32 logits and probabilities at lengths 63, 64,
|
| 90 |
+
65, 511, 512, 513, 2,048, and 8,192. It requires `rtol=1e-3`, `atol=1e-4`, and
|
| 91 |
+
identical winning slots.
|
| 92 |
+
|
| 93 |
+
On Apple Silicon, ONNX must remain on CPU because the required Microsoft
|
| 94 |
+
contrib operators do not have an ONNX Runtime MPS implementation. Check whether
|
| 95 |
+
the installed PyTorch build can use MPS:
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
uv run python -c 'import torch; print(torch.backends.mps.is_available())'
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
If this prints `True`, the PyTorch reference half may use the Apple GPU:
|
| 102 |
+
|
| 103 |
+
```bash
|
| 104 |
+
PYTORCH_ENABLE_MPS_FALLBACK=1 \
|
| 105 |
+
PYTORCH_PARITY_DEVICE=mps \
|
| 106 |
+
ORT_PARITY_DEVICE=cpu \
|
| 107 |
+
uv run openthai-systemone-validate \
|
| 108 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 109 |
+
--normal
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
`PYTORCH_ENABLE_MPS_FALLBACK=1` permits unsupported PyTorch operations to fall
|
| 113 |
+
back to CPU. If the availability check prints `False`, use the all-CPU command.
|
| 114 |
+
|
| 115 |
+
## 6. Validate the dynamic 262,144-token structure
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
uv run openthai-systemone-validate \
|
| 119 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 120 |
+
--structural
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
This runs the ONNX checker, creates an ONNX Runtime CPU session, verifies the
|
| 124 |
+
symbolic public dimensions, required contrib operator counts, dynamic position
|
| 125 |
+
construction, internal state, manifest boundary, and artifact checksums. It
|
| 126 |
+
does not attempt a 262,144-token numerical inference. Lengths above 65,536 are
|
| 127 |
+
structurally validated only.
|
| 128 |
+
|
| 129 |
+
## 7. Prepare a CUDA host for the slow certification
|
| 130 |
+
|
| 131 |
+
The 65,536-token parity test is high-memory and should run on an NVIDIA Linux
|
| 132 |
+
or Windows machine. CUDA cannot run on macOS.
|
| 133 |
+
|
| 134 |
+
First create the environment as in step 1. Then replace the CPU ONNX Runtime
|
| 135 |
+
wheel with its GPU counterpart:
|
| 136 |
+
|
| 137 |
+
```bash
|
| 138 |
+
uv pip uninstall onnxruntime
|
| 139 |
+
uv pip install onnxruntime-gpu==1.30.0
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
The first command removes the CPU package. The second installs the build that
|
| 143 |
+
provides `CUDAExecutionProvider`.
|
| 144 |
+
|
| 145 |
+
Verify both CUDA stacks before starting the expensive test:
|
| 146 |
+
|
| 147 |
+
```bash
|
| 148 |
+
uv run --no-sync python -c \
|
| 149 |
+
'import torch, onnxruntime as ort; print("torch CUDA:", torch.cuda.is_available()); print("ORT providers:", ort.get_available_providers())'
|
| 150 |
+
```
|
| 151 |
+
|
| 152 |
+
The output must include `torch CUDA: True` and `CUDAExecutionProvider`.
|
| 153 |
+
`--no-sync` is required after the manual wheel replacement; plain `uv run` may
|
| 154 |
+
synchronize from the lockfile and restore CPU-only `onnxruntime`.
|
| 155 |
+
|
| 156 |
+
## 8. Run the slow 65,536-token parity test
|
| 157 |
+
|
| 158 |
+
```bash
|
| 159 |
+
PYTORCH_PARITY_DEVICE=cuda \
|
| 160 |
+
ORT_PARITY_DEVICE=cuda \
|
| 161 |
+
uv run --no-sync openthai-systemone-validate \
|
| 162 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 163 |
+
--slow
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
This runs one numerical comparison at exactly 65,536 tokens. To reduce peak
|
| 167 |
+
GPU memory, the test executes PyTorch first, copies only its decision outputs
|
| 168 |
+
to CPU, deletes the reference model and clears its CUDA cache, and then creates
|
| 169 |
+
the ONNX Runtime session. Thus the two full model copies are not resident on
|
| 170 |
+
the GPU simultaneously.
|
| 171 |
+
|
| 172 |
+
If the process exits with signal 9, the host or driver likely exhausted
|
| 173 |
+
memory. Move the test to a larger-memory CUDA machine. If CUDA is requested on
|
| 174 |
+
macOS or a CPU-only ONNX Runtime installation, the validator stops before
|
| 175 |
+
pytest and explains how to correct the environment.
|
| 176 |
+
|
| 177 |
+
## 9. Optionally run all validation stages together
|
| 178 |
+
|
| 179 |
+
After preparing the CUDA environment:
|
| 180 |
+
|
| 181 |
+
```bash
|
| 182 |
+
PYTORCH_PARITY_DEVICE=cuda \
|
| 183 |
+
ORT_PARITY_DEVICE=cuda \
|
| 184 |
+
uv run --no-sync openthai-systemone-validate \
|
| 185 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 186 |
+
--all
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
This runs client/exporter tests, normal parity, slow parity, and structural
|
| 190 |
+
validation in sequence. Each stage records its command, timestamp, return code,
|
| 191 |
+
and test counts. The command stops at the first failed stage.
|
| 192 |
+
|
| 193 |
+
## 10. Check the upload gate without uploading
|
| 194 |
+
|
| 195 |
+
```bash
|
| 196 |
+
uv run --no-sync openthai-systemone-upload \
|
| 197 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX
|
| 198 |
+
```
|
| 199 |
+
|
| 200 |
+
This is a local dry run. It requires every validation stage to have at least
|
| 201 |
+
one executed test, zero skips, and a passing result. It then recomputes all
|
| 202 |
+
manifest hashes. It does not contact or modify Hugging Face.
|
| 203 |
+
|
| 204 |
+
## 11. Upload the validated artifact
|
| 205 |
+
|
| 206 |
+
```bash
|
| 207 |
+
uv run --no-sync openthai-systemone-upload \
|
| 208 |
+
--artifact artifacts/OpenThai-SystemOne-ONNX \
|
| 209 |
+
--repo-id imtk/OpenThai-SystemOne-ONNX \
|
| 210 |
+
--execute
|
| 211 |
+
```
|
| 212 |
+
|
| 213 |
+
This repeats the gate check, creates the Hugging Face model repository if it
|
| 214 |
+
does not exist, and uploads the artifact directory. `--execute` is the switch
|
| 215 |
+
that permits the external write; without it the command remains a dry run.
|
| 216 |
+
|
| 217 |
+
## Exported tensor contract
|
| 218 |
+
|
| 219 |
+
All inputs are `int64`; outputs are `float32`.
|
| 220 |
+
|
| 221 |
+
| Tensor | Shape |
|
| 222 |
+
|---|---|
|
| 223 |
+
| `input_ids` | `[batch, sequence]` |
|
| 224 |
+
| `attention_mask` | `[batch, sequence]` |
|
| 225 |
+
| `answer_positions` | `[batch, questions]` |
|
| 226 |
+
| `option_counts` | `[batch, questions]` |
|
| 227 |
+
| `qtypes` | `[batch, questions]` |
|
| 228 |
+
| `logits` | `[batch, questions, 256]` |
|
| 229 |
+
| `probabilities` | `[batch, questions, 256]` |
|
LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
MODEL_CARD.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: onnxruntime
|
| 4 |
+
base_model: iapp/OpenThai-SystemOne
|
| 5 |
+
tags:
|
| 6 |
+
- onnx
|
| 7 |
+
- onnxruntime
|
| 8 |
+
- thai
|
| 9 |
+
- qwen3.5
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# OpenThai-SystemOne ONNX
|
| 13 |
+
|
| 14 |
+
This is an FP32 ONNX Runtime conversion of `iapp/OpenThai-SystemOne` revision
|
| 15 |
+
`f3709948b5e3cc9606a57e74ba62b7a639d17dd3`.
|
| 16 |
+
|
| 17 |
+
The sequence dimension is symbolic. The accepted structural limit is 262,144
|
| 18 |
+
tokens, inherited from the Qwen3.5 text backbone. PyTorch/ONNX numerical parity
|
| 19 |
+
is validated through 65,536 tokens only. Larger requests may be infeasible on
|
| 20 |
+
available hardware and have structural—not numerical—validation.
|
| 21 |
+
|
| 22 |
+
The model requires ONNX Runtime 1.30.0. It uses Microsoft contrib operators and
|
| 23 |
+
will not run in arbitrary ONNX engines.
|
| 24 |
+
|
| 25 |
+
## Usage
|
| 26 |
+
|
| 27 |
+
Clone this model repository and run `uv sync --frozen` once to install its
|
| 28 |
+
locked helper package and runtime dependencies, then:
|
| 29 |
+
|
| 30 |
+
```python
|
| 31 |
+
from openthai_systemone_onnx import OnnxSystemOneClient, Choice
|
| 32 |
+
|
| 33 |
+
client = OnnxSystemOneClient("imtk/OpenThai-SystemOne-ONNX")
|
| 34 |
+
result = client.system_one(
|
| 35 |
+
"บริการดีมาก",
|
| 36 |
+
{"sentiment": Choice(instructions="Choose sentiment", criteria={"positive": None, "negative": None})},
|
| 37 |
+
)
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
The client subclasses the upstream `SystemOneClient` at commit
|
| 41 |
+
`5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf`. Formatting, public methods,
|
| 42 |
+
response classes, decoding, confidence, permutations, and usage accounting are
|
| 43 |
+
inherited unchanged.
|
| 44 |
+
|
| 45 |
+
## Validation
|
| 46 |
+
|
| 47 |
+
The uploaded `validation-report.json` is the machine-readable source of truth.
|
| 48 |
+
Upload is blocked unless the client suite, standard parity suite, 65,536-token
|
| 49 |
+
parity test, and structural 262,144-token checks all pass.
|
| 50 |
+
|
| 51 |
+
See `artifact-manifest.json` for the tensor schema, operator domains, runtime
|
| 52 |
+
versions, source revisions, limits, and SHA-256 checksums.
|
| 53 |
+
|
| 54 |
+
## Limitations
|
| 55 |
+
|
| 56 |
+
- FP32 only.
|
| 57 |
+
- CPU and CUDA execution providers only through the packaged client.
|
| 58 |
+
- ONNX Runtime contrib operators make this artifact runtime-specific.
|
| 59 |
+
- The model performs complete-request inference; generation caches are
|
| 60 |
+
deliberately internal and reset for every call.
|
| 61 |
+
- 262,144 tokens is an accepted graph boundary, not a performance guarantee.
|
README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: onnxruntime
|
| 4 |
+
base_model: iapp/OpenThai-SystemOne
|
| 5 |
+
tags:
|
| 6 |
+
- onnx
|
| 7 |
+
- onnxruntime
|
| 8 |
+
- thai
|
| 9 |
+
- qwen3.5
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# OpenThai-SystemOne ONNX
|
| 13 |
+
|
| 14 |
+
This is an FP32 ONNX Runtime conversion of `iapp/OpenThai-SystemOne` revision
|
| 15 |
+
`f3709948b5e3cc9606a57e74ba62b7a639d17dd3`.
|
| 16 |
+
|
| 17 |
+
The sequence dimension is symbolic. The accepted structural limit is 262,144
|
| 18 |
+
tokens, inherited from the Qwen3.5 text backbone. PyTorch/ONNX numerical parity
|
| 19 |
+
is validated through 65,536 tokens only. Larger requests may be infeasible on
|
| 20 |
+
available hardware and have structural—not numerical—validation.
|
| 21 |
+
|
| 22 |
+
The model requires ONNX Runtime 1.30.0. It uses Microsoft contrib operators and
|
| 23 |
+
will not run in arbitrary ONNX engines.
|
| 24 |
+
|
| 25 |
+
## Usage
|
| 26 |
+
|
| 27 |
+
Clone this model repository and run `uv sync --frozen` once to install its
|
| 28 |
+
locked helper package and runtime dependencies, then:
|
| 29 |
+
|
| 30 |
+
```python
|
| 31 |
+
from openthai_systemone_onnx import OnnxSystemOneClient, Choice
|
| 32 |
+
|
| 33 |
+
client = OnnxSystemOneClient("imtk/OpenThai-SystemOne-ONNX")
|
| 34 |
+
result = client.system_one(
|
| 35 |
+
"บริการดีมาก",
|
| 36 |
+
{"sentiment": Choice(instructions="Choose sentiment", criteria={"positive": None, "negative": None})},
|
| 37 |
+
)
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
The client subclasses the upstream `SystemOneClient` at commit
|
| 41 |
+
`5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf`. Formatting, public methods,
|
| 42 |
+
response classes, decoding, confidence, permutations, and usage accounting are
|
| 43 |
+
inherited unchanged.
|
| 44 |
+
|
| 45 |
+
## Validation
|
| 46 |
+
|
| 47 |
+
The uploaded `validation-report.json` is the machine-readable source of truth.
|
| 48 |
+
Upload is blocked unless the client suite, standard parity suite, 65,536-token
|
| 49 |
+
parity test, and structural 262,144-token checks all pass.
|
| 50 |
+
|
| 51 |
+
See `artifact-manifest.json` for the tensor schema, operator domains, runtime
|
| 52 |
+
versions, source revisions, limits, and SHA-256 checksums.
|
| 53 |
+
|
| 54 |
+
## Limitations
|
| 55 |
+
|
| 56 |
+
- FP32 only.
|
| 57 |
+
- CPU and CUDA execution providers only through the packaged client.
|
| 58 |
+
- ONNX Runtime contrib operators make this artifact runtime-specific.
|
| 59 |
+
- The model performs complete-request inference; generation caches are
|
| 60 |
+
deliberately internal and reset for every call.
|
| 61 |
+
- 262,144 tokens is an accepted graph boundary, not a performance guarantee.
|
artifact-manifest.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"checksums": {
|
| 3 |
+
"ATTRIBUTION.md": "9550b4a6711bb74c3bd05d29093e819c53c1501fab6e45c955b7c8bca22a8feb",
|
| 4 |
+
"INSTRUCTIONS.md": "ec52b251d5e3caa4036b322bc8cf0d0478649ad3ad36e297804c5910eb33da25",
|
| 5 |
+
"LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
|
| 6 |
+
"MODEL_CARD.md": "0dae46157f2e819c25a2a1b31ae0916f4024a74441dce808f456005a4c0a0475",
|
| 7 |
+
"README.md": "0dae46157f2e819c25a2a1b31ae0916f4024a74441dce808f456005a4c0a0475",
|
| 8 |
+
"chat_template.jinja": "273d8e0e683b885071fb17e08d71e5f2a5ddfb5309756181681de4f5a1822d80",
|
| 9 |
+
"examples/inference.py": "d704adb6199bdcab25e9b1a9c32b2faf44ea5c6dbab239bd82ced2ea2dbd3bd2",
|
| 10 |
+
"onnx/model.onnx": "725e6b85effd2a861ccdf7ea15a4d8f05a089d4ec3bc34c6a058abace65f9532",
|
| 11 |
+
"onnx/model.onnx.data": "259b8a487cf1e4cecdc840cfc4eefa288f56538fa1e6b69376461d0ffbb0c9f3",
|
| 12 |
+
"pyproject.toml": "5bbd1a1906fa79b305567f08bc9f0442a8bbde5d6ab8e52ba0502b8c4757e574",
|
| 13 |
+
"src/openthai_systemone_onnx/__init__.py": "c507536cc93fd376c15f3060446a429231253c98cce18bd85663978ae7b29dd7",
|
| 14 |
+
"src/openthai_systemone_onnx/artifact.py": "6aff925ddf6b6d0453289fce1b78ee3b0b75a56dee06487655223553476bf773",
|
| 15 |
+
"src/openthai_systemone_onnx/client.py": "6e2e4e4d7a8eaec9ed75d325d0be67a48512c4f18b78a21c2a8378a295194669",
|
| 16 |
+
"src/openthai_systemone_onnx/constants.py": "289574a45fb0e50900733ac5f678dd8193df9e211399af65a97f43d928977058",
|
| 17 |
+
"src/openthai_systemone_onnx/export.py": "8b1bfe477b72af0fd540cf9b5c794c97fee4c0a5624d3ccc52bc279a94b77ba3",
|
| 18 |
+
"src/openthai_systemone_onnx/upload.py": "50bd6cd53b9799e178d6677d95dd06938c772223489e5fa96fc1eade0fed1442",
|
| 19 |
+
"src/openthai_systemone_onnx/validation.py": "e661cabc9f71a84b5ffd30eab1569c5863e2cfeed11ffac6eb33e5e46eb06c25",
|
| 20 |
+
"src/openthai_systemone_onnx_tools/__init__.py": "b1fa648f1ce1a3c264f0a423a32db18939f8f4287f39abef01b2195525adaef7",
|
| 21 |
+
"src/openthai_systemone_onnx_tools/artifact.py": "9cc30acca36447aaa263b82806c4935ef0c017fd6ca5e068a5c632279a73fc18",
|
| 22 |
+
"src/openthai_systemone_onnx_tools/constants.py": "a71bdf2666ee0eb4724ee3dd3b2099d4b5cdf44cfcfe57110cf1eeeca6e57640",
|
| 23 |
+
"src/openthai_systemone_onnx_tools/export.py": "8d3c850e8d2707b4b6d0ce1d342406a6f65d19b2a3d74d1a5e8a5e5e5c1dfd8c",
|
| 24 |
+
"src/openthai_systemone_onnx_tools/upload.py": "50bd6cd53b9799e178d6677d95dd06938c772223489e5fa96fc1eade0fed1442",
|
| 25 |
+
"src/openthai_systemone_onnx_tools/validation.py": "592dc5fc91026b9447262f5ebec68817eef39eb61c3993a04d2d3f4929af4c89",
|
| 26 |
+
"tokenizer.json": "d3400f1532d54f98d82b24c503e61908aa66f84e22e566e59fc80494add3a5c3",
|
| 27 |
+
"tokenizer_config.json": "171ecbe7ddae98d11840698f7df2b8d5b4722139db0f0620d3bbf429bd656250",
|
| 28 |
+
"uv.lock": "ef30a5bb85ede6aa473859b15d26b1ff8e6061fea951ecdba4bf09eaf110f683"
|
| 29 |
+
},
|
| 30 |
+
"created_at": "2026-09-25T07:16:52.369290+00:00",
|
| 31 |
+
"external_data": "onnx/model.onnx.data",
|
| 32 |
+
"format_version": 1,
|
| 33 |
+
"graph": "onnx/model.onnx",
|
| 34 |
+
"max_position_embeddings": 262144,
|
| 35 |
+
"numerically_validated_max_tokens": 65536,
|
| 36 |
+
"operator_domains": {
|
| 37 |
+
"": 23,
|
| 38 |
+
"com.microsoft": 1
|
| 39 |
+
},
|
| 40 |
+
"precision": "fp32",
|
| 41 |
+
"required_contrib_operators": [
|
| 42 |
+
"CausalConvWithState",
|
| 43 |
+
"GroupQueryAttention",
|
| 44 |
+
"LinearAttention"
|
| 45 |
+
],
|
| 46 |
+
"runtime": {
|
| 47 |
+
"onnxruntime": "1.30.0",
|
| 48 |
+
"onnxruntime_genai_builder": "0.16.0",
|
| 49 |
+
"portable_to_arbitrary_onnx_engines": false
|
| 50 |
+
},
|
| 51 |
+
"source": {
|
| 52 |
+
"repo_id": "iapp/OpenThai-SystemOne",
|
| 53 |
+
"revision": "f3709948b5e3cc9606a57e74ba62b7a639d17dd3"
|
| 54 |
+
},
|
| 55 |
+
"state_contract": "zero convolution, recurrent, and KV state is initialized inside the graph per request",
|
| 56 |
+
"target_repository": "imtk/OpenThai-SystemOne-ONNX",
|
| 57 |
+
"tensor_schema": {
|
| 58 |
+
"inputs": {
|
| 59 |
+
"answer_positions": [
|
| 60 |
+
"batch",
|
| 61 |
+
"questions"
|
| 62 |
+
],
|
| 63 |
+
"attention_mask": [
|
| 64 |
+
"batch",
|
| 65 |
+
"sequence"
|
| 66 |
+
],
|
| 67 |
+
"input_ids": [
|
| 68 |
+
"batch",
|
| 69 |
+
"sequence"
|
| 70 |
+
],
|
| 71 |
+
"option_counts": [
|
| 72 |
+
"batch",
|
| 73 |
+
"questions"
|
| 74 |
+
],
|
| 75 |
+
"qtypes": [
|
| 76 |
+
"batch",
|
| 77 |
+
"questions"
|
| 78 |
+
]
|
| 79 |
+
},
|
| 80 |
+
"outputs": {
|
| 81 |
+
"logits": [
|
| 82 |
+
"batch",
|
| 83 |
+
"questions",
|
| 84 |
+
256
|
| 85 |
+
],
|
| 86 |
+
"probabilities": [
|
| 87 |
+
"batch",
|
| 88 |
+
"questions",
|
| 89 |
+
256
|
| 90 |
+
]
|
| 91 |
+
}
|
| 92 |
+
},
|
| 93 |
+
"upstream_client": {
|
| 94 |
+
"repository": "iapp-technology/openthai-systemone",
|
| 95 |
+
"revision": "5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf"
|
| 96 |
+
}
|
| 97 |
+
}
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- set image_count = namespace(value=0) %}
|
| 2 |
+
{%- set video_count = namespace(value=0) %}
|
| 3 |
+
{%- macro render_content(content, do_vision_count, is_system_content=false) %}
|
| 4 |
+
{%- if content is string %}
|
| 5 |
+
{{- content }}
|
| 6 |
+
{%- elif content is iterable and content is not mapping %}
|
| 7 |
+
{%- for item in content %}
|
| 8 |
+
{%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
|
| 9 |
+
{%- if is_system_content %}
|
| 10 |
+
{{- raise_exception('System message cannot contain images.') }}
|
| 11 |
+
{%- endif %}
|
| 12 |
+
{%- if do_vision_count %}
|
| 13 |
+
{%- set image_count.value = image_count.value + 1 %}
|
| 14 |
+
{%- endif %}
|
| 15 |
+
{%- if add_vision_id %}
|
| 16 |
+
{{- 'Picture ' ~ image_count.value ~ ': ' }}
|
| 17 |
+
{%- endif %}
|
| 18 |
+
{{- '<|vision_start|><|image_pad|><|vision_end|>' }}
|
| 19 |
+
{%- elif 'video' in item or item.type == 'video' %}
|
| 20 |
+
{%- if is_system_content %}
|
| 21 |
+
{{- raise_exception('System message cannot contain videos.') }}
|
| 22 |
+
{%- endif %}
|
| 23 |
+
{%- if do_vision_count %}
|
| 24 |
+
{%- set video_count.value = video_count.value + 1 %}
|
| 25 |
+
{%- endif %}
|
| 26 |
+
{%- if add_vision_id %}
|
| 27 |
+
{{- 'Video ' ~ video_count.value ~ ': ' }}
|
| 28 |
+
{%- endif %}
|
| 29 |
+
{{- '<|vision_start|><|video_pad|><|vision_end|>' }}
|
| 30 |
+
{%- elif 'text' in item %}
|
| 31 |
+
{{- item.text }}
|
| 32 |
+
{%- else %}
|
| 33 |
+
{{- raise_exception('Unexpected item type in content.') }}
|
| 34 |
+
{%- endif %}
|
| 35 |
+
{%- endfor %}
|
| 36 |
+
{%- elif content is none or content is undefined %}
|
| 37 |
+
{{- '' }}
|
| 38 |
+
{%- else %}
|
| 39 |
+
{{- raise_exception('Unexpected content type.') }}
|
| 40 |
+
{%- endif %}
|
| 41 |
+
{%- endmacro %}
|
| 42 |
+
{%- if not messages %}
|
| 43 |
+
{{- raise_exception('No messages provided.') }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- if tools and tools is iterable and tools is not mapping %}
|
| 46 |
+
{{- '<|im_start|>system\n' }}
|
| 47 |
+
{{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
|
| 48 |
+
{%- for tool in tools %}
|
| 49 |
+
{{- "\n" }}
|
| 50 |
+
{{- tool | tojson }}
|
| 51 |
+
{%- endfor %}
|
| 52 |
+
{{- "\n</tools>" }}
|
| 53 |
+
{{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
|
| 54 |
+
{%- if messages[0].role == 'system' %}
|
| 55 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 56 |
+
{%- if content %}
|
| 57 |
+
{{- '\n\n' + content }}
|
| 58 |
+
{%- endif %}
|
| 59 |
+
{%- endif %}
|
| 60 |
+
{{- '<|im_end|>\n' }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{%- if messages[0].role == 'system' %}
|
| 63 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 64 |
+
{{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
|
| 65 |
+
{%- endif %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 68 |
+
{%- for message in messages[::-1] %}
|
| 69 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 70 |
+
{%- if ns.multi_step_tool and message.role == "user" %}
|
| 71 |
+
{%- set content = render_content(message.content, false)|trim %}
|
| 72 |
+
{%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
|
| 73 |
+
{%- set ns.multi_step_tool = false %}
|
| 74 |
+
{%- set ns.last_query_index = index %}
|
| 75 |
+
{%- endif %}
|
| 76 |
+
{%- endif %}
|
| 77 |
+
{%- endfor %}
|
| 78 |
+
{%- if ns.multi_step_tool %}
|
| 79 |
+
{{- raise_exception('No user query found in messages.') }}
|
| 80 |
+
{%- endif %}
|
| 81 |
+
{%- for message in messages %}
|
| 82 |
+
{%- set content = render_content(message.content, true)|trim %}
|
| 83 |
+
{%- if message.role == "system" %}
|
| 84 |
+
{%- if not loop.first %}
|
| 85 |
+
{{- raise_exception('System message must be at the beginning.') }}
|
| 86 |
+
{%- endif %}
|
| 87 |
+
{%- elif message.role == "user" %}
|
| 88 |
+
{{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
|
| 89 |
+
{%- elif message.role == "assistant" %}
|
| 90 |
+
{%- set reasoning_content = '' %}
|
| 91 |
+
{%- if message.reasoning_content is string %}
|
| 92 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 93 |
+
{%- else %}
|
| 94 |
+
{%- if '</think>' in content %}
|
| 95 |
+
{%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 96 |
+
{%- set content = content.split('</think>')[-1].lstrip('\n') %}
|
| 97 |
+
{%- endif %}
|
| 98 |
+
{%- endif %}
|
| 99 |
+
{%- set reasoning_content = reasoning_content|trim %}
|
| 100 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 101 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
|
| 102 |
+
{%- else %}
|
| 103 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 104 |
+
{%- endif %}
|
| 105 |
+
{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
|
| 106 |
+
{%- for tool_call in message.tool_calls %}
|
| 107 |
+
{%- if tool_call.function is defined %}
|
| 108 |
+
{%- set tool_call = tool_call.function %}
|
| 109 |
+
{%- endif %}
|
| 110 |
+
{%- if loop.first %}
|
| 111 |
+
{%- if content|trim %}
|
| 112 |
+
{{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 113 |
+
{%- else %}
|
| 114 |
+
{{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 115 |
+
{%- endif %}
|
| 116 |
+
{%- else %}
|
| 117 |
+
{{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 118 |
+
{%- endif %}
|
| 119 |
+
{%- if tool_call.arguments is defined %}
|
| 120 |
+
{%- for args_name, args_value in tool_call.arguments|items %}
|
| 121 |
+
{{- '<parameter=' + args_name + '>\n' }}
|
| 122 |
+
{%- set args_value = args_value | tojson | safe if args_value is mapping or (args_value is sequence and args_value is not string) else args_value | string %}
|
| 123 |
+
{{- args_value }}
|
| 124 |
+
{{- '\n</parameter>\n' }}
|
| 125 |
+
{%- endfor %}
|
| 126 |
+
{%- endif %}
|
| 127 |
+
{{- '</function>\n</tool_call>' }}
|
| 128 |
+
{%- endfor %}
|
| 129 |
+
{%- endif %}
|
| 130 |
+
{{- '<|im_end|>\n' }}
|
| 131 |
+
{%- elif message.role == "tool" %}
|
| 132 |
+
{%- if loop.previtem and loop.previtem.role != "tool" %}
|
| 133 |
+
{{- '<|im_start|>user' }}
|
| 134 |
+
{%- endif %}
|
| 135 |
+
{{- '\n<tool_response>\n' }}
|
| 136 |
+
{{- content }}
|
| 137 |
+
{{- '\n</tool_response>' }}
|
| 138 |
+
{%- if not loop.last and loop.nextitem.role != "tool" %}
|
| 139 |
+
{{- '<|im_end|>\n' }}
|
| 140 |
+
{%- elif loop.last %}
|
| 141 |
+
{{- '<|im_end|>\n' }}
|
| 142 |
+
{%- endif %}
|
| 143 |
+
{%- else %}
|
| 144 |
+
{{- raise_exception('Unexpected message role.') }}
|
| 145 |
+
{%- endif %}
|
| 146 |
+
{%- endfor %}
|
| 147 |
+
{%- if add_generation_prompt %}
|
| 148 |
+
{{- '<|im_start|>assistant\n' }}
|
| 149 |
+
{%- if enable_thinking is defined and enable_thinking is true %}
|
| 150 |
+
{{- '<think>\n' }}
|
| 151 |
+
{%- else %}
|
| 152 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 153 |
+
{%- endif %}
|
| 154 |
+
{%- endif %}
|
examples/inference.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openthai_systemone_onnx import Choice, Noul, OnnxSystemOneClient, Score
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
client = OnnxSystemOneClient("imtk/OpenThai-SystemOne-ONNX")
|
| 5 |
+
response = client.system_one(
|
| 6 |
+
"ร้านนี้บริการดีมาก แต่อาหารค่อนข้างช้า",
|
| 7 |
+
{
|
| 8 |
+
"sentiment": Choice(
|
| 9 |
+
instructions="What is the overall sentiment?",
|
| 10 |
+
criteria={"positive": None, "neutral": None, "negative": None},
|
| 11 |
+
),
|
| 12 |
+
"recommend": Noul(instructions="Would the writer recommend the restaurant?"),
|
| 13 |
+
"quality": Score(
|
| 14 |
+
instructions="Rate the service quality.",
|
| 15 |
+
criteria=["poor", "acceptable", "good", "excellent"],
|
| 16 |
+
),
|
| 17 |
+
},
|
| 18 |
+
)
|
| 19 |
+
print(response.model_dump_json(indent=2))
|
| 20 |
+
|
onnx/model.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:725e6b85effd2a861ccdf7ea15a4d8f05a089d4ec3bc34c6a058abace65f9532
|
| 3 |
+
size 322508
|
onnx/model.onnx.data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:259b8a487cf1e4cecdc840cfc4eefa288f56538fa1e6b69376461d0ffbb0c9f3
|
| 3 |
+
size 3078303744
|
pyproject.toml
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["hatchling==1.27.0"]
|
| 3 |
+
build-backend = "hatchling.build"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "openthai-systemone-onnx"
|
| 7 |
+
version = "0.1.0"
|
| 8 |
+
description = "Dynamic ONNX Runtime export and drop-in client for OpenThai-SystemOne"
|
| 9 |
+
readme = "README.md"
|
| 10 |
+
requires-python = ">=3.12,<3.13"
|
| 11 |
+
license = {file = "LICENSE"}
|
| 12 |
+
authors = [{name = "OpenThai-SystemOne ONNX contributors"}]
|
| 13 |
+
dependencies = [
|
| 14 |
+
"huggingface-hub==1.5.0",
|
| 15 |
+
"numpy==2.3.3",
|
| 16 |
+
"onnxruntime==1.30.0",
|
| 17 |
+
"openthai-systemone @ git+https://github.com/iapp-technology/openthai-systemone.git@5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf",
|
| 18 |
+
"torch==2.8.0",
|
| 19 |
+
"transformers @ git+https://github.com/huggingface/transformers.git@856157a2f3e9594954310df18fdccc31ffddebe9",
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
[project.optional-dependencies]
|
| 23 |
+
tools = [
|
| 24 |
+
"onnx==1.19.0",
|
| 25 |
+
"onnx-ir==0.1.3",
|
| 26 |
+
"onnxruntime-genai==0.16.0",
|
| 27 |
+
"safetensors==0.8.0",
|
| 28 |
+
]
|
| 29 |
+
dev = [
|
| 30 |
+
"pytest==8.4.2",
|
| 31 |
+
"pytest-cov==7.0.0",
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
[project.scripts]
|
| 35 |
+
openthai-systemone-export = "openthai_systemone_onnx_tools.export:main"
|
| 36 |
+
openthai-systemone-validate = "openthai_systemone_onnx_tools.validation:main"
|
| 37 |
+
openthai-systemone-upload = "openthai_systemone_onnx_tools.upload:main"
|
| 38 |
+
|
| 39 |
+
[tool.hatch.build.targets.wheel]
|
| 40 |
+
packages = ["src/openthai_systemone_onnx", "src/openthai_systemone_onnx_tools"]
|
| 41 |
+
|
| 42 |
+
[tool.hatch.metadata]
|
| 43 |
+
allow-direct-references = true
|
| 44 |
+
|
| 45 |
+
[tool.pytest.ini_options]
|
| 46 |
+
testpaths = ["tests"]
|
| 47 |
+
addopts = "-ra"
|
| 48 |
+
markers = [
|
| 49 |
+
"artifact: requires an exported ONNX artifact",
|
| 50 |
+
"parity: loads the source PyTorch model and ONNX graph",
|
| 51 |
+
"slow: high-memory 65,536-token parity validation",
|
| 52 |
+
]
|
| 53 |
+
|
| 54 |
+
[tool.uv]
|
| 55 |
+
package = true
|
src/openthai_systemone_onnx/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Drop-in ONNX Runtime client for OpenThai-SystemOne."""
|
| 2 |
+
|
| 3 |
+
from openthai_systemone.types import (
|
| 4 |
+
Answer,
|
| 5 |
+
Choice,
|
| 6 |
+
ChoiceAnswer,
|
| 7 |
+
Noul,
|
| 8 |
+
NoulAnswer,
|
| 9 |
+
Question,
|
| 10 |
+
Score,
|
| 11 |
+
ScoreAnswer,
|
| 12 |
+
SystemOneRequest,
|
| 13 |
+
SystemOneResponse,
|
| 14 |
+
Usage,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
from .client import OnnxSystemOneClient
|
| 18 |
+
|
| 19 |
+
__version__ = "0.1.0"
|
| 20 |
+
|
| 21 |
+
__all__ = [
|
| 22 |
+
"Answer",
|
| 23 |
+
"Choice",
|
| 24 |
+
"ChoiceAnswer",
|
| 25 |
+
"Noul",
|
| 26 |
+
"NoulAnswer",
|
| 27 |
+
"OnnxSystemOneClient",
|
| 28 |
+
"Question",
|
| 29 |
+
"Score",
|
| 30 |
+
"ScoreAnswer",
|
| 31 |
+
"SystemOneRequest",
|
| 32 |
+
"SystemOneResponse",
|
| 33 |
+
"Usage",
|
| 34 |
+
]
|
| 35 |
+
|
src/openthai_systemone_onnx/artifact.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Artifact metadata and checksum helpers."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
from datetime import datetime, timezone
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Any
|
| 10 |
+
|
| 11 |
+
from .constants import (
|
| 12 |
+
MAX_POSITION_EMBEDDINGS,
|
| 13 |
+
NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 14 |
+
PUBLIC_TENSORS,
|
| 15 |
+
REQUIRED_CONTRIB_OPS,
|
| 16 |
+
REQUIRED_OPERATOR_DOMAINS,
|
| 17 |
+
REQUIRED_ORT_GENAI_VERSION,
|
| 18 |
+
REQUIRED_ORT_VERSION,
|
| 19 |
+
SOURCE_MODEL,
|
| 20 |
+
SOURCE_REVISION,
|
| 21 |
+
TARGET_REPOSITORY,
|
| 22 |
+
UPSTREAM_CLIENT_REVISION,
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def sha256_file(path: Path, chunk_size: int = 8 * 1024 * 1024) -> str:
|
| 27 |
+
digest = hashlib.sha256()
|
| 28 |
+
with path.open("rb") as handle:
|
| 29 |
+
while block := handle.read(chunk_size):
|
| 30 |
+
digest.update(block)
|
| 31 |
+
return digest.hexdigest()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def artifact_checksums(root: Path) -> dict[str, str]:
|
| 35 |
+
ignored = {"artifact-manifest.json", "validation-report.json"}
|
| 36 |
+
return {
|
| 37 |
+
path.relative_to(root).as_posix(): sha256_file(path)
|
| 38 |
+
for path in sorted(root.rglob("*"))
|
| 39 |
+
if path.is_file() and path.relative_to(root).as_posix() not in ignored
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def build_manifest(root: Path, *, extra: dict[str, Any] | None = None) -> dict[str, Any]:
|
| 44 |
+
manifest: dict[str, Any] = {
|
| 45 |
+
"format_version": 1,
|
| 46 |
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
| 47 |
+
"source": {"repo_id": SOURCE_MODEL, "revision": SOURCE_REVISION},
|
| 48 |
+
"upstream_client": {
|
| 49 |
+
"repository": "iapp-technology/openthai-systemone",
|
| 50 |
+
"revision": UPSTREAM_CLIENT_REVISION,
|
| 51 |
+
},
|
| 52 |
+
"target_repository": TARGET_REPOSITORY,
|
| 53 |
+
"graph": "onnx/model.onnx",
|
| 54 |
+
"external_data": "onnx/model.onnx.data",
|
| 55 |
+
"precision": "fp32",
|
| 56 |
+
"max_position_embeddings": MAX_POSITION_EMBEDDINGS,
|
| 57 |
+
"numerically_validated_max_tokens": NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 58 |
+
"runtime": {
|
| 59 |
+
"onnxruntime": REQUIRED_ORT_VERSION,
|
| 60 |
+
"onnxruntime_genai_builder": REQUIRED_ORT_GENAI_VERSION,
|
| 61 |
+
"portable_to_arbitrary_onnx_engines": False,
|
| 62 |
+
},
|
| 63 |
+
"operator_domains": REQUIRED_OPERATOR_DOMAINS,
|
| 64 |
+
"required_contrib_operators": sorted(REQUIRED_CONTRIB_OPS),
|
| 65 |
+
"tensor_schema": PUBLIC_TENSORS,
|
| 66 |
+
"state_contract": "zero convolution, recurrent, and KV state is initialized inside the graph per request",
|
| 67 |
+
"checksums": artifact_checksums(root),
|
| 68 |
+
}
|
| 69 |
+
if extra:
|
| 70 |
+
manifest.update(extra)
|
| 71 |
+
return manifest
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def write_manifest(root: Path, *, extra: dict[str, Any] | None = None) -> Path:
|
| 75 |
+
destination = root / "artifact-manifest.json"
|
| 76 |
+
destination.write_text(
|
| 77 |
+
json.dumps(build_manifest(root, extra=extra), indent=2, sort_keys=True) + "\n",
|
| 78 |
+
encoding="utf-8",
|
| 79 |
+
)
|
| 80 |
+
return destination
|
| 81 |
+
|
src/openthai_systemone_onnx/client.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ONNX implementation of the upstream local client.
|
| 2 |
+
|
| 3 |
+
Only initialization and ``_run`` differ from the pinned upstream client. All
|
| 4 |
+
formatting, permutation planning, decoding, confidence calculation, response
|
| 5 |
+
models, and token accounting remain upstream code.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import json
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
from types import SimpleNamespace
|
| 13 |
+
from typing import Optional, Sequence
|
| 14 |
+
|
| 15 |
+
import numpy as np
|
| 16 |
+
import onnxruntime as ort
|
| 17 |
+
import torch
|
| 18 |
+
from huggingface_hub import snapshot_download
|
| 19 |
+
from openthai_systemone.client import SystemOneClient
|
| 20 |
+
from openthai_systemone.formatting import Encoded, Formatter, collate
|
| 21 |
+
from openthai_systemone.modeling import QTYPE_INDEX
|
| 22 |
+
from transformers import AutoTokenizer
|
| 23 |
+
|
| 24 |
+
from .constants import ABSTAIN_SLOT, MAX_POSITION_EMBEDDINGS, REQUIRED_ORT_VERSION
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _resolve_artifact(model_path: str) -> tuple[Path, Path, dict]:
|
| 28 |
+
"""Return ``(repository_root, onnx_path, manifest)`` for a local path or HF id."""
|
| 29 |
+
candidate = Path(model_path).expanduser()
|
| 30 |
+
if candidate.exists():
|
| 31 |
+
if candidate.is_file():
|
| 32 |
+
onnx_path = candidate.resolve()
|
| 33 |
+
root = onnx_path.parent.parent if onnx_path.parent.name == "onnx" else onnx_path.parent
|
| 34 |
+
else:
|
| 35 |
+
root = candidate.resolve()
|
| 36 |
+
onnx_path = root / "onnx" / "model.onnx"
|
| 37 |
+
else:
|
| 38 |
+
root = Path(
|
| 39 |
+
snapshot_download(
|
| 40 |
+
repo_id=model_path,
|
| 41 |
+
allow_patterns=[
|
| 42 |
+
"onnx/*",
|
| 43 |
+
"artifact-manifest.json",
|
| 44 |
+
"tokenizer*",
|
| 45 |
+
"special_tokens_map.json",
|
| 46 |
+
"chat_template.jinja",
|
| 47 |
+
],
|
| 48 |
+
)
|
| 49 |
+
)
|
| 50 |
+
onnx_path = root / "onnx" / "model.onnx"
|
| 51 |
+
|
| 52 |
+
if not onnx_path.is_file():
|
| 53 |
+
raise FileNotFoundError(f"ONNX graph not found: {onnx_path}")
|
| 54 |
+
manifest_path = root / "artifact-manifest.json"
|
| 55 |
+
if not manifest_path.is_file():
|
| 56 |
+
raise FileNotFoundError(f"artifact manifest not found: {manifest_path}")
|
| 57 |
+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
| 58 |
+
return root, onnx_path, manifest
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
class OnnxSystemOneClient(SystemOneClient):
|
| 62 |
+
"""A drop-in ``SystemOneClient`` backed by one ONNX Runtime graph."""
|
| 63 |
+
|
| 64 |
+
def __init__(
|
| 65 |
+
self,
|
| 66 |
+
model_path: str,
|
| 67 |
+
*,
|
| 68 |
+
device: Optional[str] = None,
|
| 69 |
+
dtype: Optional[torch.dtype] = None,
|
| 70 |
+
max_total_tokens: int = 65536,
|
| 71 |
+
max_state_tokens: int = 32768,
|
| 72 |
+
model_name: str = "openthai-systemone",
|
| 73 |
+
):
|
| 74 |
+
if dtype is not None and dtype is not torch.float32:
|
| 75 |
+
raise TypeError(
|
| 76 |
+
"OpenThai-SystemOne-ONNX is an FP32 artifact; dtype must be None or torch.float32"
|
| 77 |
+
)
|
| 78 |
+
if max_total_tokens < 1 or max_total_tokens > MAX_POSITION_EMBEDDINGS:
|
| 79 |
+
raise ValueError(
|
| 80 |
+
f"max_total_tokens must be in 1..{MAX_POSITION_EMBEDDINGS:,}, got {max_total_tokens:,}"
|
| 81 |
+
)
|
| 82 |
+
if max_state_tokens < 1 or max_state_tokens > MAX_POSITION_EMBEDDINGS:
|
| 83 |
+
raise ValueError(
|
| 84 |
+
f"max_state_tokens must be in 1..{MAX_POSITION_EMBEDDINGS:,}, got {max_state_tokens:,}"
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
normalized_device = "cpu" if device is None else str(device).lower()
|
| 88 |
+
provider_for_device = {
|
| 89 |
+
"cpu": "CPUExecutionProvider",
|
| 90 |
+
"cuda": "CUDAExecutionProvider",
|
| 91 |
+
}
|
| 92 |
+
if normalized_device not in provider_for_device:
|
| 93 |
+
raise ValueError("device must be None, 'cpu', or 'cuda'; MPS and other ONNX providers are unsupported")
|
| 94 |
+
provider = provider_for_device[normalized_device]
|
| 95 |
+
available = ort.get_available_providers()
|
| 96 |
+
if provider not in available:
|
| 97 |
+
raise RuntimeError(
|
| 98 |
+
f"{provider} is not installed; available ONNX Runtime providers: {available}"
|
| 99 |
+
)
|
| 100 |
+
if ort.__version__ != REQUIRED_ORT_VERSION:
|
| 101 |
+
raise RuntimeError(
|
| 102 |
+
f"This artifact requires onnxruntime=={REQUIRED_ORT_VERSION}; found {ort.__version__}"
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
root, onnx_path, manifest = _resolve_artifact(model_path)
|
| 106 |
+
artifact_limit = int(manifest.get("max_position_embeddings", 0))
|
| 107 |
+
if artifact_limit != MAX_POSITION_EMBEDDINGS:
|
| 108 |
+
raise ValueError(
|
| 109 |
+
f"artifact max_position_embeddings is {artifact_limit}, expected {MAX_POSITION_EMBEDDINGS}"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
self.device = normalized_device
|
| 113 |
+
self.dtype = torch.float32
|
| 114 |
+
self.manifest = manifest
|
| 115 |
+
self.tok = AutoTokenizer.from_pretrained(root, local_files_only=True)
|
| 116 |
+
self.fmt = Formatter(
|
| 117 |
+
self.tok,
|
| 118 |
+
max_total_tokens=max_total_tokens,
|
| 119 |
+
max_state_tokens=max_state_tokens,
|
| 120 |
+
)
|
| 121 |
+
self.model_name = model_name
|
| 122 |
+
self.max_position_embeddings = artifact_limit
|
| 123 |
+
pad = self.tok.pad_token_id
|
| 124 |
+
self.pad_id = pad if pad is not None else (self.tok.eos_token_id or 0)
|
| 125 |
+
|
| 126 |
+
# The inherited decoder reads only model.config.abstain_slot.
|
| 127 |
+
self.model = SimpleNamespace(config=SimpleNamespace(abstain_slot=ABSTAIN_SLOT))
|
| 128 |
+
options = ort.SessionOptions()
|
| 129 |
+
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
|
| 130 |
+
self.session = ort.InferenceSession(str(onnx_path), sess_options=options, providers=[provider])
|
| 131 |
+
expected_inputs = {"input_ids", "attention_mask", "answer_positions", "option_counts", "qtypes"}
|
| 132 |
+
actual_inputs = {item.name for item in self.session.get_inputs()}
|
| 133 |
+
if actual_inputs != expected_inputs:
|
| 134 |
+
raise ValueError(
|
| 135 |
+
f"unexpected ONNX input contract: expected {sorted(expected_inputs)}, got {sorted(actual_inputs)}"
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
@torch.no_grad()
|
| 139 |
+
def _run(self, encs: Sequence[Encoded]) -> torch.Tensor:
|
| 140 |
+
if not encs:
|
| 141 |
+
return torch.empty((0, 0, 256), dtype=torch.float32)
|
| 142 |
+
longest = max(enc.n_tokens for enc in encs)
|
| 143 |
+
if longest > self.max_position_embeddings:
|
| 144 |
+
raise ValueError(
|
| 145 |
+
f"encoded input has {longest:,} tokens; the backbone limit is "
|
| 146 |
+
f"{self.max_position_embeddings:,}"
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
batch = collate(encs, self.pad_id)
|
| 150 |
+
qtypes = torch.full_like(batch["option_counts"], -1)
|
| 151 |
+
for batch_index, encoded in enumerate(encs):
|
| 152 |
+
for question_index, spec in enumerate(encoded.specs):
|
| 153 |
+
qtypes[batch_index, question_index] = QTYPE_INDEX[spec.qtype]
|
| 154 |
+
|
| 155 |
+
feeds = {
|
| 156 |
+
"input_ids": batch["input_ids"].numpy().astype(np.int64, copy=False),
|
| 157 |
+
"attention_mask": batch["attention_mask"].numpy().astype(np.int64, copy=False),
|
| 158 |
+
"answer_positions": batch["answer_positions"].numpy().astype(np.int64, copy=False),
|
| 159 |
+
"option_counts": batch["option_counts"].numpy().astype(np.int64, copy=False),
|
| 160 |
+
"qtypes": qtypes.numpy().astype(np.int64, copy=False),
|
| 161 |
+
}
|
| 162 |
+
probabilities = self.session.run(["probabilities"], feeds)[0]
|
| 163 |
+
return torch.from_numpy(np.asarray(probabilities, dtype=np.float32))
|
| 164 |
+
|
src/openthai_systemone_onnx/constants.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Constants required by the lightweight ONNX client runtime."""
|
| 2 |
+
|
| 3 |
+
MAX_POSITION_EMBEDDINGS = 262_144
|
| 4 |
+
ABSTAIN_SLOT = 255
|
| 5 |
+
N_SLOTS = 256
|
| 6 |
+
|
| 7 |
+
REQUIRED_ORT_VERSION = "1.30.0"
|
src/openthai_systemone_onnx/export.py
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build the dynamic FP32 OpenThai-SystemOne ONNX Runtime graph."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import shutil
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import onnx_ir as ir
|
| 11 |
+
import torch
|
| 12 |
+
from huggingface_hub import snapshot_download
|
| 13 |
+
from transformers import AutoConfig, AutoModel
|
| 14 |
+
|
| 15 |
+
from onnxruntime_genai.models.builders.qwen import Qwen35TextModel
|
| 16 |
+
|
| 17 |
+
from .artifact import write_manifest
|
| 18 |
+
from .constants import (
|
| 19 |
+
ABSTAIN_SLOT,
|
| 20 |
+
MAX_POSITION_EMBEDDINGS,
|
| 21 |
+
N_SLOTS,
|
| 22 |
+
REQUIRED_ORT_GENAI_VERSION,
|
| 23 |
+
SOURCE_MODEL,
|
| 24 |
+
SOURCE_REVISION,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class OpenThaiDynamicBuilder(Qwen35TextModel):
|
| 29 |
+
"""Qwen3.5 builder with internal state and the OpenThai decision head."""
|
| 30 |
+
|
| 31 |
+
def make_node(self, op_type, inputs, outputs, *, name, domain="", **kwargs):
|
| 32 |
+
"""Normalize ONNX integer attributes before ONNX IR serialization.
|
| 33 |
+
|
| 34 |
+
ONNX represents flags such as ``keepdims`` as INT attributes. ORT
|
| 35 |
+
GenAI 0.16 passes Python booleans for a few of them. ONNX IR 0.1.3
|
| 36 |
+
infers the correct INT attribute type but otherwise retains the bool,
|
| 37 |
+
which protobuf serialization rejects because ``bool`` is not accepted
|
| 38 |
+
for ``AttributeProto.i``.
|
| 39 |
+
"""
|
| 40 |
+
# ORT GenAI 0.16 emits an ORT-private default-domain
|
| 41 |
+
# SimplifiedLayerNormalization op. ONNX Runtime can load that op, but
|
| 42 |
+
# the ONNX checker correctly rejects it because it has no ONNX schema.
|
| 43 |
+
# ONNX opset 23 standardizes the same RMSNorm operation, so lower the
|
| 44 |
+
# standalone form to RMSNormalization. The fused skip form remains the
|
| 45 |
+
# com.microsoft contrib op.
|
| 46 |
+
if op_type == "SimplifiedLayerNormalization" and not domain:
|
| 47 |
+
op_type = "RMSNormalization"
|
| 48 |
+
self.graph.opset_imports[""] = 23
|
| 49 |
+
|
| 50 |
+
normalized = {
|
| 51 |
+
key: int(value) if isinstance(value, (bool, np.bool_)) else value
|
| 52 |
+
for key, value in kwargs.items()
|
| 53 |
+
}
|
| 54 |
+
return super().make_node(
|
| 55 |
+
op_type,
|
| 56 |
+
inputs,
|
| 57 |
+
outputs,
|
| 58 |
+
name=name,
|
| 59 |
+
domain=domain,
|
| 60 |
+
**normalized,
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
def load_weights(self, input_path):
|
| 64 |
+
return AutoModel.from_pretrained(
|
| 65 |
+
input_path,
|
| 66 |
+
trust_remote_code=True,
|
| 67 |
+
local_files_only=True,
|
| 68 |
+
dtype=torch.float32,
|
| 69 |
+
).eval()
|
| 70 |
+
|
| 71 |
+
def make_inputs_and_outputs(self):
|
| 72 |
+
self.input_shapes["position_ids"] = [3, "batch_size", "sequence_length"]
|
| 73 |
+
|
| 74 |
+
public_inputs = {
|
| 75 |
+
"input_ids": (ir.DataType.INT64, ["batch_size", "sequence_length"]),
|
| 76 |
+
"attention_mask": (ir.DataType.INT64, ["batch_size", "sequence_length"]),
|
| 77 |
+
"answer_positions": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 78 |
+
"option_counts": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 79 |
+
"qtypes": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 80 |
+
}
|
| 81 |
+
for name, (dtype, shape) in public_inputs.items():
|
| 82 |
+
self.model.graph.inputs.append(self.make_value(name, dtype=dtype, shape=shape))
|
| 83 |
+
|
| 84 |
+
output_shape = ["batch_size", "num_questions", N_SLOTS]
|
| 85 |
+
self.model.graph.outputs.append(self.make_value("logits", ir.DataType.FLOAT, output_shape))
|
| 86 |
+
self.model.graph.outputs.append(self.make_value("probabilities", ir.DataType.FLOAT, output_shape))
|
| 87 |
+
|
| 88 |
+
def _dynamic_batch_dimension(self) -> str:
|
| 89 |
+
shape_name = "/openthai/internal/input_shape"
|
| 90 |
+
self.make_shape(shape_name, "input_ids", shape=[2])
|
| 91 |
+
gather_name = "/openthai/internal/batch_dimension"
|
| 92 |
+
self.make_gather(
|
| 93 |
+
gather_name,
|
| 94 |
+
[f"{shape_name}/output_0", "/model/constants/INT64/0"],
|
| 95 |
+
dtype=ir.DataType.INT64,
|
| 96 |
+
shape=[],
|
| 97 |
+
axis=0,
|
| 98 |
+
)
|
| 99 |
+
unsqueeze_name = "/openthai/internal/batch_dimension_unsqueezed"
|
| 100 |
+
self.make_unsqueeze(
|
| 101 |
+
unsqueeze_name,
|
| 102 |
+
[f"{gather_name}/output_0", "/model/constants/INT64/[0]"],
|
| 103 |
+
dtype=ir.DataType.INT64,
|
| 104 |
+
shape=[1],
|
| 105 |
+
)
|
| 106 |
+
return f"{unsqueeze_name}/output_0"
|
| 107 |
+
|
| 108 |
+
def _zero_tensor(self, name: str, shape_input: str, dtype: ir.DataType, shape):
|
| 109 |
+
if dtype != ir.DataType.FLOAT:
|
| 110 |
+
raise TypeError(f"internal request state must be FP32, got {dtype}")
|
| 111 |
+
zero = ir.tensor(np.asarray([0], dtype=np.float32))
|
| 112 |
+
node_name = f"/openthai/internal/zero/{name.replace('.', '_')}"
|
| 113 |
+
self.make_node(
|
| 114 |
+
"ConstantOfShape",
|
| 115 |
+
inputs=[shape_input],
|
| 116 |
+
outputs=[name],
|
| 117 |
+
name=node_name,
|
| 118 |
+
value=zero,
|
| 119 |
+
)
|
| 120 |
+
self.make_value(name, dtype=dtype, shape=shape)
|
| 121 |
+
|
| 122 |
+
def _make_internal_request_state(self):
|
| 123 |
+
batch = self._dynamic_batch_dimension()
|
| 124 |
+
shape_specs = {
|
| 125 |
+
"kv": [self.num_kv_heads, 0, self.head_size],
|
| 126 |
+
"conv": [self.linear_conv_dim, self.linear_conv_kernel_dim - 1],
|
| 127 |
+
"recurrent": [
|
| 128 |
+
self.linear_num_value_heads,
|
| 129 |
+
self.linear_key_head_dim,
|
| 130 |
+
self.linear_value_head_dim,
|
| 131 |
+
],
|
| 132 |
+
}
|
| 133 |
+
shape_paths: dict[str, str] = {}
|
| 134 |
+
for label, tail in shape_specs.items():
|
| 135 |
+
concat_name = f"/openthai/internal/{label}_state_shape"
|
| 136 |
+
self.make_concat(
|
| 137 |
+
concat_name,
|
| 138 |
+
[batch, f"/model/constants/INT64/{tail}"],
|
| 139 |
+
dtype=ir.DataType.INT64,
|
| 140 |
+
shape=[1 + len(tail)],
|
| 141 |
+
axis=0,
|
| 142 |
+
)
|
| 143 |
+
shape_paths[label] = f"{concat_name}/output_0"
|
| 144 |
+
|
| 145 |
+
for cache_kind in ("past_key_values.key", "past_key_values.value"):
|
| 146 |
+
for cache_name in self.input_names[cache_kind].values():
|
| 147 |
+
self._zero_tensor(
|
| 148 |
+
cache_name,
|
| 149 |
+
shape_paths["kv"],
|
| 150 |
+
self.io_dtype,
|
| 151 |
+
["batch_size", self.num_kv_heads, 0, self.head_size],
|
| 152 |
+
)
|
| 153 |
+
for cache_name in self.input_names["past.conv"].values():
|
| 154 |
+
self._zero_tensor(
|
| 155 |
+
cache_name,
|
| 156 |
+
shape_paths["conv"],
|
| 157 |
+
self.io_dtype,
|
| 158 |
+
["batch_size", self.linear_conv_dim, self.linear_conv_kernel_dim - 1],
|
| 159 |
+
)
|
| 160 |
+
for cache_name in self.input_names["past.recurrent"].values():
|
| 161 |
+
self._zero_tensor(
|
| 162 |
+
cache_name,
|
| 163 |
+
shape_paths["recurrent"],
|
| 164 |
+
self.input_types["past.recurrent"],
|
| 165 |
+
[
|
| 166 |
+
"batch_size",
|
| 167 |
+
self.linear_num_value_heads,
|
| 168 |
+
self.linear_key_head_dim,
|
| 169 |
+
self.linear_value_head_dim,
|
| 170 |
+
],
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
def _make_dynamic_text_positions(self):
|
| 174 |
+
cumsum_name = "/openthai/positions/CumSum"
|
| 175 |
+
self.make_node(
|
| 176 |
+
"CumSum",
|
| 177 |
+
inputs=["attention_mask", "/model/constants/INT64/1"],
|
| 178 |
+
outputs=[f"{cumsum_name}/output_0"],
|
| 179 |
+
name=cumsum_name,
|
| 180 |
+
)
|
| 181 |
+
self.make_value(
|
| 182 |
+
f"{cumsum_name}/output_0",
|
| 183 |
+
ir.DataType.INT64,
|
| 184 |
+
["batch_size", "sequence_length"],
|
| 185 |
+
)
|
| 186 |
+
sub_name = "/openthai/positions/SubOne"
|
| 187 |
+
self.make_sub(
|
| 188 |
+
sub_name,
|
| 189 |
+
[f"{cumsum_name}/output_0", "/model/constants/INT64/1"],
|
| 190 |
+
ir.DataType.INT64,
|
| 191 |
+
["batch_size", "sequence_length"],
|
| 192 |
+
)
|
| 193 |
+
padded_name = "/openthai/positions/IsPadding"
|
| 194 |
+
self.make_equal(
|
| 195 |
+
padded_name,
|
| 196 |
+
["attention_mask", "/model/constants/INT64/0"],
|
| 197 |
+
["batch_size", "sequence_length"],
|
| 198 |
+
)
|
| 199 |
+
where_name = "/openthai/positions/ReplacePadding"
|
| 200 |
+
self.make_node(
|
| 201 |
+
"Where",
|
| 202 |
+
inputs=[
|
| 203 |
+
f"{padded_name}/output_0",
|
| 204 |
+
"/model/constants/INT64/0",
|
| 205 |
+
f"{sub_name}/output_0",
|
| 206 |
+
],
|
| 207 |
+
outputs=[f"{where_name}/output_0"],
|
| 208 |
+
name=where_name,
|
| 209 |
+
)
|
| 210 |
+
self.make_value(
|
| 211 |
+
f"{where_name}/output_0",
|
| 212 |
+
ir.DataType.INT64,
|
| 213 |
+
["batch_size", "sequence_length"],
|
| 214 |
+
)
|
| 215 |
+
unsqueeze_name = "/openthai/positions/Unsqueeze"
|
| 216 |
+
self.make_unsqueeze(
|
| 217 |
+
unsqueeze_name,
|
| 218 |
+
[f"{where_name}/output_0", "/model/constants/INT64/[0]"],
|
| 219 |
+
ir.DataType.INT64,
|
| 220 |
+
[1, "batch_size", "sequence_length"],
|
| 221 |
+
)
|
| 222 |
+
tile_name = "/openthai/positions/TileMRoPE"
|
| 223 |
+
self.make_node(
|
| 224 |
+
"Tile",
|
| 225 |
+
inputs=[f"{unsqueeze_name}/output_0", "/model/constants/INT64/[3, 1, 1]"],
|
| 226 |
+
outputs=[self.input_names["position_ids"]],
|
| 227 |
+
name=tile_name,
|
| 228 |
+
)
|
| 229 |
+
self.make_value(
|
| 230 |
+
self.input_names["position_ids"],
|
| 231 |
+
ir.DataType.INT64,
|
| 232 |
+
[3, "batch_size", "sequence_length"],
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
def make_preprocessing_nodes(self):
|
| 236 |
+
self._make_internal_request_state()
|
| 237 |
+
self._make_dynamic_text_positions()
|
| 238 |
+
super().make_preprocessing_nodes()
|
| 239 |
+
|
| 240 |
+
def make_postprocessing_nodes(self):
|
| 241 |
+
"""Gather answers, apply the calibrated head, mask slots, and softmax."""
|
| 242 |
+
shape = ["batch_size", "num_questions", N_SLOTS]
|
| 243 |
+
index_shape_name = "/openthai/head/AnswerIndexShape"
|
| 244 |
+
self.make_shape(index_shape_name, "answer_positions", shape=[2])
|
| 245 |
+
target_shape_name = "/openthai/head/ExpandedIndexShape"
|
| 246 |
+
self.make_concat(
|
| 247 |
+
target_shape_name,
|
| 248 |
+
[f"{index_shape_name}/output_0", f"/model/constants/INT64/[{self.hidden_size}]"],
|
| 249 |
+
ir.DataType.INT64,
|
| 250 |
+
[3],
|
| 251 |
+
)
|
| 252 |
+
clamped_name = "/openthai/head/ClampAnswerPositions"
|
| 253 |
+
self.make_node(
|
| 254 |
+
"Max",
|
| 255 |
+
inputs=["answer_positions", "/model/constants/INT64/0"],
|
| 256 |
+
outputs=[f"{clamped_name}/output_0"],
|
| 257 |
+
name=clamped_name,
|
| 258 |
+
)
|
| 259 |
+
self.make_value(
|
| 260 |
+
f"{clamped_name}/output_0",
|
| 261 |
+
ir.DataType.INT64,
|
| 262 |
+
["batch_size", "num_questions"],
|
| 263 |
+
)
|
| 264 |
+
unsqueeze_name = "/openthai/head/UnsqueezeAnswerPositions"
|
| 265 |
+
self.make_unsqueeze(
|
| 266 |
+
unsqueeze_name,
|
| 267 |
+
[f"{clamped_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 268 |
+
ir.DataType.INT64,
|
| 269 |
+
["batch_size", "num_questions", 1],
|
| 270 |
+
)
|
| 271 |
+
expand_name = "/openthai/head/ExpandAnswerPositions"
|
| 272 |
+
self.make_expand(
|
| 273 |
+
expand_name,
|
| 274 |
+
[f"{unsqueeze_name}/output_0", f"{target_shape_name}/output_0"],
|
| 275 |
+
ir.DataType.INT64,
|
| 276 |
+
["batch_size", "num_questions", self.hidden_size],
|
| 277 |
+
)
|
| 278 |
+
gather_name = "/openthai/head/GatherAnswerStates"
|
| 279 |
+
self.make_node(
|
| 280 |
+
"GatherElements",
|
| 281 |
+
inputs=["hidden_states", f"{expand_name}/output_0"],
|
| 282 |
+
outputs=[f"{gather_name}/output_0"],
|
| 283 |
+
name=gather_name,
|
| 284 |
+
axis=1,
|
| 285 |
+
)
|
| 286 |
+
self.make_value(
|
| 287 |
+
f"{gather_name}/output_0",
|
| 288 |
+
ir.DataType.FLOAT,
|
| 289 |
+
["batch_size", "num_questions", self.hidden_size],
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
weight_name = "openthai.slot_head.weight.transposed"
|
| 293 |
+
bias_name = "openthai.slot_head.bias"
|
| 294 |
+
temperature_name = "openthai.temperature"
|
| 295 |
+
self.make_initializer(
|
| 296 |
+
self.weights.slot_head.weight.detach().float().t().contiguous(),
|
| 297 |
+
weight_name,
|
| 298 |
+
to=ir.DataType.FLOAT,
|
| 299 |
+
)
|
| 300 |
+
self.make_initializer(
|
| 301 |
+
self.weights.slot_head.bias.detach().float(),
|
| 302 |
+
bias_name,
|
| 303 |
+
to=ir.DataType.FLOAT,
|
| 304 |
+
)
|
| 305 |
+
self.make_initializer(
|
| 306 |
+
self.weights.log_temperature.detach().float().exp(),
|
| 307 |
+
temperature_name,
|
| 308 |
+
to=ir.DataType.FLOAT,
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
matmul_name = "/openthai/head/SlotMatMul"
|
| 312 |
+
self.make_node(
|
| 313 |
+
"MatMul",
|
| 314 |
+
inputs=[f"{gather_name}/output_0", weight_name],
|
| 315 |
+
outputs=[f"{matmul_name}/output_0"],
|
| 316 |
+
name=matmul_name,
|
| 317 |
+
)
|
| 318 |
+
self.make_value(f"{matmul_name}/output_0", ir.DataType.FLOAT, shape)
|
| 319 |
+
add_name = "/openthai/head/SlotBias"
|
| 320 |
+
self.make_add(
|
| 321 |
+
add_name,
|
| 322 |
+
[f"{matmul_name}/output_0", bias_name],
|
| 323 |
+
ir.DataType.FLOAT,
|
| 324 |
+
shape,
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
qtype_name = "/openthai/head/ClampQuestionType"
|
| 328 |
+
self.make_node(
|
| 329 |
+
"Max",
|
| 330 |
+
inputs=["qtypes", "/model/constants/INT64/0"],
|
| 331 |
+
outputs=[f"{qtype_name}/output_0"],
|
| 332 |
+
name=qtype_name,
|
| 333 |
+
)
|
| 334 |
+
self.make_value(
|
| 335 |
+
f"{qtype_name}/output_0",
|
| 336 |
+
ir.DataType.INT64,
|
| 337 |
+
["batch_size", "num_questions"],
|
| 338 |
+
)
|
| 339 |
+
temp_gather_name = "/openthai/head/GatherTemperature"
|
| 340 |
+
self.make_gather(
|
| 341 |
+
temp_gather_name,
|
| 342 |
+
[temperature_name, f"{qtype_name}/output_0"],
|
| 343 |
+
ir.DataType.FLOAT,
|
| 344 |
+
["batch_size", "num_questions"],
|
| 345 |
+
axis=0,
|
| 346 |
+
)
|
| 347 |
+
temp_unsqueeze_name = "/openthai/head/UnsqueezeTemperature"
|
| 348 |
+
self.make_unsqueeze(
|
| 349 |
+
temp_unsqueeze_name,
|
| 350 |
+
[f"{temp_gather_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 351 |
+
ir.DataType.FLOAT,
|
| 352 |
+
["batch_size", "num_questions", 1],
|
| 353 |
+
)
|
| 354 |
+
scaled_name = "/openthai/head/ApplyTemperature"
|
| 355 |
+
self.make_div(
|
| 356 |
+
scaled_name,
|
| 357 |
+
[f"{add_name}/output_0", f"{temp_unsqueeze_name}/output_0"],
|
| 358 |
+
ir.DataType.FLOAT,
|
| 359 |
+
shape,
|
| 360 |
+
)
|
| 361 |
+
|
| 362 |
+
count_name = "/openthai/head/UnsqueezeOptionCounts"
|
| 363 |
+
self.make_unsqueeze(
|
| 364 |
+
count_name,
|
| 365 |
+
["option_counts", "/model/constants/INT64/[-1]"],
|
| 366 |
+
ir.DataType.INT64,
|
| 367 |
+
["batch_size", "num_questions", 1],
|
| 368 |
+
)
|
| 369 |
+
range_name = "/openthai/head/SlotRange"
|
| 370 |
+
self.make_range(
|
| 371 |
+
range_name,
|
| 372 |
+
[
|
| 373 |
+
"/model/constants/INT64/0",
|
| 374 |
+
f"/model/constants/INT64/{N_SLOTS}",
|
| 375 |
+
"/model/constants/INT64/1",
|
| 376 |
+
],
|
| 377 |
+
ir.DataType.INT64,
|
| 378 |
+
[N_SLOTS],
|
| 379 |
+
)
|
| 380 |
+
less_name = "/openthai/head/ValidOptions"
|
| 381 |
+
self.make_node(
|
| 382 |
+
"Less",
|
| 383 |
+
inputs=[f"{range_name}/output_0", f"{count_name}/output_0"],
|
| 384 |
+
outputs=[f"{less_name}/output_0"],
|
| 385 |
+
name=less_name,
|
| 386 |
+
)
|
| 387 |
+
self.make_value(f"{less_name}/output_0", ir.DataType.BOOL, shape)
|
| 388 |
+
abstain_name = "/openthai/head/IsAbstain"
|
| 389 |
+
self.make_equal(
|
| 390 |
+
abstain_name,
|
| 391 |
+
[f"{range_name}/output_0", f"/model/constants/INT64/{ABSTAIN_SLOT}"],
|
| 392 |
+
[N_SLOTS],
|
| 393 |
+
)
|
| 394 |
+
valid_name = "/openthai/head/IncludeAbstain"
|
| 395 |
+
self.make_node(
|
| 396 |
+
"Or",
|
| 397 |
+
inputs=[f"{less_name}/output_0", f"{abstain_name}/output_0"],
|
| 398 |
+
outputs=[f"{valid_name}/output_0"],
|
| 399 |
+
name=valid_name,
|
| 400 |
+
)
|
| 401 |
+
self.make_value(f"{valid_name}/output_0", ir.DataType.BOOL, shape)
|
| 402 |
+
|
| 403 |
+
empty_name = "/openthai/head/EmptyQuestion"
|
| 404 |
+
self.make_equal(
|
| 405 |
+
empty_name,
|
| 406 |
+
["option_counts", "/model/constants/INT64/0"],
|
| 407 |
+
["batch_size", "num_questions"],
|
| 408 |
+
)
|
| 409 |
+
empty_unsqueeze_name = "/openthai/head/UnsqueezeEmptyQuestion"
|
| 410 |
+
self.make_unsqueeze(
|
| 411 |
+
empty_unsqueeze_name,
|
| 412 |
+
[f"{empty_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 413 |
+
ir.DataType.BOOL,
|
| 414 |
+
["batch_size", "num_questions", 1],
|
| 415 |
+
)
|
| 416 |
+
slot_zero_name = "/openthai/head/IsSlotZero"
|
| 417 |
+
self.make_equal(
|
| 418 |
+
slot_zero_name,
|
| 419 |
+
[f"{range_name}/output_0", "/model/constants/INT64/0"],
|
| 420 |
+
[N_SLOTS],
|
| 421 |
+
)
|
| 422 |
+
padding_slot_name = "/openthai/head/PaddingSlot"
|
| 423 |
+
self.make_node(
|
| 424 |
+
"And",
|
| 425 |
+
inputs=[f"{empty_unsqueeze_name}/output_0", f"{slot_zero_name}/output_0"],
|
| 426 |
+
outputs=[f"{padding_slot_name}/output_0"],
|
| 427 |
+
name=padding_slot_name,
|
| 428 |
+
)
|
| 429 |
+
self.make_value(f"{padding_slot_name}/output_0", ir.DataType.BOOL, shape)
|
| 430 |
+
final_valid_name = "/openthai/head/FinalValidMask"
|
| 431 |
+
self.make_node(
|
| 432 |
+
"Or",
|
| 433 |
+
inputs=[f"{valid_name}/output_0", f"{padding_slot_name}/output_0"],
|
| 434 |
+
outputs=[f"{final_valid_name}/output_0"],
|
| 435 |
+
name=final_valid_name,
|
| 436 |
+
)
|
| 437 |
+
self.make_value(f"{final_valid_name}/output_0", ir.DataType.BOOL, shape)
|
| 438 |
+
|
| 439 |
+
negative_infinity_name = "openthai.negative_infinity"
|
| 440 |
+
self.make_initializer(
|
| 441 |
+
np.asarray(float("-inf"), dtype=np.float32),
|
| 442 |
+
negative_infinity_name,
|
| 443 |
+
to=ir.DataType.FLOAT,
|
| 444 |
+
)
|
| 445 |
+
self.make_node(
|
| 446 |
+
"Where",
|
| 447 |
+
inputs=[
|
| 448 |
+
f"{final_valid_name}/output_0",
|
| 449 |
+
f"{scaled_name}/output_0",
|
| 450 |
+
negative_infinity_name,
|
| 451 |
+
],
|
| 452 |
+
outputs=["logits"],
|
| 453 |
+
name="/openthai/head/MaskInvalidSlots",
|
| 454 |
+
)
|
| 455 |
+
self.make_value("logits", ir.DataType.FLOAT, shape)
|
| 456 |
+
self.make_node(
|
| 457 |
+
"Softmax",
|
| 458 |
+
inputs=["logits"],
|
| 459 |
+
outputs=["probabilities"],
|
| 460 |
+
name="/openthai/head/Softmax",
|
| 461 |
+
axis=-1,
|
| 462 |
+
)
|
| 463 |
+
self.make_value("probabilities", ir.DataType.FLOAT, shape)
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def _copy_release_files(snapshot: Path, destination: Path):
|
| 467 |
+
tokenizer_names = {
|
| 468 |
+
"tokenizer.json",
|
| 469 |
+
"tokenizer_config.json",
|
| 470 |
+
"special_tokens_map.json",
|
| 471 |
+
"chat_template.jinja",
|
| 472 |
+
}
|
| 473 |
+
for name in tokenizer_names:
|
| 474 |
+
source = snapshot / name
|
| 475 |
+
if source.is_file():
|
| 476 |
+
shutil.copy2(source, destination / name)
|
| 477 |
+
|
| 478 |
+
project_root = Path(__file__).resolve().parents[2]
|
| 479 |
+
shutil.copy2(project_root / "LICENSE", destination / "LICENSE")
|
| 480 |
+
shutil.copy2(project_root / "MODEL_CARD.md", destination / "README.md")
|
| 481 |
+
shutil.copy2(project_root / "MODEL_CARD.md", destination / "MODEL_CARD.md")
|
| 482 |
+
shutil.copy2(project_root / "ATTRIBUTION.md", destination / "ATTRIBUTION.md")
|
| 483 |
+
shutil.copy2(project_root / "pyproject.toml", destination / "pyproject.toml")
|
| 484 |
+
shutil.copy2(project_root / "uv.lock", destination / "uv.lock")
|
| 485 |
+
shutil.copytree(
|
| 486 |
+
project_root / "src" / "openthai_systemone_onnx",
|
| 487 |
+
destination / "src" / "openthai_systemone_onnx",
|
| 488 |
+
dirs_exist_ok=True,
|
| 489 |
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
| 490 |
+
)
|
| 491 |
+
shutil.copytree(
|
| 492 |
+
project_root / "examples",
|
| 493 |
+
destination / "examples",
|
| 494 |
+
dirs_exist_ok=True,
|
| 495 |
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
def export_dynamic_model(output_dir: Path, cache_dir: Path, source: str, revision: str) -> Path:
|
| 500 |
+
if revision != SOURCE_REVISION:
|
| 501 |
+
raise ValueError(
|
| 502 |
+
f"This validated recipe is pinned to source revision {SOURCE_REVISION}; got {revision}"
|
| 503 |
+
)
|
| 504 |
+
snapshot = Path(
|
| 505 |
+
snapshot_download(
|
| 506 |
+
repo_id=source,
|
| 507 |
+
revision=revision,
|
| 508 |
+
cache_dir=cache_dir,
|
| 509 |
+
allow_patterns=[
|
| 510 |
+
"*.json",
|
| 511 |
+
"*.py",
|
| 512 |
+
"*.jinja",
|
| 513 |
+
"*.safetensors",
|
| 514 |
+
"LICENSE*",
|
| 515 |
+
"README.md",
|
| 516 |
+
],
|
| 517 |
+
)
|
| 518 |
+
)
|
| 519 |
+
config = AutoConfig.from_pretrained(snapshot, trust_remote_code=True, local_files_only=True)
|
| 520 |
+
if config.text_config.max_position_embeddings != MAX_POSITION_EMBEDDINGS:
|
| 521 |
+
raise ValueError("the pinned backbone no longer reports max_position_embeddings=262144")
|
| 522 |
+
|
| 523 |
+
output_dir.mkdir(parents=True, exist_ok=True)
|
| 524 |
+
onnx_dir = output_dir / "onnx"
|
| 525 |
+
onnx_dir.mkdir(parents=True, exist_ok=True)
|
| 526 |
+
builder_cache = cache_dir / "builder"
|
| 527 |
+
builder_cache.mkdir(parents=True, exist_ok=True)
|
| 528 |
+
options = {
|
| 529 |
+
"exclude_lm_head": True,
|
| 530 |
+
"exclude_mtp": True,
|
| 531 |
+
"filename": "model.onnx",
|
| 532 |
+
"hf_remote": True,
|
| 533 |
+
"linear_attn_op": "linear_attention",
|
| 534 |
+
"state_window": 0,
|
| 535 |
+
"use_paged_attention": False,
|
| 536 |
+
}
|
| 537 |
+
builder = OpenThaiDynamicBuilder(
|
| 538 |
+
config,
|
| 539 |
+
ir.DataType.FLOAT,
|
| 540 |
+
ir.DataType.FLOAT,
|
| 541 |
+
"cpu",
|
| 542 |
+
str(builder_cache),
|
| 543 |
+
options,
|
| 544 |
+
)
|
| 545 |
+
builder.model.metadata_props.update(
|
| 546 |
+
{
|
| 547 |
+
"source_model": source,
|
| 548 |
+
"source_revision": revision,
|
| 549 |
+
"max_position_embeddings": str(MAX_POSITION_EMBEDDINGS),
|
| 550 |
+
"onnxruntime_genai_builder": REQUIRED_ORT_GENAI_VERSION,
|
| 551 |
+
"public_state": "internal-zero-state-per-request",
|
| 552 |
+
}
|
| 553 |
+
)
|
| 554 |
+
builder.make_model(str(snapshot))
|
| 555 |
+
builder.save_model(str(onnx_dir))
|
| 556 |
+
_copy_release_files(snapshot, output_dir)
|
| 557 |
+
return write_manifest(output_dir)
|
| 558 |
+
|
| 559 |
+
|
| 560 |
+
def build_parser() -> argparse.ArgumentParser:
|
| 561 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 562 |
+
parser.add_argument("--output", type=Path, default=Path("artifacts/OpenThai-SystemOne-ONNX"))
|
| 563 |
+
parser.add_argument("--cache-dir", type=Path, default=Path(".cache/huggingface"))
|
| 564 |
+
parser.add_argument("--source", default=SOURCE_MODEL)
|
| 565 |
+
parser.add_argument("--revision", default=SOURCE_REVISION)
|
| 566 |
+
return parser
|
| 567 |
+
|
| 568 |
+
|
| 569 |
+
def main(argv: list[str] | None = None):
|
| 570 |
+
args = build_parser().parse_args(argv)
|
| 571 |
+
manifest = export_dynamic_model(args.output.resolve(), args.cache_dir.resolve(), args.source, args.revision)
|
| 572 |
+
print(f"Export complete: {manifest}")
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
if __name__ == "__main__":
|
| 576 |
+
main()
|
src/openthai_systemone_onnx/upload.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Upload a fully validated artifact to Hugging Face."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from huggingface_hub import HfApi
|
| 10 |
+
|
| 11 |
+
from .artifact import sha256_file
|
| 12 |
+
from .constants import TARGET_REPOSITORY
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
REQUIRED_STAGES = {
|
| 16 |
+
"client_compatibility",
|
| 17 |
+
"normal_parity",
|
| 18 |
+
"slow_65536_parity",
|
| 19 |
+
"structural_262144",
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def verify_upload_gate(artifact: Path):
|
| 24 |
+
report_path = artifact / "validation-report.json"
|
| 25 |
+
manifest_path = artifact / "artifact-manifest.json"
|
| 26 |
+
if not report_path.is_file() or not manifest_path.is_file():
|
| 27 |
+
raise RuntimeError("artifact manifest and validation report are both required")
|
| 28 |
+
report = json.loads(report_path.read_text(encoding="utf-8"))
|
| 29 |
+
stages = report.get("stages", {})
|
| 30 |
+
failed = sorted(
|
| 31 |
+
stage
|
| 32 |
+
for stage in REQUIRED_STAGES
|
| 33 |
+
if not stages.get(stage, {}).get("passed", False)
|
| 34 |
+
or stages.get(stage, {}).get("test_counts", {}).get("tests", 0) < 1
|
| 35 |
+
or stages.get(stage, {}).get("test_counts", {}).get("skipped", 1) != 0
|
| 36 |
+
)
|
| 37 |
+
if failed or not report.get("upload_gate", {}).get("passed", False):
|
| 38 |
+
raise RuntimeError(f"upload blocked; required validation stages not passed: {failed}")
|
| 39 |
+
|
| 40 |
+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
| 41 |
+
bad = []
|
| 42 |
+
for relative, expected in manifest.get("checksums", {}).items():
|
| 43 |
+
path = artifact / relative
|
| 44 |
+
if not path.is_file() or sha256_file(path) != expected:
|
| 45 |
+
bad.append(relative)
|
| 46 |
+
if bad:
|
| 47 |
+
raise RuntimeError(f"upload blocked; artifact checksum mismatch: {bad}")
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def main(argv: list[str] | None = None):
|
| 51 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 52 |
+
parser.add_argument("--artifact", type=Path, required=True)
|
| 53 |
+
parser.add_argument("--repo-id", default=TARGET_REPOSITORY)
|
| 54 |
+
parser.add_argument("--execute", action="store_true", help="perform the upload (default is a gate-only dry run)")
|
| 55 |
+
args = parser.parse_args(argv)
|
| 56 |
+
artifact = args.artifact.resolve()
|
| 57 |
+
verify_upload_gate(artifact)
|
| 58 |
+
if not args.execute:
|
| 59 |
+
print(f"Upload gate passed for {artifact}; rerun with --execute to upload to {args.repo_id}")
|
| 60 |
+
return
|
| 61 |
+
api = HfApi()
|
| 62 |
+
api.create_repo(args.repo_id, repo_type="model", exist_ok=True)
|
| 63 |
+
api.upload_folder(
|
| 64 |
+
repo_id=args.repo_id,
|
| 65 |
+
repo_type="model",
|
| 66 |
+
folder_path=artifact,
|
| 67 |
+
commit_message="Publish validated dynamic FP32 ONNX Runtime graph",
|
| 68 |
+
)
|
| 69 |
+
print(f"Uploaded {artifact} to https://huggingface.co/{args.repo_id}")
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
if __name__ == "__main__":
|
| 73 |
+
main()
|
src/openthai_systemone_onnx/validation.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Run reproducible validation stages and maintain the upload gate report."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import json
|
| 7 |
+
import os
|
| 8 |
+
import subprocess
|
| 9 |
+
import sys
|
| 10 |
+
import xml.etree.ElementTree as ET
|
| 11 |
+
from datetime import datetime, timezone
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
from .constants import NUMERICALLY_VALIDATED_MAX_TOKENS, SOURCE_REVISION
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
STAGE_COMMANDS = {
|
| 18 |
+
"client_compatibility": ["tests/test_client_contract.py", "tests/test_export_builder.py"],
|
| 19 |
+
"normal_parity": ["tests/test_parity.py", "-m", "parity and not slow"],
|
| 20 |
+
"slow_65536_parity": ["tests/test_parity.py", "-m", "slow"],
|
| 21 |
+
"structural_262144": ["tests/test_structure.py"],
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def _run_stage(name: str, artifact: Path) -> dict:
|
| 26 |
+
environment = os.environ.copy()
|
| 27 |
+
environment["OPENTHAI_ONNX_ARTIFACT"] = str(artifact)
|
| 28 |
+
if name == "normal_parity":
|
| 29 |
+
environment["RUN_PARITY"] = "1"
|
| 30 |
+
if name == "slow_65536_parity":
|
| 31 |
+
environment["RUN_PARITY"] = "1"
|
| 32 |
+
environment["RUN_SLOW_65536"] = "1"
|
| 33 |
+
junit_path = artifact / f".{name}.junit.xml"
|
| 34 |
+
command = [
|
| 35 |
+
sys.executable,
|
| 36 |
+
"-m",
|
| 37 |
+
"pytest",
|
| 38 |
+
"-q",
|
| 39 |
+
*STAGE_COMMANDS[name],
|
| 40 |
+
f"--junitxml={junit_path}",
|
| 41 |
+
]
|
| 42 |
+
completed = subprocess.run(command, env=environment, text=True)
|
| 43 |
+
counts = {"tests": 0, "failures": 0, "errors": 0, "skipped": 0}
|
| 44 |
+
if junit_path.is_file():
|
| 45 |
+
try:
|
| 46 |
+
root = ET.parse(junit_path).getroot()
|
| 47 |
+
suites = [root] if root.tag == "testsuite" else list(root.iter("testsuite"))
|
| 48 |
+
for suite in suites:
|
| 49 |
+
for key in counts:
|
| 50 |
+
counts[key] += int(suite.attrib.get(key, 0))
|
| 51 |
+
finally:
|
| 52 |
+
junit_path.unlink(missing_ok=True)
|
| 53 |
+
passed = (
|
| 54 |
+
completed.returncode == 0
|
| 55 |
+
and counts["tests"] > 0
|
| 56 |
+
and counts["failures"] == 0
|
| 57 |
+
and counts["errors"] == 0
|
| 58 |
+
and counts["skipped"] == 0
|
| 59 |
+
)
|
| 60 |
+
return {
|
| 61 |
+
"passed": passed,
|
| 62 |
+
"returncode": completed.returncode,
|
| 63 |
+
"command": command,
|
| 64 |
+
"test_counts": counts,
|
| 65 |
+
"completed_at": datetime.now(timezone.utc).isoformat(),
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def validate(artifact: Path, stages: list[str]) -> Path:
|
| 70 |
+
report_path = artifact / "validation-report.json"
|
| 71 |
+
if report_path.exists():
|
| 72 |
+
report = json.loads(report_path.read_text(encoding="utf-8"))
|
| 73 |
+
else:
|
| 74 |
+
report = {
|
| 75 |
+
"format_version": 1,
|
| 76 |
+
"source_revision": SOURCE_REVISION,
|
| 77 |
+
"numerical_parity_certified_through_tokens": NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 78 |
+
"lengths_above_65536": "structural validation only",
|
| 79 |
+
"stages": {},
|
| 80 |
+
}
|
| 81 |
+
for stage in stages:
|
| 82 |
+
print(f"\n=== {stage} ===", flush=True)
|
| 83 |
+
report["stages"][stage] = _run_stage(stage, artifact)
|
| 84 |
+
report["upload_gate"] = {
|
| 85 |
+
"required_stages": list(STAGE_COMMANDS),
|
| 86 |
+
"passed": all(report["stages"].get(item, {}).get("passed", False) for item in STAGE_COMMANDS),
|
| 87 |
+
}
|
| 88 |
+
report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
| 89 |
+
if not report["stages"][stage]["passed"]:
|
| 90 |
+
raise SystemExit(f"validation stage failed: {stage}")
|
| 91 |
+
return report_path
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def build_parser() -> argparse.ArgumentParser:
|
| 95 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 96 |
+
parser.add_argument("--artifact", type=Path, required=True)
|
| 97 |
+
group = parser.add_mutually_exclusive_group(required=True)
|
| 98 |
+
group.add_argument("--client", action="store_true")
|
| 99 |
+
group.add_argument("--normal", action="store_true")
|
| 100 |
+
group.add_argument("--slow", action="store_true")
|
| 101 |
+
group.add_argument("--structural", action="store_true")
|
| 102 |
+
group.add_argument("--all", action="store_true")
|
| 103 |
+
return parser
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def main(argv: list[str] | None = None):
|
| 107 |
+
args = build_parser().parse_args(argv)
|
| 108 |
+
selection = {
|
| 109 |
+
"client": ["client_compatibility"],
|
| 110 |
+
"normal": ["client_compatibility", "normal_parity"],
|
| 111 |
+
"slow": ["slow_65536_parity"],
|
| 112 |
+
"structural": ["structural_262144"],
|
| 113 |
+
"all": list(STAGE_COMMANDS),
|
| 114 |
+
}
|
| 115 |
+
selected = next(key for key in selection if getattr(args, key))
|
| 116 |
+
report = validate(args.artifact.resolve(), selection[selected])
|
| 117 |
+
print(f"Validation report: {report}")
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
if __name__ == "__main__":
|
| 121 |
+
main()
|
src/openthai_systemone_onnx_tools/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Conversion, validation, and Hugging Face release tooling.
|
| 2 |
+
|
| 3 |
+
This package is intentionally separate from :mod:`openthai_systemone_onnx`,
|
| 4 |
+
which contains only the installed ONNX client runtime.
|
| 5 |
+
"""
|
| 6 |
+
|
src/openthai_systemone_onnx_tools/artifact.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Artifact metadata and checksum helpers for conversion and release tooling."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
from datetime import datetime, timezone
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Any
|
| 10 |
+
|
| 11 |
+
from .constants import (
|
| 12 |
+
MAX_POSITION_EMBEDDINGS,
|
| 13 |
+
NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 14 |
+
PUBLIC_TENSORS,
|
| 15 |
+
REQUIRED_CONTRIB_OPS,
|
| 16 |
+
REQUIRED_OPERATOR_DOMAINS,
|
| 17 |
+
REQUIRED_ORT_GENAI_VERSION,
|
| 18 |
+
REQUIRED_ORT_VERSION,
|
| 19 |
+
SOURCE_MODEL,
|
| 20 |
+
SOURCE_REVISION,
|
| 21 |
+
TARGET_REPOSITORY,
|
| 22 |
+
UPSTREAM_CLIENT_REVISION,
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def sha256_file(path: Path, chunk_size: int = 8 * 1024 * 1024) -> str:
|
| 27 |
+
digest = hashlib.sha256()
|
| 28 |
+
with path.open("rb") as handle:
|
| 29 |
+
while block := handle.read(chunk_size):
|
| 30 |
+
digest.update(block)
|
| 31 |
+
return digest.hexdigest()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def artifact_checksums(root: Path) -> dict[str, str]:
|
| 35 |
+
ignored = {"artifact-manifest.json", "validation-report.json"}
|
| 36 |
+
return {
|
| 37 |
+
path.relative_to(root).as_posix(): sha256_file(path)
|
| 38 |
+
for path in sorted(root.rglob("*"))
|
| 39 |
+
if path.is_file() and path.relative_to(root).as_posix() not in ignored
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def build_manifest(root: Path, *, extra: dict[str, Any] | None = None) -> dict[str, Any]:
|
| 44 |
+
manifest: dict[str, Any] = {
|
| 45 |
+
"format_version": 1,
|
| 46 |
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
| 47 |
+
"source": {"repo_id": SOURCE_MODEL, "revision": SOURCE_REVISION},
|
| 48 |
+
"upstream_client": {
|
| 49 |
+
"repository": "iapp-technology/openthai-systemone",
|
| 50 |
+
"revision": UPSTREAM_CLIENT_REVISION,
|
| 51 |
+
},
|
| 52 |
+
"target_repository": TARGET_REPOSITORY,
|
| 53 |
+
"graph": "onnx/model.onnx",
|
| 54 |
+
"external_data": "onnx/model.onnx.data",
|
| 55 |
+
"precision": "fp32",
|
| 56 |
+
"max_position_embeddings": MAX_POSITION_EMBEDDINGS,
|
| 57 |
+
"numerically_validated_max_tokens": NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 58 |
+
"runtime": {
|
| 59 |
+
"onnxruntime": REQUIRED_ORT_VERSION,
|
| 60 |
+
"onnxruntime_genai_builder": REQUIRED_ORT_GENAI_VERSION,
|
| 61 |
+
"portable_to_arbitrary_onnx_engines": False,
|
| 62 |
+
},
|
| 63 |
+
"operator_domains": REQUIRED_OPERATOR_DOMAINS,
|
| 64 |
+
"required_contrib_operators": sorted(REQUIRED_CONTRIB_OPS),
|
| 65 |
+
"tensor_schema": PUBLIC_TENSORS,
|
| 66 |
+
"state_contract": "zero convolution, recurrent, and KV state is initialized inside the graph per request",
|
| 67 |
+
"checksums": artifact_checksums(root),
|
| 68 |
+
}
|
| 69 |
+
if extra:
|
| 70 |
+
manifest.update(extra)
|
| 71 |
+
return manifest
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def write_manifest(root: Path, *, extra: dict[str, Any] | None = None) -> Path:
|
| 75 |
+
destination = root / "artifact-manifest.json"
|
| 76 |
+
destination.write_text(
|
| 77 |
+
json.dumps(build_manifest(root, extra=extra), indent=2, sort_keys=True) + "\n",
|
| 78 |
+
encoding="utf-8",
|
| 79 |
+
)
|
| 80 |
+
return destination
|
src/openthai_systemone_onnx_tools/constants.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pinned source, graph, validation, and release configuration."""
|
| 2 |
+
|
| 3 |
+
from openthai_systemone_onnx.constants import (
|
| 4 |
+
ABSTAIN_SLOT,
|
| 5 |
+
MAX_POSITION_EMBEDDINGS,
|
| 6 |
+
N_SLOTS,
|
| 7 |
+
REQUIRED_ORT_VERSION,
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
SOURCE_MODEL = "iapp/OpenThai-SystemOne"
|
| 11 |
+
SOURCE_REVISION = "f3709948b5e3cc9606a57e74ba62b7a639d17dd3"
|
| 12 |
+
UPSTREAM_CLIENT_REVISION = "5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf"
|
| 13 |
+
TARGET_REPOSITORY = "imtk/OpenThai-SystemOne-ONNX"
|
| 14 |
+
|
| 15 |
+
NUMERICALLY_VALIDATED_MAX_TOKENS = 65_536
|
| 16 |
+
REQUIRED_ORT_GENAI_VERSION = "0.16.0"
|
| 17 |
+
REQUIRED_OPERATOR_DOMAINS = {"": 23, "com.microsoft": 1}
|
| 18 |
+
REQUIRED_CONTRIB_OPS = {
|
| 19 |
+
"CausalConvWithState",
|
| 20 |
+
"LinearAttention",
|
| 21 |
+
"GroupQueryAttention",
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
PUBLIC_TENSORS = {
|
| 25 |
+
"inputs": {
|
| 26 |
+
"input_ids": ["batch", "sequence"],
|
| 27 |
+
"attention_mask": ["batch", "sequence"],
|
| 28 |
+
"answer_positions": ["batch", "questions"],
|
| 29 |
+
"option_counts": ["batch", "questions"],
|
| 30 |
+
"qtypes": ["batch", "questions"],
|
| 31 |
+
},
|
| 32 |
+
"outputs": {
|
| 33 |
+
"logits": ["batch", "questions", N_SLOTS],
|
| 34 |
+
"probabilities": ["batch", "questions", N_SLOTS],
|
| 35 |
+
},
|
| 36 |
+
}
|
| 37 |
+
|
src/openthai_systemone_onnx_tools/export.py
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build the dynamic FP32 OpenThai-SystemOne ONNX Runtime graph."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import shutil
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import onnx_ir as ir
|
| 11 |
+
import torch
|
| 12 |
+
from huggingface_hub import snapshot_download
|
| 13 |
+
from transformers import AutoConfig, AutoModel
|
| 14 |
+
|
| 15 |
+
from onnxruntime_genai.models.builders.qwen import Qwen35TextModel
|
| 16 |
+
|
| 17 |
+
from .artifact import write_manifest
|
| 18 |
+
from .constants import (
|
| 19 |
+
ABSTAIN_SLOT,
|
| 20 |
+
MAX_POSITION_EMBEDDINGS,
|
| 21 |
+
N_SLOTS,
|
| 22 |
+
REQUIRED_ORT_GENAI_VERSION,
|
| 23 |
+
SOURCE_MODEL,
|
| 24 |
+
SOURCE_REVISION,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class OpenThaiDynamicBuilder(Qwen35TextModel):
|
| 29 |
+
"""Qwen3.5 builder with internal state and the OpenThai decision head."""
|
| 30 |
+
|
| 31 |
+
def make_node(self, op_type, inputs, outputs, *, name, domain="", **kwargs):
|
| 32 |
+
"""Normalize ONNX integer attributes before ONNX IR serialization.
|
| 33 |
+
|
| 34 |
+
ONNX represents flags such as ``keepdims`` as INT attributes. ORT
|
| 35 |
+
GenAI 0.16 passes Python booleans for a few of them. ONNX IR 0.1.3
|
| 36 |
+
infers the correct INT attribute type but otherwise retains the bool,
|
| 37 |
+
which protobuf serialization rejects because ``bool`` is not accepted
|
| 38 |
+
for ``AttributeProto.i``.
|
| 39 |
+
"""
|
| 40 |
+
# ORT GenAI 0.16 emits an ORT-private default-domain
|
| 41 |
+
# SimplifiedLayerNormalization op. ONNX Runtime can load that op, but
|
| 42 |
+
# the ONNX checker correctly rejects it because it has no ONNX schema.
|
| 43 |
+
# ONNX opset 23 standardizes the same RMSNorm operation, so lower the
|
| 44 |
+
# standalone form to RMSNormalization. The fused skip form remains the
|
| 45 |
+
# com.microsoft contrib op.
|
| 46 |
+
if op_type == "SimplifiedLayerNormalization" and not domain:
|
| 47 |
+
op_type = "RMSNormalization"
|
| 48 |
+
self.graph.opset_imports[""] = 23
|
| 49 |
+
|
| 50 |
+
normalized = {
|
| 51 |
+
key: int(value) if isinstance(value, (bool, np.bool_)) else value
|
| 52 |
+
for key, value in kwargs.items()
|
| 53 |
+
}
|
| 54 |
+
return super().make_node(
|
| 55 |
+
op_type,
|
| 56 |
+
inputs,
|
| 57 |
+
outputs,
|
| 58 |
+
name=name,
|
| 59 |
+
domain=domain,
|
| 60 |
+
**normalized,
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
def load_weights(self, input_path):
|
| 64 |
+
return AutoModel.from_pretrained(
|
| 65 |
+
input_path,
|
| 66 |
+
trust_remote_code=True,
|
| 67 |
+
local_files_only=True,
|
| 68 |
+
dtype=torch.float32,
|
| 69 |
+
).eval()
|
| 70 |
+
|
| 71 |
+
def make_inputs_and_outputs(self):
|
| 72 |
+
self.input_shapes["position_ids"] = [3, "batch_size", "sequence_length"]
|
| 73 |
+
|
| 74 |
+
public_inputs = {
|
| 75 |
+
"input_ids": (ir.DataType.INT64, ["batch_size", "sequence_length"]),
|
| 76 |
+
"attention_mask": (ir.DataType.INT64, ["batch_size", "sequence_length"]),
|
| 77 |
+
"answer_positions": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 78 |
+
"option_counts": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 79 |
+
"qtypes": (ir.DataType.INT64, ["batch_size", "num_questions"]),
|
| 80 |
+
}
|
| 81 |
+
for name, (dtype, shape) in public_inputs.items():
|
| 82 |
+
self.model.graph.inputs.append(self.make_value(name, dtype=dtype, shape=shape))
|
| 83 |
+
|
| 84 |
+
output_shape = ["batch_size", "num_questions", N_SLOTS]
|
| 85 |
+
self.model.graph.outputs.append(self.make_value("logits", ir.DataType.FLOAT, output_shape))
|
| 86 |
+
self.model.graph.outputs.append(self.make_value("probabilities", ir.DataType.FLOAT, output_shape))
|
| 87 |
+
|
| 88 |
+
def _dynamic_batch_dimension(self) -> str:
|
| 89 |
+
shape_name = "/openthai/internal/input_shape"
|
| 90 |
+
self.make_shape(shape_name, "input_ids", shape=[2])
|
| 91 |
+
gather_name = "/openthai/internal/batch_dimension"
|
| 92 |
+
self.make_gather(
|
| 93 |
+
gather_name,
|
| 94 |
+
[f"{shape_name}/output_0", "/model/constants/INT64/0"],
|
| 95 |
+
dtype=ir.DataType.INT64,
|
| 96 |
+
shape=[],
|
| 97 |
+
axis=0,
|
| 98 |
+
)
|
| 99 |
+
unsqueeze_name = "/openthai/internal/batch_dimension_unsqueezed"
|
| 100 |
+
self.make_unsqueeze(
|
| 101 |
+
unsqueeze_name,
|
| 102 |
+
[f"{gather_name}/output_0", "/model/constants/INT64/[0]"],
|
| 103 |
+
dtype=ir.DataType.INT64,
|
| 104 |
+
shape=[1],
|
| 105 |
+
)
|
| 106 |
+
return f"{unsqueeze_name}/output_0"
|
| 107 |
+
|
| 108 |
+
def _zero_tensor(self, name: str, shape_input: str, dtype: ir.DataType, shape):
|
| 109 |
+
if dtype != ir.DataType.FLOAT:
|
| 110 |
+
raise TypeError(f"internal request state must be FP32, got {dtype}")
|
| 111 |
+
zero = ir.tensor(np.asarray([0], dtype=np.float32))
|
| 112 |
+
node_name = f"/openthai/internal/zero/{name.replace('.', '_')}"
|
| 113 |
+
self.make_node(
|
| 114 |
+
"ConstantOfShape",
|
| 115 |
+
inputs=[shape_input],
|
| 116 |
+
outputs=[name],
|
| 117 |
+
name=node_name,
|
| 118 |
+
value=zero,
|
| 119 |
+
)
|
| 120 |
+
self.make_value(name, dtype=dtype, shape=shape)
|
| 121 |
+
|
| 122 |
+
def _make_internal_request_state(self):
|
| 123 |
+
batch = self._dynamic_batch_dimension()
|
| 124 |
+
shape_specs = {
|
| 125 |
+
"kv": [self.num_kv_heads, 0, self.head_size],
|
| 126 |
+
"conv": [self.linear_conv_dim, self.linear_conv_kernel_dim - 1],
|
| 127 |
+
"recurrent": [
|
| 128 |
+
self.linear_num_value_heads,
|
| 129 |
+
self.linear_key_head_dim,
|
| 130 |
+
self.linear_value_head_dim,
|
| 131 |
+
],
|
| 132 |
+
}
|
| 133 |
+
shape_paths: dict[str, str] = {}
|
| 134 |
+
for label, tail in shape_specs.items():
|
| 135 |
+
concat_name = f"/openthai/internal/{label}_state_shape"
|
| 136 |
+
self.make_concat(
|
| 137 |
+
concat_name,
|
| 138 |
+
[batch, f"/model/constants/INT64/{tail}"],
|
| 139 |
+
dtype=ir.DataType.INT64,
|
| 140 |
+
shape=[1 + len(tail)],
|
| 141 |
+
axis=0,
|
| 142 |
+
)
|
| 143 |
+
shape_paths[label] = f"{concat_name}/output_0"
|
| 144 |
+
|
| 145 |
+
for cache_kind in ("past_key_values.key", "past_key_values.value"):
|
| 146 |
+
for cache_name in self.input_names[cache_kind].values():
|
| 147 |
+
self._zero_tensor(
|
| 148 |
+
cache_name,
|
| 149 |
+
shape_paths["kv"],
|
| 150 |
+
self.io_dtype,
|
| 151 |
+
["batch_size", self.num_kv_heads, 0, self.head_size],
|
| 152 |
+
)
|
| 153 |
+
for cache_name in self.input_names["past.conv"].values():
|
| 154 |
+
self._zero_tensor(
|
| 155 |
+
cache_name,
|
| 156 |
+
shape_paths["conv"],
|
| 157 |
+
self.io_dtype,
|
| 158 |
+
["batch_size", self.linear_conv_dim, self.linear_conv_kernel_dim - 1],
|
| 159 |
+
)
|
| 160 |
+
for cache_name in self.input_names["past.recurrent"].values():
|
| 161 |
+
self._zero_tensor(
|
| 162 |
+
cache_name,
|
| 163 |
+
shape_paths["recurrent"],
|
| 164 |
+
self.input_types["past.recurrent"],
|
| 165 |
+
[
|
| 166 |
+
"batch_size",
|
| 167 |
+
self.linear_num_value_heads,
|
| 168 |
+
self.linear_key_head_dim,
|
| 169 |
+
self.linear_value_head_dim,
|
| 170 |
+
],
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
def _make_dynamic_text_positions(self):
|
| 174 |
+
cumsum_name = "/openthai/positions/CumSum"
|
| 175 |
+
self.make_node(
|
| 176 |
+
"CumSum",
|
| 177 |
+
inputs=["attention_mask", "/model/constants/INT64/1"],
|
| 178 |
+
outputs=[f"{cumsum_name}/output_0"],
|
| 179 |
+
name=cumsum_name,
|
| 180 |
+
)
|
| 181 |
+
self.make_value(
|
| 182 |
+
f"{cumsum_name}/output_0",
|
| 183 |
+
ir.DataType.INT64,
|
| 184 |
+
["batch_size", "sequence_length"],
|
| 185 |
+
)
|
| 186 |
+
sub_name = "/openthai/positions/SubOne"
|
| 187 |
+
self.make_sub(
|
| 188 |
+
sub_name,
|
| 189 |
+
[f"{cumsum_name}/output_0", "/model/constants/INT64/1"],
|
| 190 |
+
ir.DataType.INT64,
|
| 191 |
+
["batch_size", "sequence_length"],
|
| 192 |
+
)
|
| 193 |
+
padded_name = "/openthai/positions/IsPadding"
|
| 194 |
+
self.make_equal(
|
| 195 |
+
padded_name,
|
| 196 |
+
["attention_mask", "/model/constants/INT64/0"],
|
| 197 |
+
["batch_size", "sequence_length"],
|
| 198 |
+
)
|
| 199 |
+
where_name = "/openthai/positions/ReplacePadding"
|
| 200 |
+
self.make_node(
|
| 201 |
+
"Where",
|
| 202 |
+
inputs=[
|
| 203 |
+
f"{padded_name}/output_0",
|
| 204 |
+
"/model/constants/INT64/0",
|
| 205 |
+
f"{sub_name}/output_0",
|
| 206 |
+
],
|
| 207 |
+
outputs=[f"{where_name}/output_0"],
|
| 208 |
+
name=where_name,
|
| 209 |
+
)
|
| 210 |
+
self.make_value(
|
| 211 |
+
f"{where_name}/output_0",
|
| 212 |
+
ir.DataType.INT64,
|
| 213 |
+
["batch_size", "sequence_length"],
|
| 214 |
+
)
|
| 215 |
+
unsqueeze_name = "/openthai/positions/Unsqueeze"
|
| 216 |
+
self.make_unsqueeze(
|
| 217 |
+
unsqueeze_name,
|
| 218 |
+
[f"{where_name}/output_0", "/model/constants/INT64/[0]"],
|
| 219 |
+
ir.DataType.INT64,
|
| 220 |
+
[1, "batch_size", "sequence_length"],
|
| 221 |
+
)
|
| 222 |
+
tile_name = "/openthai/positions/TileMRoPE"
|
| 223 |
+
self.make_node(
|
| 224 |
+
"Tile",
|
| 225 |
+
inputs=[f"{unsqueeze_name}/output_0", "/model/constants/INT64/[3, 1, 1]"],
|
| 226 |
+
outputs=[self.input_names["position_ids"]],
|
| 227 |
+
name=tile_name,
|
| 228 |
+
)
|
| 229 |
+
self.make_value(
|
| 230 |
+
self.input_names["position_ids"],
|
| 231 |
+
ir.DataType.INT64,
|
| 232 |
+
[3, "batch_size", "sequence_length"],
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
def make_preprocessing_nodes(self):
|
| 236 |
+
self._make_internal_request_state()
|
| 237 |
+
self._make_dynamic_text_positions()
|
| 238 |
+
super().make_preprocessing_nodes()
|
| 239 |
+
|
| 240 |
+
def make_postprocessing_nodes(self):
|
| 241 |
+
"""Gather answers, apply the calibrated head, mask slots, and softmax."""
|
| 242 |
+
shape = ["batch_size", "num_questions", N_SLOTS]
|
| 243 |
+
index_shape_name = "/openthai/head/AnswerIndexShape"
|
| 244 |
+
self.make_shape(index_shape_name, "answer_positions", shape=[2])
|
| 245 |
+
target_shape_name = "/openthai/head/ExpandedIndexShape"
|
| 246 |
+
self.make_concat(
|
| 247 |
+
target_shape_name,
|
| 248 |
+
[f"{index_shape_name}/output_0", f"/model/constants/INT64/[{self.hidden_size}]"],
|
| 249 |
+
ir.DataType.INT64,
|
| 250 |
+
[3],
|
| 251 |
+
)
|
| 252 |
+
clamped_name = "/openthai/head/ClampAnswerPositions"
|
| 253 |
+
self.make_node(
|
| 254 |
+
"Max",
|
| 255 |
+
inputs=["answer_positions", "/model/constants/INT64/0"],
|
| 256 |
+
outputs=[f"{clamped_name}/output_0"],
|
| 257 |
+
name=clamped_name,
|
| 258 |
+
)
|
| 259 |
+
self.make_value(
|
| 260 |
+
f"{clamped_name}/output_0",
|
| 261 |
+
ir.DataType.INT64,
|
| 262 |
+
["batch_size", "num_questions"],
|
| 263 |
+
)
|
| 264 |
+
unsqueeze_name = "/openthai/head/UnsqueezeAnswerPositions"
|
| 265 |
+
self.make_unsqueeze(
|
| 266 |
+
unsqueeze_name,
|
| 267 |
+
[f"{clamped_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 268 |
+
ir.DataType.INT64,
|
| 269 |
+
["batch_size", "num_questions", 1],
|
| 270 |
+
)
|
| 271 |
+
expand_name = "/openthai/head/ExpandAnswerPositions"
|
| 272 |
+
self.make_expand(
|
| 273 |
+
expand_name,
|
| 274 |
+
[f"{unsqueeze_name}/output_0", f"{target_shape_name}/output_0"],
|
| 275 |
+
ir.DataType.INT64,
|
| 276 |
+
["batch_size", "num_questions", self.hidden_size],
|
| 277 |
+
)
|
| 278 |
+
gather_name = "/openthai/head/GatherAnswerStates"
|
| 279 |
+
self.make_node(
|
| 280 |
+
"GatherElements",
|
| 281 |
+
inputs=["hidden_states", f"{expand_name}/output_0"],
|
| 282 |
+
outputs=[f"{gather_name}/output_0"],
|
| 283 |
+
name=gather_name,
|
| 284 |
+
axis=1,
|
| 285 |
+
)
|
| 286 |
+
self.make_value(
|
| 287 |
+
f"{gather_name}/output_0",
|
| 288 |
+
ir.DataType.FLOAT,
|
| 289 |
+
["batch_size", "num_questions", self.hidden_size],
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
weight_name = "openthai.slot_head.weight.transposed"
|
| 293 |
+
bias_name = "openthai.slot_head.bias"
|
| 294 |
+
temperature_name = "openthai.temperature"
|
| 295 |
+
self.make_initializer(
|
| 296 |
+
self.weights.slot_head.weight.detach().float().t().contiguous(),
|
| 297 |
+
weight_name,
|
| 298 |
+
to=ir.DataType.FLOAT,
|
| 299 |
+
)
|
| 300 |
+
self.make_initializer(
|
| 301 |
+
self.weights.slot_head.bias.detach().float(),
|
| 302 |
+
bias_name,
|
| 303 |
+
to=ir.DataType.FLOAT,
|
| 304 |
+
)
|
| 305 |
+
self.make_initializer(
|
| 306 |
+
self.weights.log_temperature.detach().float().exp(),
|
| 307 |
+
temperature_name,
|
| 308 |
+
to=ir.DataType.FLOAT,
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
matmul_name = "/openthai/head/SlotMatMul"
|
| 312 |
+
self.make_node(
|
| 313 |
+
"MatMul",
|
| 314 |
+
inputs=[f"{gather_name}/output_0", weight_name],
|
| 315 |
+
outputs=[f"{matmul_name}/output_0"],
|
| 316 |
+
name=matmul_name,
|
| 317 |
+
)
|
| 318 |
+
self.make_value(f"{matmul_name}/output_0", ir.DataType.FLOAT, shape)
|
| 319 |
+
add_name = "/openthai/head/SlotBias"
|
| 320 |
+
self.make_add(
|
| 321 |
+
add_name,
|
| 322 |
+
[f"{matmul_name}/output_0", bias_name],
|
| 323 |
+
ir.DataType.FLOAT,
|
| 324 |
+
shape,
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
qtype_name = "/openthai/head/ClampQuestionType"
|
| 328 |
+
self.make_node(
|
| 329 |
+
"Max",
|
| 330 |
+
inputs=["qtypes", "/model/constants/INT64/0"],
|
| 331 |
+
outputs=[f"{qtype_name}/output_0"],
|
| 332 |
+
name=qtype_name,
|
| 333 |
+
)
|
| 334 |
+
self.make_value(
|
| 335 |
+
f"{qtype_name}/output_0",
|
| 336 |
+
ir.DataType.INT64,
|
| 337 |
+
["batch_size", "num_questions"],
|
| 338 |
+
)
|
| 339 |
+
temp_gather_name = "/openthai/head/GatherTemperature"
|
| 340 |
+
self.make_gather(
|
| 341 |
+
temp_gather_name,
|
| 342 |
+
[temperature_name, f"{qtype_name}/output_0"],
|
| 343 |
+
ir.DataType.FLOAT,
|
| 344 |
+
["batch_size", "num_questions"],
|
| 345 |
+
axis=0,
|
| 346 |
+
)
|
| 347 |
+
temp_unsqueeze_name = "/openthai/head/UnsqueezeTemperature"
|
| 348 |
+
self.make_unsqueeze(
|
| 349 |
+
temp_unsqueeze_name,
|
| 350 |
+
[f"{temp_gather_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 351 |
+
ir.DataType.FLOAT,
|
| 352 |
+
["batch_size", "num_questions", 1],
|
| 353 |
+
)
|
| 354 |
+
scaled_name = "/openthai/head/ApplyTemperature"
|
| 355 |
+
self.make_div(
|
| 356 |
+
scaled_name,
|
| 357 |
+
[f"{add_name}/output_0", f"{temp_unsqueeze_name}/output_0"],
|
| 358 |
+
ir.DataType.FLOAT,
|
| 359 |
+
shape,
|
| 360 |
+
)
|
| 361 |
+
|
| 362 |
+
count_name = "/openthai/head/UnsqueezeOptionCounts"
|
| 363 |
+
self.make_unsqueeze(
|
| 364 |
+
count_name,
|
| 365 |
+
["option_counts", "/model/constants/INT64/[-1]"],
|
| 366 |
+
ir.DataType.INT64,
|
| 367 |
+
["batch_size", "num_questions", 1],
|
| 368 |
+
)
|
| 369 |
+
range_name = "/openthai/head/SlotRange"
|
| 370 |
+
self.make_range(
|
| 371 |
+
range_name,
|
| 372 |
+
[
|
| 373 |
+
"/model/constants/INT64/0",
|
| 374 |
+
f"/model/constants/INT64/{N_SLOTS}",
|
| 375 |
+
"/model/constants/INT64/1",
|
| 376 |
+
],
|
| 377 |
+
ir.DataType.INT64,
|
| 378 |
+
[N_SLOTS],
|
| 379 |
+
)
|
| 380 |
+
less_name = "/openthai/head/ValidOptions"
|
| 381 |
+
self.make_node(
|
| 382 |
+
"Less",
|
| 383 |
+
inputs=[f"{range_name}/output_0", f"{count_name}/output_0"],
|
| 384 |
+
outputs=[f"{less_name}/output_0"],
|
| 385 |
+
name=less_name,
|
| 386 |
+
)
|
| 387 |
+
self.make_value(f"{less_name}/output_0", ir.DataType.BOOL, shape)
|
| 388 |
+
abstain_name = "/openthai/head/IsAbstain"
|
| 389 |
+
self.make_equal(
|
| 390 |
+
abstain_name,
|
| 391 |
+
[f"{range_name}/output_0", f"/model/constants/INT64/{ABSTAIN_SLOT}"],
|
| 392 |
+
[N_SLOTS],
|
| 393 |
+
)
|
| 394 |
+
valid_name = "/openthai/head/IncludeAbstain"
|
| 395 |
+
self.make_node(
|
| 396 |
+
"Or",
|
| 397 |
+
inputs=[f"{less_name}/output_0", f"{abstain_name}/output_0"],
|
| 398 |
+
outputs=[f"{valid_name}/output_0"],
|
| 399 |
+
name=valid_name,
|
| 400 |
+
)
|
| 401 |
+
self.make_value(f"{valid_name}/output_0", ir.DataType.BOOL, shape)
|
| 402 |
+
|
| 403 |
+
empty_name = "/openthai/head/EmptyQuestion"
|
| 404 |
+
self.make_equal(
|
| 405 |
+
empty_name,
|
| 406 |
+
["option_counts", "/model/constants/INT64/0"],
|
| 407 |
+
["batch_size", "num_questions"],
|
| 408 |
+
)
|
| 409 |
+
empty_unsqueeze_name = "/openthai/head/UnsqueezeEmptyQuestion"
|
| 410 |
+
self.make_unsqueeze(
|
| 411 |
+
empty_unsqueeze_name,
|
| 412 |
+
[f"{empty_name}/output_0", "/model/constants/INT64/[-1]"],
|
| 413 |
+
ir.DataType.BOOL,
|
| 414 |
+
["batch_size", "num_questions", 1],
|
| 415 |
+
)
|
| 416 |
+
slot_zero_name = "/openthai/head/IsSlotZero"
|
| 417 |
+
self.make_equal(
|
| 418 |
+
slot_zero_name,
|
| 419 |
+
[f"{range_name}/output_0", "/model/constants/INT64/0"],
|
| 420 |
+
[N_SLOTS],
|
| 421 |
+
)
|
| 422 |
+
padding_slot_name = "/openthai/head/PaddingSlot"
|
| 423 |
+
self.make_node(
|
| 424 |
+
"And",
|
| 425 |
+
inputs=[f"{empty_unsqueeze_name}/output_0", f"{slot_zero_name}/output_0"],
|
| 426 |
+
outputs=[f"{padding_slot_name}/output_0"],
|
| 427 |
+
name=padding_slot_name,
|
| 428 |
+
)
|
| 429 |
+
self.make_value(f"{padding_slot_name}/output_0", ir.DataType.BOOL, shape)
|
| 430 |
+
final_valid_name = "/openthai/head/FinalValidMask"
|
| 431 |
+
self.make_node(
|
| 432 |
+
"Or",
|
| 433 |
+
inputs=[f"{valid_name}/output_0", f"{padding_slot_name}/output_0"],
|
| 434 |
+
outputs=[f"{final_valid_name}/output_0"],
|
| 435 |
+
name=final_valid_name,
|
| 436 |
+
)
|
| 437 |
+
self.make_value(f"{final_valid_name}/output_0", ir.DataType.BOOL, shape)
|
| 438 |
+
|
| 439 |
+
negative_infinity_name = "openthai.negative_infinity"
|
| 440 |
+
self.make_initializer(
|
| 441 |
+
np.asarray(float("-inf"), dtype=np.float32),
|
| 442 |
+
negative_infinity_name,
|
| 443 |
+
to=ir.DataType.FLOAT,
|
| 444 |
+
)
|
| 445 |
+
self.make_node(
|
| 446 |
+
"Where",
|
| 447 |
+
inputs=[
|
| 448 |
+
f"{final_valid_name}/output_0",
|
| 449 |
+
f"{scaled_name}/output_0",
|
| 450 |
+
negative_infinity_name,
|
| 451 |
+
],
|
| 452 |
+
outputs=["logits"],
|
| 453 |
+
name="/openthai/head/MaskInvalidSlots",
|
| 454 |
+
)
|
| 455 |
+
self.make_value("logits", ir.DataType.FLOAT, shape)
|
| 456 |
+
self.make_node(
|
| 457 |
+
"Softmax",
|
| 458 |
+
inputs=["logits"],
|
| 459 |
+
outputs=["probabilities"],
|
| 460 |
+
name="/openthai/head/Softmax",
|
| 461 |
+
axis=-1,
|
| 462 |
+
)
|
| 463 |
+
self.make_value("probabilities", ir.DataType.FLOAT, shape)
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def _copy_release_files(snapshot: Path, destination: Path):
|
| 467 |
+
tokenizer_names = {
|
| 468 |
+
"tokenizer.json",
|
| 469 |
+
"tokenizer_config.json",
|
| 470 |
+
"special_tokens_map.json",
|
| 471 |
+
"chat_template.jinja",
|
| 472 |
+
}
|
| 473 |
+
for name in tokenizer_names:
|
| 474 |
+
source = snapshot / name
|
| 475 |
+
if source.is_file():
|
| 476 |
+
shutil.copy2(source, destination / name)
|
| 477 |
+
|
| 478 |
+
project_root = Path(__file__).resolve().parents[2]
|
| 479 |
+
shutil.copy2(project_root / "LICENSE", destination / "LICENSE")
|
| 480 |
+
shutil.copy2(project_root / "MODEL_CARD.md", destination / "README.md")
|
| 481 |
+
shutil.copy2(project_root / "MODEL_CARD.md", destination / "MODEL_CARD.md")
|
| 482 |
+
shutil.copy2(project_root / "ATTRIBUTION.md", destination / "ATTRIBUTION.md")
|
| 483 |
+
shutil.copy2(project_root / "INSTRUCTIONS.md", destination / "INSTRUCTIONS.md")
|
| 484 |
+
shutil.copy2(project_root / "pyproject.toml", destination / "pyproject.toml")
|
| 485 |
+
shutil.copy2(project_root / "uv.lock", destination / "uv.lock")
|
| 486 |
+
shutil.copytree(
|
| 487 |
+
project_root / "src" / "openthai_systemone_onnx",
|
| 488 |
+
destination / "src" / "openthai_systemone_onnx",
|
| 489 |
+
dirs_exist_ok=True,
|
| 490 |
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
| 491 |
+
)
|
| 492 |
+
shutil.copytree(
|
| 493 |
+
project_root / "src" / "openthai_systemone_onnx_tools",
|
| 494 |
+
destination / "src" / "openthai_systemone_onnx_tools",
|
| 495 |
+
dirs_exist_ok=True,
|
| 496 |
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
| 497 |
+
)
|
| 498 |
+
shutil.copytree(
|
| 499 |
+
project_root / "examples",
|
| 500 |
+
destination / "examples",
|
| 501 |
+
dirs_exist_ok=True,
|
| 502 |
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
| 503 |
+
)
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
def export_dynamic_model(output_dir: Path, cache_dir: Path, source: str, revision: str) -> Path:
|
| 507 |
+
if revision != SOURCE_REVISION:
|
| 508 |
+
raise ValueError(
|
| 509 |
+
f"This validated recipe is pinned to source revision {SOURCE_REVISION}; got {revision}"
|
| 510 |
+
)
|
| 511 |
+
snapshot = Path(
|
| 512 |
+
snapshot_download(
|
| 513 |
+
repo_id=source,
|
| 514 |
+
revision=revision,
|
| 515 |
+
cache_dir=cache_dir,
|
| 516 |
+
allow_patterns=[
|
| 517 |
+
"*.json",
|
| 518 |
+
"*.py",
|
| 519 |
+
"*.jinja",
|
| 520 |
+
"*.safetensors",
|
| 521 |
+
"LICENSE*",
|
| 522 |
+
"README.md",
|
| 523 |
+
],
|
| 524 |
+
)
|
| 525 |
+
)
|
| 526 |
+
config = AutoConfig.from_pretrained(snapshot, trust_remote_code=True, local_files_only=True)
|
| 527 |
+
if config.text_config.max_position_embeddings != MAX_POSITION_EMBEDDINGS:
|
| 528 |
+
raise ValueError("the pinned backbone no longer reports max_position_embeddings=262144")
|
| 529 |
+
|
| 530 |
+
output_dir.mkdir(parents=True, exist_ok=True)
|
| 531 |
+
onnx_dir = output_dir / "onnx"
|
| 532 |
+
onnx_dir.mkdir(parents=True, exist_ok=True)
|
| 533 |
+
builder_cache = cache_dir / "builder"
|
| 534 |
+
builder_cache.mkdir(parents=True, exist_ok=True)
|
| 535 |
+
options = {
|
| 536 |
+
"exclude_lm_head": True,
|
| 537 |
+
"exclude_mtp": True,
|
| 538 |
+
"filename": "model.onnx",
|
| 539 |
+
"hf_remote": True,
|
| 540 |
+
"linear_attn_op": "linear_attention",
|
| 541 |
+
"state_window": 0,
|
| 542 |
+
"use_paged_attention": False,
|
| 543 |
+
}
|
| 544 |
+
builder = OpenThaiDynamicBuilder(
|
| 545 |
+
config,
|
| 546 |
+
ir.DataType.FLOAT,
|
| 547 |
+
ir.DataType.FLOAT,
|
| 548 |
+
"cpu",
|
| 549 |
+
str(builder_cache),
|
| 550 |
+
options,
|
| 551 |
+
)
|
| 552 |
+
builder.model.metadata_props.update(
|
| 553 |
+
{
|
| 554 |
+
"source_model": source,
|
| 555 |
+
"source_revision": revision,
|
| 556 |
+
"max_position_embeddings": str(MAX_POSITION_EMBEDDINGS),
|
| 557 |
+
"onnxruntime_genai_builder": REQUIRED_ORT_GENAI_VERSION,
|
| 558 |
+
"public_state": "internal-zero-state-per-request",
|
| 559 |
+
}
|
| 560 |
+
)
|
| 561 |
+
builder.make_model(str(snapshot))
|
| 562 |
+
builder.save_model(str(onnx_dir))
|
| 563 |
+
_copy_release_files(snapshot, output_dir)
|
| 564 |
+
return write_manifest(output_dir)
|
| 565 |
+
|
| 566 |
+
|
| 567 |
+
def build_parser() -> argparse.ArgumentParser:
|
| 568 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 569 |
+
parser.add_argument("--output", type=Path, default=Path("artifacts/OpenThai-SystemOne-ONNX"))
|
| 570 |
+
parser.add_argument("--cache-dir", type=Path, default=Path(".cache/huggingface"))
|
| 571 |
+
parser.add_argument("--source", default=SOURCE_MODEL)
|
| 572 |
+
parser.add_argument("--revision", default=SOURCE_REVISION)
|
| 573 |
+
return parser
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
def main(argv: list[str] | None = None):
|
| 577 |
+
args = build_parser().parse_args(argv)
|
| 578 |
+
manifest = export_dynamic_model(args.output.resolve(), args.cache_dir.resolve(), args.source, args.revision)
|
| 579 |
+
print(f"Export complete: {manifest}")
|
| 580 |
+
|
| 581 |
+
|
| 582 |
+
if __name__ == "__main__":
|
| 583 |
+
main()
|
src/openthai_systemone_onnx_tools/upload.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Upload a fully validated artifact to Hugging Face."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from huggingface_hub import HfApi
|
| 10 |
+
|
| 11 |
+
from .artifact import sha256_file
|
| 12 |
+
from .constants import TARGET_REPOSITORY
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
REQUIRED_STAGES = {
|
| 16 |
+
"client_compatibility",
|
| 17 |
+
"normal_parity",
|
| 18 |
+
"slow_65536_parity",
|
| 19 |
+
"structural_262144",
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def verify_upload_gate(artifact: Path):
|
| 24 |
+
report_path = artifact / "validation-report.json"
|
| 25 |
+
manifest_path = artifact / "artifact-manifest.json"
|
| 26 |
+
if not report_path.is_file() or not manifest_path.is_file():
|
| 27 |
+
raise RuntimeError("artifact manifest and validation report are both required")
|
| 28 |
+
report = json.loads(report_path.read_text(encoding="utf-8"))
|
| 29 |
+
stages = report.get("stages", {})
|
| 30 |
+
failed = sorted(
|
| 31 |
+
stage
|
| 32 |
+
for stage in REQUIRED_STAGES
|
| 33 |
+
if not stages.get(stage, {}).get("passed", False)
|
| 34 |
+
or stages.get(stage, {}).get("test_counts", {}).get("tests", 0) < 1
|
| 35 |
+
or stages.get(stage, {}).get("test_counts", {}).get("skipped", 1) != 0
|
| 36 |
+
)
|
| 37 |
+
if failed or not report.get("upload_gate", {}).get("passed", False):
|
| 38 |
+
raise RuntimeError(f"upload blocked; required validation stages not passed: {failed}")
|
| 39 |
+
|
| 40 |
+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
| 41 |
+
bad = []
|
| 42 |
+
for relative, expected in manifest.get("checksums", {}).items():
|
| 43 |
+
path = artifact / relative
|
| 44 |
+
if not path.is_file() or sha256_file(path) != expected:
|
| 45 |
+
bad.append(relative)
|
| 46 |
+
if bad:
|
| 47 |
+
raise RuntimeError(f"upload blocked; artifact checksum mismatch: {bad}")
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def main(argv: list[str] | None = None):
|
| 51 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 52 |
+
parser.add_argument("--artifact", type=Path, required=True)
|
| 53 |
+
parser.add_argument("--repo-id", default=TARGET_REPOSITORY)
|
| 54 |
+
parser.add_argument("--execute", action="store_true", help="perform the upload (default is a gate-only dry run)")
|
| 55 |
+
args = parser.parse_args(argv)
|
| 56 |
+
artifact = args.artifact.resolve()
|
| 57 |
+
verify_upload_gate(artifact)
|
| 58 |
+
if not args.execute:
|
| 59 |
+
print(f"Upload gate passed for {artifact}; rerun with --execute to upload to {args.repo_id}")
|
| 60 |
+
return
|
| 61 |
+
api = HfApi()
|
| 62 |
+
api.create_repo(args.repo_id, repo_type="model", exist_ok=True)
|
| 63 |
+
api.upload_folder(
|
| 64 |
+
repo_id=args.repo_id,
|
| 65 |
+
repo_type="model",
|
| 66 |
+
folder_path=artifact,
|
| 67 |
+
commit_message="Publish validated dynamic FP32 ONNX Runtime graph",
|
| 68 |
+
)
|
| 69 |
+
print(f"Uploaded {artifact} to https://huggingface.co/{args.repo_id}")
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
if __name__ == "__main__":
|
| 73 |
+
main()
|
src/openthai_systemone_onnx_tools/validation.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Run reproducible validation stages and maintain the upload gate report."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import json
|
| 7 |
+
import os
|
| 8 |
+
import subprocess
|
| 9 |
+
import sys
|
| 10 |
+
import xml.etree.ElementTree as ET
|
| 11 |
+
from datetime import datetime, timezone
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
from .constants import NUMERICALLY_VALIDATED_MAX_TOKENS, SOURCE_REVISION
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
STAGE_COMMANDS = {
|
| 18 |
+
"client_compatibility": [
|
| 19 |
+
"tests/test_client_contract.py",
|
| 20 |
+
"tests/test_export_builder.py",
|
| 21 |
+
"tests/test_validation.py",
|
| 22 |
+
],
|
| 23 |
+
"normal_parity": ["tests/test_parity.py", "-m", "parity and not slow"],
|
| 24 |
+
"slow_65536_parity": ["tests/test_parity.py", "-m", "slow"],
|
| 25 |
+
"structural_262144": ["tests/test_structure.py"],
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _accelerator_preflight(name: str) -> None:
|
| 30 |
+
"""Fail early with an actionable message for unavailable requested devices."""
|
| 31 |
+
if name not in {"normal_parity", "slow_65536_parity"}:
|
| 32 |
+
return
|
| 33 |
+
|
| 34 |
+
import onnxruntime as ort
|
| 35 |
+
import torch
|
| 36 |
+
|
| 37 |
+
requested_ort = os.environ.get("ORT_PARITY_DEVICE")
|
| 38 |
+
if requested_ort == "cuda" and "CUDAExecutionProvider" not in ort.get_available_providers():
|
| 39 |
+
raise SystemExit(
|
| 40 |
+
"ORT_PARITY_DEVICE=cuda was requested, but CUDAExecutionProvider is unavailable. "
|
| 41 |
+
"CUDA cannot run on macOS. On an NVIDIA Linux/Windows host, replace onnxruntime "
|
| 42 |
+
"with onnxruntime-gpu==1.30.0 and invoke the validator with `uv run --no-sync` "
|
| 43 |
+
"so uv does not restore the CPU wheel."
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
requested_torch = os.environ.get("PYTORCH_PARITY_DEVICE", requested_ort)
|
| 47 |
+
if requested_torch == "cuda" and not torch.cuda.is_available():
|
| 48 |
+
raise SystemExit(
|
| 49 |
+
"PYTORCH_PARITY_DEVICE=cuda was requested (or inherited from ORT_PARITY_DEVICE), "
|
| 50 |
+
"but PyTorch CUDA is unavailable. Run this certification on an NVIDIA CUDA host."
|
| 51 |
+
)
|
| 52 |
+
if requested_torch == "mps" and not torch.backends.mps.is_available():
|
| 53 |
+
raise SystemExit(
|
| 54 |
+
"PYTORCH_PARITY_DEVICE=mps was requested, but PyTorch reports MPS unavailable."
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def _run_stage(name: str, artifact: Path) -> dict:
|
| 59 |
+
_accelerator_preflight(name)
|
| 60 |
+
environment = os.environ.copy()
|
| 61 |
+
environment["OPENTHAI_ONNX_ARTIFACT"] = str(artifact)
|
| 62 |
+
if name == "normal_parity":
|
| 63 |
+
environment["RUN_PARITY"] = "1"
|
| 64 |
+
if name == "slow_65536_parity":
|
| 65 |
+
environment["RUN_PARITY"] = "1"
|
| 66 |
+
environment["RUN_SLOW_65536"] = "1"
|
| 67 |
+
junit_path = artifact / f".{name}.junit.xml"
|
| 68 |
+
command = [
|
| 69 |
+
sys.executable,
|
| 70 |
+
"-m",
|
| 71 |
+
"pytest",
|
| 72 |
+
"-q",
|
| 73 |
+
*STAGE_COMMANDS[name],
|
| 74 |
+
f"--junitxml={junit_path}",
|
| 75 |
+
]
|
| 76 |
+
completed = subprocess.run(command, env=environment, text=True)
|
| 77 |
+
counts = {"tests": 0, "failures": 0, "errors": 0, "skipped": 0}
|
| 78 |
+
if junit_path.is_file():
|
| 79 |
+
try:
|
| 80 |
+
root = ET.parse(junit_path).getroot()
|
| 81 |
+
suites = [root] if root.tag == "testsuite" else list(root.iter("testsuite"))
|
| 82 |
+
for suite in suites:
|
| 83 |
+
for key in counts:
|
| 84 |
+
counts[key] += int(suite.attrib.get(key, 0))
|
| 85 |
+
finally:
|
| 86 |
+
junit_path.unlink(missing_ok=True)
|
| 87 |
+
passed = (
|
| 88 |
+
completed.returncode == 0
|
| 89 |
+
and counts["tests"] > 0
|
| 90 |
+
and counts["failures"] == 0
|
| 91 |
+
and counts["errors"] == 0
|
| 92 |
+
and counts["skipped"] == 0
|
| 93 |
+
)
|
| 94 |
+
return {
|
| 95 |
+
"passed": passed,
|
| 96 |
+
"returncode": completed.returncode,
|
| 97 |
+
"command": command,
|
| 98 |
+
"test_counts": counts,
|
| 99 |
+
"completed_at": datetime.now(timezone.utc).isoformat(),
|
| 100 |
+
"failure_hint": (
|
| 101 |
+
"validation process was killed (signal 9), usually because host or GPU memory was exhausted"
|
| 102 |
+
if completed.returncode == -9
|
| 103 |
+
else None
|
| 104 |
+
),
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def validate(artifact: Path, stages: list[str]) -> Path:
|
| 109 |
+
report_path = artifact / "validation-report.json"
|
| 110 |
+
if report_path.exists():
|
| 111 |
+
report = json.loads(report_path.read_text(encoding="utf-8"))
|
| 112 |
+
else:
|
| 113 |
+
report = {
|
| 114 |
+
"format_version": 1,
|
| 115 |
+
"source_revision": SOURCE_REVISION,
|
| 116 |
+
"numerical_parity_certified_through_tokens": NUMERICALLY_VALIDATED_MAX_TOKENS,
|
| 117 |
+
"lengths_above_65536": "structural validation only",
|
| 118 |
+
"stages": {},
|
| 119 |
+
}
|
| 120 |
+
for stage in stages:
|
| 121 |
+
print(f"\n=== {stage} ===", flush=True)
|
| 122 |
+
report["stages"][stage] = _run_stage(stage, artifact)
|
| 123 |
+
report["upload_gate"] = {
|
| 124 |
+
"required_stages": list(STAGE_COMMANDS),
|
| 125 |
+
"passed": all(report["stages"].get(item, {}).get("passed", False) for item in STAGE_COMMANDS),
|
| 126 |
+
}
|
| 127 |
+
report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
| 128 |
+
if not report["stages"][stage]["passed"]:
|
| 129 |
+
hint = report["stages"][stage].get("failure_hint")
|
| 130 |
+
suffix = f" ({hint})" if hint else ""
|
| 131 |
+
raise SystemExit(f"validation stage failed: {stage}{suffix}")
|
| 132 |
+
return report_path
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def build_parser() -> argparse.ArgumentParser:
|
| 136 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 137 |
+
parser.add_argument("--artifact", type=Path, required=True)
|
| 138 |
+
group = parser.add_mutually_exclusive_group(required=True)
|
| 139 |
+
group.add_argument("--client", action="store_true")
|
| 140 |
+
group.add_argument("--normal", action="store_true")
|
| 141 |
+
group.add_argument("--slow", action="store_true")
|
| 142 |
+
group.add_argument("--structural", action="store_true")
|
| 143 |
+
group.add_argument("--all", action="store_true")
|
| 144 |
+
return parser
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def main(argv: list[str] | None = None):
|
| 148 |
+
args = build_parser().parse_args(argv)
|
| 149 |
+
selection = {
|
| 150 |
+
"client": ["client_compatibility"],
|
| 151 |
+
"normal": ["client_compatibility", "normal_parity"],
|
| 152 |
+
"slow": ["slow_65536_parity"],
|
| 153 |
+
"structural": ["structural_262144"],
|
| 154 |
+
"all": list(STAGE_COMMANDS),
|
| 155 |
+
}
|
| 156 |
+
selected = next(key for key in selection if getattr(args, key))
|
| 157 |
+
report = validate(args.artifact.resolve(), selection[selected])
|
| 158 |
+
print(f"Validation report: {report}")
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
if __name__ == "__main__":
|
| 162 |
+
main()
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d3400f1532d54f98d82b24c503e61908aa66f84e22e566e59fc80494add3a5c3
|
| 3 |
+
size 20039242
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"audio_bos_token": "<|audio_start|>",
|
| 4 |
+
"audio_eos_token": "<|audio_end|>",
|
| 5 |
+
"audio_token": "<|audio_pad|>",
|
| 6 |
+
"backend": "tokenizers",
|
| 7 |
+
"bos_token": null,
|
| 8 |
+
"clean_up_tokenization_spaces": false,
|
| 9 |
+
"eos_token": "<|endoftext|>",
|
| 10 |
+
"errors": "replace",
|
| 11 |
+
"image_token": "<|image_pad|>",
|
| 12 |
+
"is_local": true,
|
| 13 |
+
"local_files_only": false,
|
| 14 |
+
"model_max_length": 262144,
|
| 15 |
+
"model_specific_special_tokens": {
|
| 16 |
+
"audio_bos_token": "<|audio_start|>",
|
| 17 |
+
"audio_eos_token": "<|audio_end|>",
|
| 18 |
+
"audio_token": "<|audio_pad|>",
|
| 19 |
+
"image_token": "<|image_pad|>",
|
| 20 |
+
"video_token": "<|video_pad|>",
|
| 21 |
+
"vision_bos_token": "<|vision_start|>",
|
| 22 |
+
"vision_eos_token": "<|vision_end|>"
|
| 23 |
+
},
|
| 24 |
+
"pad_token": "<|endoftext|>",
|
| 25 |
+
"pretokenize_regex": "(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?[\\p{L}\\p{M}]+|\\p{N}| ?[^\\s\\p{L}\\p{M}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+",
|
| 26 |
+
"split_special_tokens": false,
|
| 27 |
+
"tokenizer_class": "Qwen2Tokenizer",
|
| 28 |
+
"unk_token": null,
|
| 29 |
+
"video_token": "<|video_pad|>",
|
| 30 |
+
"vision_bos_token": "<|vision_start|>",
|
| 31 |
+
"vision_eos_token": "<|vision_end|>"
|
| 32 |
+
}
|
uv.lock
ADDED
|
@@ -0,0 +1,909 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
revision = 3
|
| 3 |
+
requires-python = "==3.12.*"
|
| 4 |
+
|
| 5 |
+
[[package]]
|
| 6 |
+
name = "annotated-doc"
|
| 7 |
+
version = "0.0.5"
|
| 8 |
+
source = { registry = "https://pypi.org/simple" }
|
| 9 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" }
|
| 10 |
+
wheels = [
|
| 11 |
+
{ url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[[package]]
|
| 15 |
+
name = "annotated-types"
|
| 16 |
+
version = "0.8.0"
|
| 17 |
+
source = { registry = "https://pypi.org/simple" }
|
| 18 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" }
|
| 19 |
+
wheels = [
|
| 20 |
+
{ url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" },
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
[[package]]
|
| 24 |
+
name = "anyio"
|
| 25 |
+
version = "4.15.1"
|
| 26 |
+
source = { registry = "https://pypi.org/simple" }
|
| 27 |
+
dependencies = [
|
| 28 |
+
{ name = "idna" },
|
| 29 |
+
{ name = "typing-extensions" },
|
| 30 |
+
]
|
| 31 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a9/d2/f4d173e22df740bc37b1db102b386ba719b66e95b0f0d751f556b387e6d2/anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94", size = 276966, upload-time = "2026-09-05T10:42:39.44Z" }
|
| 32 |
+
wheels = [
|
| 33 |
+
{ url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" },
|
| 34 |
+
]
|
| 35 |
+
|
| 36 |
+
[[package]]
|
| 37 |
+
name = "certifi"
|
| 38 |
+
version = "2026.7.22"
|
| 39 |
+
source = { registry = "https://pypi.org/simple" }
|
| 40 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" }
|
| 41 |
+
wheels = [
|
| 42 |
+
{ url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" },
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
[[package]]
|
| 46 |
+
name = "colorama"
|
| 47 |
+
version = "0.4.6"
|
| 48 |
+
source = { registry = "https://pypi.org/simple" }
|
| 49 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
| 50 |
+
wheels = [
|
| 51 |
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
| 52 |
+
]
|
| 53 |
+
|
| 54 |
+
[[package]]
|
| 55 |
+
name = "coverage"
|
| 56 |
+
version = "7.16.1"
|
| 57 |
+
source = { registry = "https://pypi.org/simple" }
|
| 58 |
+
sdist = { url = "https://files.pythonhosted.org/packages/65/2d/c738872f477f5687152acae68635790387425d407ae37dd3d3a8a6692307/coverage-7.16.1.tar.gz", hash = "sha256:f83981779bcf9dfa06fa0a8d4cb43e0faec1706328ce07aa3e7b665b4ac0f210", size = 969651, upload-time = "2026-09-13T19:12:21.422Z" }
|
| 59 |
+
wheels = [
|
| 60 |
+
{ url = "https://files.pythonhosted.org/packages/1a/f7/7cd4c9f2a3b7574414222ec425d5eee21cc690d867a013315e3be8ba185c/coverage-7.16.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b7f2c26ce6ce0b1e0ca0d5fae96ea510e3a2e78b7207f06e76b7f2c87fa3d0af", size = 223475, upload-time = "2026-09-13T19:09:10.145Z" },
|
| 61 |
+
{ url = "https://files.pythonhosted.org/packages/3e/f2/9ac65f9cedd43f91e2d3657c11f13aef82aebae89b2243dc9e44fe58a740/coverage-7.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070acb9da788dff743a4d36fc015feee12d68f0349959017542017c79f59c21c", size = 223845, upload-time = "2026-09-13T19:09:11.988Z" },
|
| 62 |
+
{ url = "https://files.pythonhosted.org/packages/62/4d/f13db452d4367fe1122abfd98ae330596f65a3b40498f8e1a5811f68f123/coverage-7.16.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e366587b370bc9b8b51b7b7272c610c56db5d5b4795b9e4a29d28ff2f440f809", size = 255341, upload-time = "2026-09-13T19:09:13.708Z" },
|
| 63 |
+
{ url = "https://files.pythonhosted.org/packages/5d/6b/85ed86e82835a96ddfbe7705c387c28ce1cbbecd1b6d606f5ddfeeb712df/coverage-7.16.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e82e10b9d290f60b63459cfb245a841aec347603997206296b93881463a93dcf", size = 258078, upload-time = "2026-09-13T19:09:15.368Z" },
|
| 64 |
+
{ url = "https://files.pythonhosted.org/packages/cd/d2/f66945853d850b9c05f4e012e37396f1f31d0cd40d062394b229c22e7b56/coverage-7.16.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d73bb1f85c4150ac208fb0755beb04b2e44897bad81414de9380f98dd74729f", size = 259191, upload-time = "2026-09-13T19:09:17.046Z" },
|
| 65 |
+
{ url = "https://files.pythonhosted.org/packages/77/a1/7b907abe62461f289035c7ac60ab3e6334efb8c425151aac4abfa0c97820/coverage-7.16.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3397b9032553d281ad6a9253b12675b65e0cc8cd7a3b0633cf48872c9eb13360", size = 261452, upload-time = "2026-09-13T19:09:18.756Z" },
|
| 66 |
+
{ url = "https://files.pythonhosted.org/packages/51/e6/e26f4d6b1069a2a2fee3238a132f85c5b4c1dc25aebd88e015451ff0bd68/coverage-7.16.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:77890395cf37026a5907d3ad32376aa51f41c0f163b7477fdbd4f94966cc1d08", size = 255698, upload-time = "2026-09-13T19:09:20.786Z" },
|
| 67 |
+
{ url = "https://files.pythonhosted.org/packages/7f/ec/99db7450e813050ebce300e31bbd4f997c76a8c6e3a6d168c5dffc104109/coverage-7.16.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b0944dc3bee3091039bf970d73caaf930c906013128a421bdc132e797494d941", size = 257111, upload-time = "2026-09-13T19:09:22.693Z" },
|
| 68 |
+
{ url = "https://files.pythonhosted.org/packages/2e/9d/500df9d3cd8c541ac84b5e0bcab00646be75654e05aa34e8410ec851282d/coverage-7.16.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b89d22a89d5bc05dd95b64e08295b8394aa96dc88e08f8ba210c9ebfebbe0489", size = 255258, upload-time = "2026-09-13T19:09:24.429Z" },
|
| 69 |
+
{ url = "https://files.pythonhosted.org/packages/c0/24/53318d96da332bb4946f8ac646fa19fd37fecbd0c49144735c716ac69bf0/coverage-7.16.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:550a2a1faf7559f13d5344f12d1eb886ad87955155d7dfab2a3fe5c8ec8fe776", size = 259326, upload-time = "2026-09-13T19:09:26.32Z" },
|
| 70 |
+
{ url = "https://files.pythonhosted.org/packages/c5/ce/abc0462b2e6ae96ae22197d2bc30fe33b6b4e52937e782745436ceb2a761/coverage-7.16.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:55eb268e5b81aefac759766c9162625b06c1bedb7b77d936225bafc4f038a6f6", size = 254827, upload-time = "2026-09-13T19:09:28.191Z" },
|
| 71 |
+
{ url = "https://files.pythonhosted.org/packages/8b/e1/0a04eedaaf19196b51f0180968134228c7646e469ed29914e48690a7cf3e/coverage-7.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65a8fc80898c9ce59f04349fe8b4849b1f9787f14e52ead990e5f849ff4727a0", size = 256698, upload-time = "2026-09-13T19:09:29.922Z" },
|
| 72 |
+
{ url = "https://files.pythonhosted.org/packages/de/1d/d441a55cf22ce9d8e9e34814806c47441ab844bd534e0f4b64e1c6ae8bd1/coverage-7.16.1-cp312-cp312-win32.whl", hash = "sha256:528a61be40977c340cf201d23b69bd6a6bab507da60e9dbda85f8b30e935d70d", size = 225541, upload-time = "2026-09-13T19:09:31.752Z" },
|
| 73 |
+
{ url = "https://files.pythonhosted.org/packages/73/27/ec3d032375735dd331477caa051419678079ff90fcb53d0284a6c2bfb757/coverage-7.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:d0f02c633630e2b74522108ee95a84ad6e1204a8016a6cca5297f335ea27147e", size = 226075, upload-time = "2026-09-13T19:09:33.556Z" },
|
| 74 |
+
{ url = "https://files.pythonhosted.org/packages/94/00/90e9f5c4434878494306b9c0ee8068ebbd829483737d8cefccc58884d728/coverage-7.16.1-cp312-cp312-win_arm64.whl", hash = "sha256:2959978f9d1d20a2c0c15d0a68baaeccf615ac1aa214cf4a05a10d6f568926c8", size = 225461, upload-time = "2026-09-13T19:09:35.48Z" },
|
| 75 |
+
{ url = "https://files.pythonhosted.org/packages/96/1a/d6d16babd0a5fe4c3fae40702158c570351694e74516d8d81b86c5637448/coverage-7.16.1-py3-none-any.whl", hash = "sha256:3d8bd4e58b6a5c2018d808f297905393c6c61da466a48c3f0596a76a4900ebe4", size = 215264, upload-time = "2026-09-13T19:12:18.895Z" },
|
| 76 |
+
]
|
| 77 |
+
|
| 78 |
+
[[package]]
|
| 79 |
+
name = "filelock"
|
| 80 |
+
version = "4.0.3"
|
| 81 |
+
source = { registry = "https://pypi.org/simple" }
|
| 82 |
+
sdist = { url = "https://files.pythonhosted.org/packages/4f/b8/9ba8f569df649beb7058db5eb392a5f779bdbc3b82cf3942f0be439fb99e/filelock-4.0.3.tar.gz", hash = "sha256:87296d60478e14204fd9406e79831400fef76693bae2895deec236c98e87a8aa", size = 244309, upload-time = "2026-09-23T23:40:22.569Z" }
|
| 83 |
+
wheels = [
|
| 84 |
+
{ url = "https://files.pythonhosted.org/packages/7a/6d/db8b86e168fef0cf904737e275bccb683558088ef971e92d3b41ce980699/filelock-4.0.3-py3-none-any.whl", hash = "sha256:30cd166e2aee2c7534ce2c33c6367c4cd051b8368e20e2c4eb0c34f699bacfab", size = 108444, upload-time = "2026-09-23T23:40:20.819Z" },
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
[[package]]
|
| 88 |
+
name = "flatbuffers"
|
| 89 |
+
version = "25.12.19"
|
| 90 |
+
source = { registry = "https://pypi.org/simple" }
|
| 91 |
+
wheels = [
|
| 92 |
+
{ url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" },
|
| 93 |
+
]
|
| 94 |
+
|
| 95 |
+
[[package]]
|
| 96 |
+
name = "fsspec"
|
| 97 |
+
version = "2026.9.0"
|
| 98 |
+
source = { registry = "https://pypi.org/simple" }
|
| 99 |
+
sdist = { url = "https://files.pythonhosted.org/packages/77/cd/9be253869fc42e764de7f3dedd6969af7d44ff9c3375214a3442a6f3fc08/fsspec-2026.9.0.tar.gz", hash = "sha256:0f08147951c8cb31d844c3547d631053b127863b60be04cf06e121333ee0e2fe", size = 333545, upload-time = "2026-09-18T17:50:42.825Z" }
|
| 100 |
+
wheels = [
|
| 101 |
+
{ url = "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl", hash = "sha256:8dd6e646e99ea382bd85f97a45e6b526a442d79423a7dc673f1e2756d05fcb5f", size = 221738, upload-time = "2026-09-18T17:50:41.341Z" },
|
| 102 |
+
]
|
| 103 |
+
|
| 104 |
+
[[package]]
|
| 105 |
+
name = "h11"
|
| 106 |
+
version = "0.16.0"
|
| 107 |
+
source = { registry = "https://pypi.org/simple" }
|
| 108 |
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
| 109 |
+
wheels = [
|
| 110 |
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
| 111 |
+
]
|
| 112 |
+
|
| 113 |
+
[[package]]
|
| 114 |
+
name = "hf-xet"
|
| 115 |
+
version = "1.6.0"
|
| 116 |
+
source = { registry = "https://pypi.org/simple" }
|
| 117 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" }
|
| 118 |
+
wheels = [
|
| 119 |
+
{ url = "https://files.pythonhosted.org/packages/a2/50/7afa2c9c787405864fc47a0d1bbc02c62e9101947ed43c1f43899fc7d91d/hf_xet-1.6.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d", size = 4071729, upload-time = "2026-08-03T22:33:00.721Z" },
|
| 120 |
+
{ url = "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a", size = 3876287, upload-time = "2026-08-03T22:33:02.251Z" },
|
| 121 |
+
{ url = "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f", size = 4464663, upload-time = "2026-08-03T22:33:03.802Z" },
|
| 122 |
+
{ url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" },
|
| 123 |
+
{ url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" },
|
| 124 |
+
{ url = "https://files.pythonhosted.org/packages/ab/5f/311725e2a905534dfee2dcb5b08414f249147f1f12252bfc2bd24caa075c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c", size = 4675937, upload-time = "2026-08-03T22:33:08.616Z" },
|
| 125 |
+
{ url = "https://files.pythonhosted.org/packages/98/b7/8c59a66d15205024662f1d66968136f13893f96df1ddc5087e2e281fc95f/hf_xet-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b", size = 4033128, upload-time = "2026-08-03T22:33:10.171Z" },
|
| 126 |
+
{ url = "https://files.pythonhosted.org/packages/73/63/ca511b6f802f28cf3489b280fe77475bcca8de85e81a6299d7916b5b5555/hf_xet-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3", size = 3859359, upload-time = "2026-08-03T22:33:11.725Z" },
|
| 127 |
+
]
|
| 128 |
+
|
| 129 |
+
[[package]]
|
| 130 |
+
name = "httpcore"
|
| 131 |
+
version = "1.0.9"
|
| 132 |
+
source = { registry = "https://pypi.org/simple" }
|
| 133 |
+
dependencies = [
|
| 134 |
+
{ name = "certifi" },
|
| 135 |
+
{ name = "h11" },
|
| 136 |
+
]
|
| 137 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
| 138 |
+
wheels = [
|
| 139 |
+
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
| 140 |
+
]
|
| 141 |
+
|
| 142 |
+
[[package]]
|
| 143 |
+
name = "httpx"
|
| 144 |
+
version = "0.28.1"
|
| 145 |
+
source = { registry = "https://pypi.org/simple" }
|
| 146 |
+
dependencies = [
|
| 147 |
+
{ name = "anyio" },
|
| 148 |
+
{ name = "certifi" },
|
| 149 |
+
{ name = "httpcore" },
|
| 150 |
+
{ name = "idna" },
|
| 151 |
+
]
|
| 152 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
| 153 |
+
wheels = [
|
| 154 |
+
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
| 155 |
+
]
|
| 156 |
+
|
| 157 |
+
[[package]]
|
| 158 |
+
name = "huggingface-hub"
|
| 159 |
+
version = "1.5.0"
|
| 160 |
+
source = { registry = "https://pypi.org/simple" }
|
| 161 |
+
dependencies = [
|
| 162 |
+
{ name = "filelock" },
|
| 163 |
+
{ name = "fsspec" },
|
| 164 |
+
{ name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
|
| 165 |
+
{ name = "httpx" },
|
| 166 |
+
{ name = "packaging" },
|
| 167 |
+
{ name = "pyyaml" },
|
| 168 |
+
{ name = "tqdm" },
|
| 169 |
+
{ name = "typer" },
|
| 170 |
+
{ name = "typing-extensions" },
|
| 171 |
+
]
|
| 172 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ae/76/b5efb3033d8499b17f9386beaf60f64c461798e1ee16d10bc9c0077beba5/huggingface_hub-1.5.0.tar.gz", hash = "sha256:f281838db29265880fb543de7a23b0f81d3504675de82044307ea3c6c62f799d", size = 695872, upload-time = "2026-02-26T15:35:32.745Z" }
|
| 173 |
+
wheels = [
|
| 174 |
+
{ url = "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl", hash = "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", size = 596261, upload-time = "2026-02-26T15:35:31.1Z" },
|
| 175 |
+
]
|
| 176 |
+
|
| 177 |
+
[[package]]
|
| 178 |
+
name = "idna"
|
| 179 |
+
version = "3.20"
|
| 180 |
+
source = { registry = "https://pypi.org/simple" }
|
| 181 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44", size = 216463, upload-time = "2026-09-17T14:11:04.752Z" }
|
| 182 |
+
wheels = [
|
| 183 |
+
{ url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" },
|
| 184 |
+
]
|
| 185 |
+
|
| 186 |
+
[[package]]
|
| 187 |
+
name = "iniconfig"
|
| 188 |
+
version = "2.3.0"
|
| 189 |
+
source = { registry = "https://pypi.org/simple" }
|
| 190 |
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
| 191 |
+
wheels = [
|
| 192 |
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
| 193 |
+
]
|
| 194 |
+
|
| 195 |
+
[[package]]
|
| 196 |
+
name = "jinja2"
|
| 197 |
+
version = "3.1.6"
|
| 198 |
+
source = { registry = "https://pypi.org/simple" }
|
| 199 |
+
dependencies = [
|
| 200 |
+
{ name = "markupsafe" },
|
| 201 |
+
]
|
| 202 |
+
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
|
| 203 |
+
wheels = [
|
| 204 |
+
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
| 205 |
+
]
|
| 206 |
+
|
| 207 |
+
[[package]]
|
| 208 |
+
name = "markdown-it-py"
|
| 209 |
+
version = "4.2.0"
|
| 210 |
+
source = { registry = "https://pypi.org/simple" }
|
| 211 |
+
dependencies = [
|
| 212 |
+
{ name = "mdurl" },
|
| 213 |
+
]
|
| 214 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
| 215 |
+
wheels = [
|
| 216 |
+
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
|
| 217 |
+
]
|
| 218 |
+
|
| 219 |
+
[[package]]
|
| 220 |
+
name = "markupsafe"
|
| 221 |
+
version = "3.0.3"
|
| 222 |
+
source = { registry = "https://pypi.org/simple" }
|
| 223 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
|
| 224 |
+
wheels = [
|
| 225 |
+
{ url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
|
| 226 |
+
{ url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
|
| 227 |
+
{ url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
|
| 228 |
+
{ url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
|
| 229 |
+
{ url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
|
| 230 |
+
{ url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
|
| 231 |
+
{ url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
|
| 232 |
+
{ url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
|
| 233 |
+
{ url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
|
| 234 |
+
{ url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
|
| 235 |
+
{ url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
|
| 236 |
+
]
|
| 237 |
+
|
| 238 |
+
[[package]]
|
| 239 |
+
name = "mdurl"
|
| 240 |
+
version = "0.1.2"
|
| 241 |
+
source = { registry = "https://pypi.org/simple" }
|
| 242 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
| 243 |
+
wheels = [
|
| 244 |
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
| 245 |
+
]
|
| 246 |
+
|
| 247 |
+
[[package]]
|
| 248 |
+
name = "ml-dtypes"
|
| 249 |
+
version = "0.6.0"
|
| 250 |
+
source = { registry = "https://pypi.org/simple" }
|
| 251 |
+
dependencies = [
|
| 252 |
+
{ name = "numpy" },
|
| 253 |
+
]
|
| 254 |
+
sdist = { url = "https://files.pythonhosted.org/packages/12/72/307d7c4bd0600601c7133fba5cb78af7db968152951c1cd473abb1cda782/ml_dtypes-0.6.0.tar.gz", hash = "sha256:5e60251d32ced5598972e4d5e06a2f044341f9291402551a3f6f0ec44f9299b0", size = 3032327, upload-time = "2026-08-13T14:14:40.215Z" }
|
| 255 |
+
wheels = [
|
| 256 |
+
{ url = "https://files.pythonhosted.org/packages/84/6a/441eb053b078954f7fea284dfb288701884d0a1404d39babb858e1649023/ml_dtypes-0.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:5359c588cc62de6f78d7430f06b65853d884955494d86d6ad90b6dd64a3f3a08", size = 565447, upload-time = "2026-08-13T14:14:01.737Z" },
|
| 257 |
+
{ url = "https://files.pythonhosted.org/packages/ed/cf/87e8a6c57eed63a91782a0d229856ddf73e138ce004dd71e2799a9dcdb33/ml_dtypes-0.6.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37da32aa97749251025666d62372775019594577b9c9e9cfda83bed48d778fdb", size = 360227, upload-time = "2026-08-13T14:14:02.938Z" },
|
| 258 |
+
{ url = "https://files.pythonhosted.org/packages/c7/f9/7d76c1eae866f5d4636401b31b6d6dd90e4b4ced1fa7cfdfcca9c60e4bd3/ml_dtypes-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b4a480aa8fd54a1805b8ac10f3f91763926a74f73c0c364c10f9231854f4170", size = 409890, upload-time = "2026-08-13T14:14:04.248Z" },
|
| 259 |
+
{ url = "https://files.pythonhosted.org/packages/ba/db/9c61ec2760b5cbfb1c6558d5c991a6d8fd3271053c32db20506a9a90272b/ml_dtypes-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a3e9d53925597fbffafd2a37048dadeddd0bdaba58058f6ae0869ed709a184d", size = 439333, upload-time = "2026-08-13T14:14:05.501Z" },
|
| 260 |
+
{ url = "https://files.pythonhosted.org/packages/6a/57/780ca3e5ab135b9fbdd8e5441abf5f801b30398371b691291e05ab9834c0/ml_dtypes-0.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:6eaed129a4afe90694b8685e2f9b6294849f5eda4af9a15be83a4326eeebd775", size = 552268, upload-time = "2026-08-13T14:14:06.866Z" },
|
| 261 |
+
]
|
| 262 |
+
|
| 263 |
+
[[package]]
|
| 264 |
+
name = "mpmath"
|
| 265 |
+
version = "1.3.0"
|
| 266 |
+
source = { registry = "https://pypi.org/simple" }
|
| 267 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
|
| 268 |
+
wheels = [
|
| 269 |
+
{ url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
|
| 270 |
+
]
|
| 271 |
+
|
| 272 |
+
[[package]]
|
| 273 |
+
name = "networkx"
|
| 274 |
+
version = "3.7"
|
| 275 |
+
source = { registry = "https://pypi.org/simple" }
|
| 276 |
+
sdist = { url = "https://files.pythonhosted.org/packages/dc/76/3af777226b63a5e64a6b36b1ec5855c14e2b94a37096d4760e595fc43511/networkx-3.7.tar.gz", hash = "sha256:fd77a511bd90f39f3d016351345b52cf5319b813bdca01de3f755d3cca62e96a", size = 1866482, upload-time = "2026-09-21T16:45:16.974Z" }
|
| 277 |
+
wheels = [
|
| 278 |
+
{ url = "https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl", hash = "sha256:e3fd2c13a7814cee3746340d8d7f8598a67f16a58bf47fb7f8793fab6efca1b0", size = 2142205, upload-time = "2026-09-21T16:45:14.609Z" },
|
| 279 |
+
]
|
| 280 |
+
|
| 281 |
+
[[package]]
|
| 282 |
+
name = "numpy"
|
| 283 |
+
version = "2.3.3"
|
| 284 |
+
source = { registry = "https://pypi.org/simple" }
|
| 285 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" }
|
| 286 |
+
wheels = [
|
| 287 |
+
{ url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" },
|
| 288 |
+
{ url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" },
|
| 289 |
+
{ url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" },
|
| 290 |
+
{ url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" },
|
| 291 |
+
{ url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" },
|
| 292 |
+
{ url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" },
|
| 293 |
+
{ url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" },
|
| 294 |
+
{ url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" },
|
| 295 |
+
{ url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" },
|
| 296 |
+
{ url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" },
|
| 297 |
+
{ url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" },
|
| 298 |
+
]
|
| 299 |
+
|
| 300 |
+
[[package]]
|
| 301 |
+
name = "nvidia-cublas-cu12"
|
| 302 |
+
version = "12.8.4.1"
|
| 303 |
+
source = { registry = "https://pypi.org/simple" }
|
| 304 |
+
wheels = [
|
| 305 |
+
{ url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" },
|
| 306 |
+
]
|
| 307 |
+
|
| 308 |
+
[[package]]
|
| 309 |
+
name = "nvidia-cuda-cupti-cu12"
|
| 310 |
+
version = "12.8.90"
|
| 311 |
+
source = { registry = "https://pypi.org/simple" }
|
| 312 |
+
wheels = [
|
| 313 |
+
{ url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" },
|
| 314 |
+
]
|
| 315 |
+
|
| 316 |
+
[[package]]
|
| 317 |
+
name = "nvidia-cuda-nvrtc-cu12"
|
| 318 |
+
version = "12.8.93"
|
| 319 |
+
source = { registry = "https://pypi.org/simple" }
|
| 320 |
+
wheels = [
|
| 321 |
+
{ url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" },
|
| 322 |
+
]
|
| 323 |
+
|
| 324 |
+
[[package]]
|
| 325 |
+
name = "nvidia-cuda-runtime-cu12"
|
| 326 |
+
version = "12.8.90"
|
| 327 |
+
source = { registry = "https://pypi.org/simple" }
|
| 328 |
+
wheels = [
|
| 329 |
+
{ url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" },
|
| 330 |
+
]
|
| 331 |
+
|
| 332 |
+
[[package]]
|
| 333 |
+
name = "nvidia-cudnn-cu12"
|
| 334 |
+
version = "9.10.2.21"
|
| 335 |
+
source = { registry = "https://pypi.org/simple" }
|
| 336 |
+
dependencies = [
|
| 337 |
+
{ name = "nvidia-cublas-cu12" },
|
| 338 |
+
]
|
| 339 |
+
wheels = [
|
| 340 |
+
{ url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" },
|
| 341 |
+
]
|
| 342 |
+
|
| 343 |
+
[[package]]
|
| 344 |
+
name = "nvidia-cufft-cu12"
|
| 345 |
+
version = "11.3.3.83"
|
| 346 |
+
source = { registry = "https://pypi.org/simple" }
|
| 347 |
+
dependencies = [
|
| 348 |
+
{ name = "nvidia-nvjitlink-cu12" },
|
| 349 |
+
]
|
| 350 |
+
wheels = [
|
| 351 |
+
{ url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" },
|
| 352 |
+
]
|
| 353 |
+
|
| 354 |
+
[[package]]
|
| 355 |
+
name = "nvidia-cufile-cu12"
|
| 356 |
+
version = "1.13.1.3"
|
| 357 |
+
source = { registry = "https://pypi.org/simple" }
|
| 358 |
+
wheels = [
|
| 359 |
+
{ url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" },
|
| 360 |
+
]
|
| 361 |
+
|
| 362 |
+
[[package]]
|
| 363 |
+
name = "nvidia-curand-cu12"
|
| 364 |
+
version = "10.3.9.90"
|
| 365 |
+
source = { registry = "https://pypi.org/simple" }
|
| 366 |
+
wheels = [
|
| 367 |
+
{ url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" },
|
| 368 |
+
]
|
| 369 |
+
|
| 370 |
+
[[package]]
|
| 371 |
+
name = "nvidia-cusolver-cu12"
|
| 372 |
+
version = "11.7.3.90"
|
| 373 |
+
source = { registry = "https://pypi.org/simple" }
|
| 374 |
+
dependencies = [
|
| 375 |
+
{ name = "nvidia-cublas-cu12" },
|
| 376 |
+
{ name = "nvidia-cusparse-cu12" },
|
| 377 |
+
{ name = "nvidia-nvjitlink-cu12" },
|
| 378 |
+
]
|
| 379 |
+
wheels = [
|
| 380 |
+
{ url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" },
|
| 381 |
+
]
|
| 382 |
+
|
| 383 |
+
[[package]]
|
| 384 |
+
name = "nvidia-cusparse-cu12"
|
| 385 |
+
version = "12.5.8.93"
|
| 386 |
+
source = { registry = "https://pypi.org/simple" }
|
| 387 |
+
dependencies = [
|
| 388 |
+
{ name = "nvidia-nvjitlink-cu12" },
|
| 389 |
+
]
|
| 390 |
+
wheels = [
|
| 391 |
+
{ url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" },
|
| 392 |
+
]
|
| 393 |
+
|
| 394 |
+
[[package]]
|
| 395 |
+
name = "nvidia-cusparselt-cu12"
|
| 396 |
+
version = "0.7.1"
|
| 397 |
+
source = { registry = "https://pypi.org/simple" }
|
| 398 |
+
wheels = [
|
| 399 |
+
{ url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" },
|
| 400 |
+
]
|
| 401 |
+
|
| 402 |
+
[[package]]
|
| 403 |
+
name = "nvidia-nccl-cu12"
|
| 404 |
+
version = "2.27.3"
|
| 405 |
+
source = { registry = "https://pypi.org/simple" }
|
| 406 |
+
wheels = [
|
| 407 |
+
{ url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" },
|
| 408 |
+
]
|
| 409 |
+
|
| 410 |
+
[[package]]
|
| 411 |
+
name = "nvidia-nvjitlink-cu12"
|
| 412 |
+
version = "12.8.93"
|
| 413 |
+
source = { registry = "https://pypi.org/simple" }
|
| 414 |
+
wheels = [
|
| 415 |
+
{ url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" },
|
| 416 |
+
]
|
| 417 |
+
|
| 418 |
+
[[package]]
|
| 419 |
+
name = "nvidia-nvtx-cu12"
|
| 420 |
+
version = "12.8.90"
|
| 421 |
+
source = { registry = "https://pypi.org/simple" }
|
| 422 |
+
wheels = [
|
| 423 |
+
{ url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" },
|
| 424 |
+
]
|
| 425 |
+
|
| 426 |
+
[[package]]
|
| 427 |
+
name = "onnx"
|
| 428 |
+
version = "1.19.0"
|
| 429 |
+
source = { registry = "https://pypi.org/simple" }
|
| 430 |
+
dependencies = [
|
| 431 |
+
{ name = "ml-dtypes" },
|
| 432 |
+
{ name = "numpy" },
|
| 433 |
+
{ name = "protobuf" },
|
| 434 |
+
{ name = "typing-extensions" },
|
| 435 |
+
]
|
| 436 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5b/bf/b0a63ee9f3759dcd177b28c6f2cb22f2aecc6d9b3efecaabc298883caa5f/onnx-1.19.0.tar.gz", hash = "sha256:aa3f70b60f54a29015e41639298ace06adf1dd6b023b9b30f1bca91bb0db9473", size = 11949859, upload-time = "2025-08-27T02:34:27.107Z" }
|
| 437 |
+
wheels = [
|
| 438 |
+
{ url = "https://files.pythonhosted.org/packages/0d/94/f56f6ca5e2f921b28c0f0476705eab56486b279f04e1d568ed64c14e7764/onnx-1.19.0-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:61d94e6498ca636756f8f4ee2135708434601b2892b7c09536befb19bc8ca007", size = 18322331, upload-time = "2025-08-27T02:33:20.373Z" },
|
| 439 |
+
{ url = "https://files.pythonhosted.org/packages/c8/00/8cc3f3c40b54b28f96923380f57c9176872e475face726f7d7a78bd74098/onnx-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:224473354462f005bae985c72028aaa5c85ab11de1b71d55b06fdadd64a667dd", size = 18027513, upload-time = "2025-08-27T02:33:23.44Z" },
|
| 440 |
+
{ url = "https://files.pythonhosted.org/packages/61/90/17c4d2566fd0117a5e412688c9525f8950d467f477fbd574e6b32bc9cb8d/onnx-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae475c85c89bc4d1f16571006fd21a3e7c0e258dd2c091f6e8aafb083d1ed9b", size = 18202278, upload-time = "2025-08-27T02:33:26.103Z" },
|
| 441 |
+
{ url = "https://files.pythonhosted.org/packages/bc/6e/a9383d9cf6db4ac761a129b081e9fa5d0cd89aad43cf1e3fc6285b915c7d/onnx-1.19.0-cp312-cp312-win32.whl", hash = "sha256:323f6a96383a9cdb3960396cffea0a922593d221f3929b17312781e9f9b7fb9f", size = 16333080, upload-time = "2025-08-27T02:33:28.559Z" },
|
| 442 |
+
{ url = "https://files.pythonhosted.org/packages/a7/2e/3ff480a8c1fa7939662bdc973e41914add2d4a1f2b8572a3c39c2e4982e5/onnx-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:50220f3499a499b1a15e19451a678a58e22ad21b34edf2c844c6ef1d9febddc2", size = 16453927, upload-time = "2025-08-27T02:33:31.177Z" },
|
| 443 |
+
{ url = "https://files.pythonhosted.org/packages/57/37/ad500945b1b5c154fe9d7b826b30816ebd629d10211ea82071b5bcc30aa4/onnx-1.19.0-cp312-cp312-win_arm64.whl", hash = "sha256:efb768299580b786e21abe504e1652ae6189f0beed02ab087cd841cb4bb37e43", size = 16426022, upload-time = "2025-08-27T02:33:33.515Z" },
|
| 444 |
+
]
|
| 445 |
+
|
| 446 |
+
[[package]]
|
| 447 |
+
name = "onnx-ir"
|
| 448 |
+
version = "0.1.3"
|
| 449 |
+
source = { registry = "https://pypi.org/simple" }
|
| 450 |
+
dependencies = [
|
| 451 |
+
{ name = "ml-dtypes" },
|
| 452 |
+
{ name = "numpy" },
|
| 453 |
+
{ name = "onnx" },
|
| 454 |
+
{ name = "typing-extensions" },
|
| 455 |
+
]
|
| 456 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1c/ad/00807b7b6887a9107f651d7d549dec9cb9d34f09884d326e39a05a5572e1/onnx_ir-0.1.3.tar.gz", hash = "sha256:239dab04addc5cadbf496b8d41caeac771f6791239718fd43cef3987b5d20305", size = 105791, upload-time = "2025-06-26T16:23:37.216Z" }
|
| 457 |
+
wheels = [
|
| 458 |
+
{ url = "https://files.pythonhosted.org/packages/04/5b/e44d474d70e10b633f547692b1f6bbda29ccaae2eb4eb8ad73fc699aaed3/onnx_ir-0.1.3-py3-none-any.whl", hash = "sha256:d52f4316fa39a51bf6547cb0fed4a17811ea452023ef870ea6ba9f3eec1ff52c", size = 119195, upload-time = "2025-06-26T16:23:35.545Z" },
|
| 459 |
+
]
|
| 460 |
+
|
| 461 |
+
[[package]]
|
| 462 |
+
name = "onnxruntime"
|
| 463 |
+
version = "1.30.0"
|
| 464 |
+
source = { registry = "https://pypi.org/simple" }
|
| 465 |
+
dependencies = [
|
| 466 |
+
{ name = "flatbuffers" },
|
| 467 |
+
{ name = "numpy" },
|
| 468 |
+
{ name = "packaging" },
|
| 469 |
+
{ name = "protobuf" },
|
| 470 |
+
]
|
| 471 |
+
wheels = [
|
| 472 |
+
{ url = "https://files.pythonhosted.org/packages/31/6f/48169f2e62b405bff5053cbd1d73fb5ce41ef7ecd13bb3bfcc191e689b8a/onnxruntime-1.30.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:001ed726c9bd5e2bc92faade7d37d889e9606a350b7d5529f0227df2e3bb57fd", size = 21544867, upload-time = "2026-09-10T16:31:19.876Z" },
|
| 473 |
+
{ url = "https://files.pythonhosted.org/packages/16/bd/cbc5b8f91963689fdd622f463508c01d0aa95d3f944747b1e0b1eb2160b8/onnxruntime-1.30.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:6c32a000d5139a38ba9349030b0032e3331acb559d596b22738d9d2b343a2b83", size = 21345202, upload-time = "2026-09-10T16:31:23.361Z" },
|
| 474 |
+
{ url = "https://files.pythonhosted.org/packages/34/35/e7f862dbacbc99fadd9b14a614e49c99bf0f35fd9927a82f096e3de33531/onnxruntime-1.30.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:fa688e7891a6aa206636fe7372e27ee75fd17713289f6b4fc7b190e0a7de9328", size = 23585654, upload-time = "2026-09-10T16:31:26.65Z" },
|
| 475 |
+
{ url = "https://files.pythonhosted.org/packages/a6/13/0f1699f6de549c9324bc9112a2a85b14c517904cd11b562a654643b755a1/onnxruntime-1.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:f3501472571f1b1eee50e017851e7929f5ea37312d2d8c2494a19e8fc58b4a38", size = 14311470, upload-time = "2026-09-10T16:31:31.273Z" },
|
| 476 |
+
{ url = "https://files.pythonhosted.org/packages/a2/17/02b13e5f51461f0453b18ab854e2d0bc1b6ec353241b05a2ee6b79e35d87/onnxruntime-1.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:dc4c706f1935ebb62356e6a095b047859badd854482c40560888e95c328ed262", size = 14175072, upload-time = "2026-09-10T16:31:34.541Z" },
|
| 477 |
+
]
|
| 478 |
+
|
| 479 |
+
[[package]]
|
| 480 |
+
name = "onnxruntime-genai"
|
| 481 |
+
version = "0.16.0"
|
| 482 |
+
source = { registry = "https://pypi.org/simple" }
|
| 483 |
+
dependencies = [
|
| 484 |
+
{ name = "numpy" },
|
| 485 |
+
{ name = "onnxruntime" },
|
| 486 |
+
]
|
| 487 |
+
wheels = [
|
| 488 |
+
{ url = "https://files.pythonhosted.org/packages/a0/ba/8ad8cdf62ee816e019a9b3f56bf2cb2a63629a9aeeb0cf9d1a256dc28d5d/onnxruntime_genai-0.16.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1a861b2176424fa172795250bb0c2326be1340538706f454bffef7e70918702b", size = 5236371, upload-time = "2026-09-13T07:42:10.745Z" },
|
| 489 |
+
{ url = "https://files.pythonhosted.org/packages/84/c5/36a3d6be3f4742bc1d658329196b7a791c55c5771230d3ac20e9415ad583/onnxruntime_genai-0.16.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:504b9ec876fe35d83f01b53816ee0091ca4be7c1673806947f20754643fb5f77", size = 11997330, upload-time = "2026-09-13T07:42:12.709Z" },
|
| 490 |
+
{ url = "https://files.pythonhosted.org/packages/f5/6a/3732820f12d502f6fe094bb4ff0edb490fe72cf970bb62c07b803672bda4/onnxruntime_genai-0.16.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:0fd61645bdffedc644cba9e02001082d28d5cbf92e705925ea1a769bfeba3d8c", size = 12359325, upload-time = "2026-09-13T07:42:14.875Z" },
|
| 491 |
+
{ url = "https://files.pythonhosted.org/packages/8d/e3/2e79dea57d8e2dcdbfd985825d8044f994a174cf9cfe98b29ee3af407589/onnxruntime_genai-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:4427d8f3a6a9f1a77c1cdfb9efc1a9af518ab78bd70991db3eb9eae3ac7bdc56", size = 4128674, upload-time = "2026-09-13T07:42:16.987Z" },
|
| 492 |
+
{ url = "https://files.pythonhosted.org/packages/4d/f4/1ed79731608b8e6dc52b6b25e92e0596750e30a04aebaa22c55913bbe3f5/onnxruntime_genai-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:f3bdf8a701e761c427449a68f88aa26de0b6fcfaf6084b605a5bb1ff7a623742", size = 3967050, upload-time = "2026-09-13T07:42:18.486Z" },
|
| 493 |
+
]
|
| 494 |
+
|
| 495 |
+
[[package]]
|
| 496 |
+
name = "openthai-systemone"
|
| 497 |
+
version = "0.1.0"
|
| 498 |
+
source = { git = "https://github.com/iapp-technology/openthai-systemone.git?rev=5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf#5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf" }
|
| 499 |
+
dependencies = [
|
| 500 |
+
{ name = "numpy" },
|
| 501 |
+
{ name = "pydantic" },
|
| 502 |
+
{ name = "torch" },
|
| 503 |
+
{ name = "transformers" },
|
| 504 |
+
]
|
| 505 |
+
|
| 506 |
+
[[package]]
|
| 507 |
+
name = "openthai-systemone-onnx"
|
| 508 |
+
version = "0.1.0"
|
| 509 |
+
source = { editable = "." }
|
| 510 |
+
dependencies = [
|
| 511 |
+
{ name = "huggingface-hub" },
|
| 512 |
+
{ name = "numpy" },
|
| 513 |
+
{ name = "onnxruntime" },
|
| 514 |
+
{ name = "openthai-systemone" },
|
| 515 |
+
{ name = "torch" },
|
| 516 |
+
{ name = "transformers" },
|
| 517 |
+
]
|
| 518 |
+
|
| 519 |
+
[package.optional-dependencies]
|
| 520 |
+
dev = [
|
| 521 |
+
{ name = "pytest" },
|
| 522 |
+
{ name = "pytest-cov" },
|
| 523 |
+
]
|
| 524 |
+
tools = [
|
| 525 |
+
{ name = "onnx" },
|
| 526 |
+
{ name = "onnx-ir" },
|
| 527 |
+
{ name = "onnxruntime-genai" },
|
| 528 |
+
{ name = "safetensors" },
|
| 529 |
+
]
|
| 530 |
+
|
| 531 |
+
[package.metadata]
|
| 532 |
+
requires-dist = [
|
| 533 |
+
{ name = "huggingface-hub", specifier = "==1.5.0" },
|
| 534 |
+
{ name = "numpy", specifier = "==2.3.3" },
|
| 535 |
+
{ name = "onnx", marker = "extra == 'tools'", specifier = "==1.19.0" },
|
| 536 |
+
{ name = "onnx-ir", marker = "extra == 'tools'", specifier = "==0.1.3" },
|
| 537 |
+
{ name = "onnxruntime", specifier = "==1.30.0" },
|
| 538 |
+
{ name = "onnxruntime-genai", marker = "extra == 'tools'", specifier = "==0.16.0" },
|
| 539 |
+
{ name = "openthai-systemone", git = "https://github.com/iapp-technology/openthai-systemone.git?rev=5d04bcca0c58bd10e7dac2d3d369d8f760bea6cf" },
|
| 540 |
+
{ name = "pytest", marker = "extra == 'dev'", specifier = "==8.4.2" },
|
| 541 |
+
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = "==7.0.0" },
|
| 542 |
+
{ name = "safetensors", marker = "extra == 'tools'", specifier = "==0.8.0" },
|
| 543 |
+
{ name = "torch", specifier = "==2.8.0" },
|
| 544 |
+
{ name = "transformers", git = "https://github.com/huggingface/transformers.git?rev=856157a2f3e9594954310df18fdccc31ffddebe9" },
|
| 545 |
+
]
|
| 546 |
+
provides-extras = ["tools", "dev"]
|
| 547 |
+
|
| 548 |
+
[[package]]
|
| 549 |
+
name = "packaging"
|
| 550 |
+
version = "26.3"
|
| 551 |
+
source = { registry = "https://pypi.org/simple" }
|
| 552 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
| 553 |
+
wheels = [
|
| 554 |
+
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
| 555 |
+
]
|
| 556 |
+
|
| 557 |
+
[[package]]
|
| 558 |
+
name = "pluggy"
|
| 559 |
+
version = "1.6.0"
|
| 560 |
+
source = { registry = "https://pypi.org/simple" }
|
| 561 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
| 562 |
+
wheels = [
|
| 563 |
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 564 |
+
]
|
| 565 |
+
|
| 566 |
+
[[package]]
|
| 567 |
+
name = "protobuf"
|
| 568 |
+
version = "7.36.2"
|
| 569 |
+
source = { registry = "https://pypi.org/simple" }
|
| 570 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d9/89/5b8517baa72f84a67b8a307ba953c91057af618bf40bf676f3c03551f8f0/protobuf-7.36.2.tar.gz", hash = "sha256:497d0463ff3316681da6c0b9e8d06cb465d61abce00b613ab42226175644d1bb", size = 512737, upload-time = "2026-09-17T20:07:59.326Z" }
|
| 571 |
+
wheels = [
|
| 572 |
+
{ url = "https://files.pythonhosted.org/packages/32/72/98342feb672507c8f3a69e34b4fa8961f608edba5c1a48a6f47156d92cb5/protobuf-7.36.2-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:cbc70b17ee27e28894c7fee8bb04be1abead49e936bc70eb60052531eee2079e", size = 456039, upload-time = "2026-09-17T20:07:51.542Z" },
|
| 573 |
+
{ url = "https://files.pythonhosted.org/packages/b6/ea/91fdf7c2b8bbd49cde056f00a9df6773532987e1c00fe2830b895af95c7e/protobuf-7.36.2-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:e11e1f0180583a2af89db6a2ecd9e8dc40aa6d2988ca175bfd0e6d12ea72d74e", size = 344219, upload-time = "2026-09-17T20:07:52.914Z" },
|
| 574 |
+
{ url = "https://files.pythonhosted.org/packages/17/ab/5fd5f8ece73fad885c5a09aa849b32d70472f954ba3a92d3bb5974ea953b/protobuf-7.36.2-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:f4fee11ec330d238b34a05c9b675f693c20415d1c5bd7d5320cc2f8a798eb9cf", size = 357223, upload-time = "2026-09-17T20:07:53.985Z" },
|
| 575 |
+
{ url = "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:89f23aa53c24553a2416fd4fd1ec06f74fa42b14b546d8883128813f775bbfd2", size = 343223, upload-time = "2026-09-17T20:07:54.931Z" },
|
| 576 |
+
{ url = "https://files.pythonhosted.org/packages/fc/1b/dcc64f358fcb51811b58ae40b3d28f820725f116d86487cc20bd4b130701/protobuf-7.36.2-cp310-abi3-win32.whl", hash = "sha256:912c1221170e16c08d1f086762f563dd61ff83c18b5fa6652952dfaded66f728", size = 442998, upload-time = "2026-09-17T20:07:55.826Z" },
|
| 577 |
+
{ url = "https://files.pythonhosted.org/packages/8a/55/b77bda4e5e5f5971fb51b07663694690e9afdb9402136c16a522bd621cad/protobuf-7.36.2-cp310-abi3-win_amd64.whl", hash = "sha256:a300819d441e078a5608c0d3c709796bb548136058fda017ae51d425b44fd353", size = 456514, upload-time = "2026-09-17T20:07:57.188Z" },
|
| 578 |
+
{ url = "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl", hash = "sha256:bdb3a345d48db958e6ce1f18e508beb0cc981d64f24088427549c866cd039f1e", size = 179806, upload-time = "2026-09-17T20:07:58.211Z" },
|
| 579 |
+
]
|
| 580 |
+
|
| 581 |
+
[[package]]
|
| 582 |
+
name = "pydantic"
|
| 583 |
+
version = "2.13.5"
|
| 584 |
+
source = { registry = "https://pypi.org/simple" }
|
| 585 |
+
dependencies = [
|
| 586 |
+
{ name = "annotated-types" },
|
| 587 |
+
{ name = "pydantic-core" },
|
| 588 |
+
{ name = "typing-extensions" },
|
| 589 |
+
{ name = "typing-inspection" },
|
| 590 |
+
]
|
| 591 |
+
sdist = { url = "https://files.pythonhosted.org/packages/53/ef/fc4f868f4e2cee79f863883abffceff107875f569b848507319842d2a681/pydantic-2.13.5.tar.gz", hash = "sha256:51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08", size = 845750, upload-time = "2026-08-28T14:04:00.916Z" }
|
| 592 |
+
wheels = [
|
| 593 |
+
{ url = "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl", hash = "sha256:346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73", size = 472589, upload-time = "2026-08-28T14:03:59.136Z" },
|
| 594 |
+
]
|
| 595 |
+
|
| 596 |
+
[[package]]
|
| 597 |
+
name = "pydantic-core"
|
| 598 |
+
version = "2.46.5"
|
| 599 |
+
source = { registry = "https://pypi.org/simple" }
|
| 600 |
+
dependencies = [
|
| 601 |
+
{ name = "typing-extensions" },
|
| 602 |
+
]
|
| 603 |
+
sdist = { url = "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz", hash = "sha256:10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc", size = 472262, upload-time = "2026-08-28T10:01:31.677Z" }
|
| 604 |
+
wheels = [
|
| 605 |
+
{ url = "https://files.pythonhosted.org/packages/82/3f/76358795aa7a8c6d4f36e2cb828ad1c90ee118e1393a9281664f5aade9d4/pydantic_core-2.46.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d", size = 2076516, upload-time = "2026-08-28T09:58:21.576Z" },
|
| 606 |
+
{ url = "https://files.pythonhosted.org/packages/db/50/26b091836076ce4cb2fac264186936acc069e0595772cfd02a563bc4761a/pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e", size = 1922874, upload-time = "2026-08-28T09:58:23.766Z" },
|
| 607 |
+
{ url = "https://files.pythonhosted.org/packages/09/f0/2a8ce3849e299d44e2d2c196b6082643a3235565a735cb51db7a6261f614/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29", size = 1951772, upload-time = "2026-08-28T09:58:25.435Z" },
|
| 608 |
+
{ url = "https://files.pythonhosted.org/packages/87/46/ac0dc8bdd9e6048183a14eb127764e7ad9240021c17513074a4711b0e31e/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4", size = 2031832, upload-time = "2026-08-28T09:58:27.102Z" },
|
| 609 |
+
{ url = "https://files.pythonhosted.org/packages/c4/c2/339de5bef7be36301a2231eaa52e62163742c2281f11b5f4892bc79785cd/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a", size = 2208645, upload-time = "2026-08-28T09:58:28.948Z" },
|
| 610 |
+
{ url = "https://files.pythonhosted.org/packages/7b/a0/9ff22b797724262da14427abaed4dd1d864a139693fc5e7809114376a716/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62", size = 2265935, upload-time = "2026-08-28T09:58:30.625Z" },
|
| 611 |
+
{ url = "https://files.pythonhosted.org/packages/c0/a4/eb9409ec0736e50aa70a412f16c204ed149516846912f7e6724d4c73ee53/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2", size = 2066284, upload-time = "2026-08-28T09:58:32.289Z" },
|
| 612 |
+
{ url = "https://files.pythonhosted.org/packages/c0/02/7f6156ffc926857f1c37c07d9a388682865a81830ab6a1b637082c25e399/pydantic_core-2.46.5-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869", size = 2105889, upload-time = "2026-08-28T09:58:33.986Z" },
|
| 613 |
+
{ url = "https://files.pythonhosted.org/packages/92/b1/e781d357ebe09fc929f995700f1b3503e8897f1cece183ecb1300d4d67e9/pydantic_core-2.46.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5", size = 2158006, upload-time = "2026-08-28T09:58:35.647Z" },
|
| 614 |
+
{ url = "https://files.pythonhosted.org/packages/70/0a/644597d84ab400e50609c192120b85c9681c22d3a20461b9060a79be0a7a/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3", size = 2158408, upload-time = "2026-08-28T09:58:37.38Z" },
|
| 615 |
+
{ url = "https://files.pythonhosted.org/packages/1e/ee/ca3b7b3a4b3769ffe9ce9432a7c9be755de9593a46d3b0d54d0409323e44/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b", size = 2309609, upload-time = "2026-08-28T09:58:39.22Z" },
|
| 616 |
+
{ url = "https://files.pythonhosted.org/packages/ce/52/39fa1f451486019524ca685020390e7ca351832fd874530ba30c8628e6dc/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0", size = 2342618, upload-time = "2026-08-28T09:58:40.89Z" },
|
| 617 |
+
{ url = "https://files.pythonhosted.org/packages/81/5e/468fc630568c61dcef3cd47ad32ffbeed9af643f49208d1ea86ab4f890c4/pydantic_core-2.46.5-cp312-cp312-win32.whl", hash = "sha256:5cb482e9e84c851f4e623fe4acc1ced89168cf1fe18f7089db4548c8f5bbb65b", size = 1939475, upload-time = "2026-08-28T09:58:42.591Z" },
|
| 618 |
+
{ url = "https://files.pythonhosted.org/packages/cf/c9/4c19f41b84cf6b622a72fbeed7665b25d47a187d68d47d0d430c07f23268/pydantic_core-2.46.5-cp312-cp312-win_amd64.whl", hash = "sha256:5e81740c09e310f5aa5cbd3e434a01c154d4bef93241c7877b39f211d2b78ba8", size = 2043140, upload-time = "2026-08-28T09:58:44.272Z" },
|
| 619 |
+
{ url = "https://files.pythonhosted.org/packages/af/dd/0c1a050299147c746e5256db16d645ab5efd4f78c59937d581a0524e74a2/pydantic_core-2.46.5-cp312-cp312-win_arm64.whl", hash = "sha256:f7b0ec93a2893de856652154d73b7ba622f26fa97726487dcac373de5f4c6084", size = 1997729, upload-time = "2026-08-28T09:58:46.13Z" },
|
| 620 |
+
{ url = "https://files.pythonhosted.org/packages/df/dd/053c2e4303f791f3b8f8a14ab0b22008e8eb21d868c0c90b4f9be705b76a/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:013d6f3483d81e02e7c328831808f336c8596ee33b4bd4026b9ffb1e960b8942", size = 2062540, upload-time = "2026-08-28T10:01:00.318Z" },
|
| 621 |
+
{ url = "https://files.pythonhosted.org/packages/d7/dd/a18df751a5e37dd51bfad7f68e766999125bebe68c9e1d10a493ad01bd63/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:e9c134bb666dd54b778b9fc0d2b50cbb7f979b9e3716f26a88c9ab3b6fc1dd0f", size = 1902040, upload-time = "2026-08-28T10:01:02.529Z" },
|
| 622 |
+
{ url = "https://files.pythonhosted.org/packages/b7/13/01d40f9d07ce8a779fd6e0bd8ad4fba91309500dd67b869e2e219d261a6d/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:347ec774390c87326a2e4929d58d3f7e8763a104d5d35f4cd595a4c952366433", size = 1967479, upload-time = "2026-08-28T10:01:05.004Z" },
|
| 623 |
+
{ url = "https://files.pythonhosted.org/packages/fa/04/c81d4841331c2178b6fb09ae225425e110ed72d990c9fe556c4ec03d1013/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e24d8f05fa2d28513d94e877e9c75ad66175376209b3977f916e240e623193c", size = 2111034, upload-time = "2026-08-28T10:01:07.345Z" },
|
| 624 |
+
]
|
| 625 |
+
|
| 626 |
+
[[package]]
|
| 627 |
+
name = "pygments"
|
| 628 |
+
version = "2.21.0"
|
| 629 |
+
source = { registry = "https://pypi.org/simple" }
|
| 630 |
+
sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" }
|
| 631 |
+
wheels = [
|
| 632 |
+
{ url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
|
| 633 |
+
]
|
| 634 |
+
|
| 635 |
+
[[package]]
|
| 636 |
+
name = "pytest"
|
| 637 |
+
version = "8.4.2"
|
| 638 |
+
source = { registry = "https://pypi.org/simple" }
|
| 639 |
+
dependencies = [
|
| 640 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 641 |
+
{ name = "iniconfig" },
|
| 642 |
+
{ name = "packaging" },
|
| 643 |
+
{ name = "pluggy" },
|
| 644 |
+
{ name = "pygments" },
|
| 645 |
+
]
|
| 646 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
|
| 647 |
+
wheels = [
|
| 648 |
+
{ url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
|
| 649 |
+
]
|
| 650 |
+
|
| 651 |
+
[[package]]
|
| 652 |
+
name = "pytest-cov"
|
| 653 |
+
version = "7.0.0"
|
| 654 |
+
source = { registry = "https://pypi.org/simple" }
|
| 655 |
+
dependencies = [
|
| 656 |
+
{ name = "coverage" },
|
| 657 |
+
{ name = "pluggy" },
|
| 658 |
+
{ name = "pytest" },
|
| 659 |
+
]
|
| 660 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
|
| 661 |
+
wheels = [
|
| 662 |
+
{ url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
|
| 663 |
+
]
|
| 664 |
+
|
| 665 |
+
[[package]]
|
| 666 |
+
name = "pyyaml"
|
| 667 |
+
version = "6.0.3"
|
| 668 |
+
source = { registry = "https://pypi.org/simple" }
|
| 669 |
+
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
| 670 |
+
wheels = [
|
| 671 |
+
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
|
| 672 |
+
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
|
| 673 |
+
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
|
| 674 |
+
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
|
| 675 |
+
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
|
| 676 |
+
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
|
| 677 |
+
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
|
| 678 |
+
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
|
| 679 |
+
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
|
| 680 |
+
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
|
| 681 |
+
]
|
| 682 |
+
|
| 683 |
+
[[package]]
|
| 684 |
+
name = "regex"
|
| 685 |
+
version = "2026.9.10"
|
| 686 |
+
source = { registry = "https://pypi.org/simple" }
|
| 687 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b9/5c/f403115361de25809e8f785686ec7096e30fef73be9ae35aa51da4e80abb/regex-2026.9.10.tar.gz", hash = "sha256:1e321e2c84f0e52c457f5ea5944f796d6e8e09cb99738ea98dcc1bfe402a128d", size = 417072, upload-time = "2026-09-09T21:00:21.521Z" }
|
| 688 |
+
wheels = [
|
| 689 |
+
{ url = "https://files.pythonhosted.org/packages/32/c8/bfbe893e90ee0148bd2860dd086f09b5d2080ca2b125f740c2e118c16982/regex-2026.9.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880ac684c27176464c00c3fdc456116364f5ebc70da07aad0c2d4a7ba45e98db", size = 496609, upload-time = "2026-09-09T20:57:09.987Z" },
|
| 690 |
+
{ url = "https://files.pythonhosted.org/packages/8c/ac/56d5ae6efb759255c3b3db650a4be25f96a844ea3613b91e1e189a3b7294/regex-2026.9.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9d36b03dc362aa40ffaaec9d9bd75e87763529563ec008c43b0e07782f5be7a", size = 297024, upload-time = "2026-09-09T20:57:11.35Z" },
|
| 691 |
+
{ url = "https://files.pythonhosted.org/packages/60/4b/0f2d5f6bbb791cc10f22f0ed16c487e630dde8fa8fa0bd92a2bfe21a4b20/regex-2026.9.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866de9f98df0611d7b62b3a8729d3284a64c0cc6edd90bb95a533e443a4939cb", size = 291905, upload-time = "2026-09-09T20:57:13.127Z" },
|
| 692 |
+
{ url = "https://files.pythonhosted.org/packages/89/51/3fb5fe0d32f4cf0bc982286722c729a8d6f522d2fa2d5d14a702d9fc87f8/regex-2026.9.10-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c66d54042a14a503907d81861b8a5235e6d1f03d4fbc1d8767f652eaf957ac1", size = 800055, upload-time = "2026-09-09T20:57:14.68Z" },
|
| 693 |
+
{ url = "https://files.pythonhosted.org/packages/89/46/ee507bd2f9d4420f26a594b35c551d7194b66f5d7897f63730fae6ec05c1/regex-2026.9.10-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:032da15431c890d376f53547f0a6219f4f4cd19f3e4f11bdc321453b5bd207e4", size = 871133, upload-time = "2026-09-09T20:57:16.674Z" },
|
| 694 |
+
{ url = "https://files.pythonhosted.org/packages/d1/75/cbaa90689684f91b1bc017e7f8c6d9425c6bd299108db02482dc51376d8a/regex-2026.9.10-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:23ac9a28180f274d7dd7651fa131ad5b02d343b75df4b040737f0356223895dd", size = 919627, upload-time = "2026-09-09T20:57:18.402Z" },
|
| 695 |
+
{ url = "https://files.pythonhosted.org/packages/cb/f5/dcdf5e0d898024005cfcce631e3e934d111dfbe177ca0b7f253ae8a735a2/regex-2026.9.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e67f8843f0e4b931f1fa860bf3bbe4134b714c0155cc5c7c0d7ea450230aae0", size = 804587, upload-time = "2026-09-09T20:57:19.859Z" },
|
| 696 |
+
{ url = "https://files.pythonhosted.org/packages/73/70/eedfe81c29bae266a06ab4250978361a9bccd474704d88d4f4ef4506dff8/regex-2026.9.10-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bb7774924f8cd69f49cba0b3c2d679a6326f777e0e67d130ad5203e4df53f0d3", size = 777320, upload-time = "2026-09-09T20:57:21.62Z" },
|
| 697 |
+
{ url = "https://files.pythonhosted.org/packages/ca/e5/86b207077efbcd91305700488f170b7eb1e1c54721cea74175273aa3b9a4/regex-2026.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c32480f3371b75068decaf9e5da72c224e953830dd71e36e06cf80e30ea39d8", size = 790572, upload-time = "2026-09-09T20:57:23.048Z" },
|
| 698 |
+
{ url = "https://files.pythonhosted.org/packages/b2/92/f622c3b2323f4c035b98e80221740a442127ad7993135b814f52057430db/regex-2026.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d2d377fd1cad611b806cdd732d86b65f536c768209890cb442556548daa65a23", size = 865485, upload-time = "2026-09-09T20:57:24.658Z" },
|
| 699 |
+
{ url = "https://files.pythonhosted.org/packages/4a/be/34bd621d3d6ac906ad67e57ed56c40cd45f7d51b9c0328335e97a7cb8ecb/regex-2026.9.10-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c014641157e9049b0603b8daa5343bd408d9b757b709aaa0f373cd3fab2d7944", size = 767925, upload-time = "2026-09-09T20:57:26.268Z" },
|
| 700 |
+
{ url = "https://files.pythonhosted.org/packages/0d/28/ddbf7cba86f2adf5038c6c16aa829636ffc6e437f81bb0cbf302899cea5e/regex-2026.9.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1562aabd9d4eb09bd88a62ad97ed06800094b529ac43419e43020b9cefec79b0", size = 858800, upload-time = "2026-09-09T20:57:27.901Z" },
|
| 701 |
+
{ url = "https://files.pythonhosted.org/packages/d0/f1/e8d7656ff3d3bd32e881d32f540b4981c79dee61908d6b790a45966e6895/regex-2026.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2479171edccced52ef02b899558f88ab2c235fe05b93180fdcae1670aacd89e1", size = 791648, upload-time = "2026-09-09T20:57:29.786Z" },
|
| 702 |
+
{ url = "https://files.pythonhosted.org/packages/fc/65/eac1a79115c8475d8ff539602eb54031564d719fdea5a599c4b0a1a26d1b/regex-2026.9.10-cp312-cp312-win32.whl", hash = "sha256:239620b0e0681669367c0e218c8eb2551d9f8fe3b9fccfc8d0003377804e8348", size = 267326, upload-time = "2026-09-09T20:57:31.782Z" },
|
| 703 |
+
{ url = "https://files.pythonhosted.org/packages/ad/d4/4dcd0a05d3e97ca829165df1c39717f899d1d484dac8a6032439f2cb8d6d/regex-2026.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4db7d00c4afbfbb55b8e17b1e371da11418ea9389b030acec63c1fa4c7ad4b86", size = 277933, upload-time = "2026-09-09T20:57:33.648Z" },
|
| 704 |
+
{ url = "https://files.pythonhosted.org/packages/55/f8/22617a80dee28f2451011eae36bc26b3d78c4994ba87b5281d60acf9b6c0/regex-2026.9.10-cp312-cp312-win_arm64.whl", hash = "sha256:c25a754bb81a2edcfc3b65eda50f017d736f818112ed43e8aafd595cb00678ae", size = 277447, upload-time = "2026-09-09T20:57:35.156Z" },
|
| 705 |
+
]
|
| 706 |
+
|
| 707 |
+
[[package]]
|
| 708 |
+
name = "rich"
|
| 709 |
+
version = "15.0.0"
|
| 710 |
+
source = { registry = "https://pypi.org/simple" }
|
| 711 |
+
dependencies = [
|
| 712 |
+
{ name = "markdown-it-py" },
|
| 713 |
+
{ name = "pygments" },
|
| 714 |
+
]
|
| 715 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
| 716 |
+
wheels = [
|
| 717 |
+
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
| 718 |
+
]
|
| 719 |
+
|
| 720 |
+
[[package]]
|
| 721 |
+
name = "safetensors"
|
| 722 |
+
version = "0.8.0"
|
| 723 |
+
source = { registry = "https://pypi.org/simple" }
|
| 724 |
+
sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" }
|
| 725 |
+
wheels = [
|
| 726 |
+
{ url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" },
|
| 727 |
+
{ url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" },
|
| 728 |
+
{ url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" },
|
| 729 |
+
{ url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" },
|
| 730 |
+
{ url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" },
|
| 731 |
+
{ url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" },
|
| 732 |
+
{ url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" },
|
| 733 |
+
{ url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" },
|
| 734 |
+
{ url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" },
|
| 735 |
+
{ url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" },
|
| 736 |
+
{ url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" },
|
| 737 |
+
{ url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" },
|
| 738 |
+
{ url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" },
|
| 739 |
+
{ url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" },
|
| 740 |
+
{ url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" },
|
| 741 |
+
{ url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" },
|
| 742 |
+
]
|
| 743 |
+
|
| 744 |
+
[[package]]
|
| 745 |
+
name = "setuptools"
|
| 746 |
+
version = "84.0.0"
|
| 747 |
+
source = { registry = "https://pypi.org/simple" }
|
| 748 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
|
| 749 |
+
wheels = [
|
| 750 |
+
{ url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
|
| 751 |
+
]
|
| 752 |
+
|
| 753 |
+
[[package]]
|
| 754 |
+
name = "shellingham"
|
| 755 |
+
version = "1.5.4"
|
| 756 |
+
source = { registry = "https://pypi.org/simple" }
|
| 757 |
+
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
| 758 |
+
wheels = [
|
| 759 |
+
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
| 760 |
+
]
|
| 761 |
+
|
| 762 |
+
[[package]]
|
| 763 |
+
name = "sympy"
|
| 764 |
+
version = "1.14.0"
|
| 765 |
+
source = { registry = "https://pypi.org/simple" }
|
| 766 |
+
dependencies = [
|
| 767 |
+
{ name = "mpmath" },
|
| 768 |
+
]
|
| 769 |
+
sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
|
| 770 |
+
wheels = [
|
| 771 |
+
{ url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
|
| 772 |
+
]
|
| 773 |
+
|
| 774 |
+
[[package]]
|
| 775 |
+
name = "tokenizers"
|
| 776 |
+
version = "0.23.2"
|
| 777 |
+
source = { registry = "https://pypi.org/simple" }
|
| 778 |
+
dependencies = [
|
| 779 |
+
{ name = "huggingface-hub" },
|
| 780 |
+
]
|
| 781 |
+
sdist = { url = "https://files.pythonhosted.org/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz", hash = "sha256:7f0f085686b9de0d0079e6f874ae053600db64c5d13049e0bbc0119926d25aac", size = 385745, upload-time = "2026-09-03T08:55:42.89Z" }
|
| 782 |
+
wheels = [
|
| 783 |
+
{ url = "https://files.pythonhosted.org/packages/4d/ed/8a443528baa6fac8dfe8c3b75b038c63ac92bb539bcabe311e227c718173/tokenizers-0.23.2-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:85a9a357a3764aecc904ee76bdaf8cf1ad8e5a67a1b929a487c4a39b49ed0e90", size = 3148852, upload-time = "2026-09-03T08:55:30.874Z" },
|
| 784 |
+
{ url = "https://files.pythonhosted.org/packages/67/49/22da045a91732384d3a3771816bf188dc5a1f702c32e635afa7c679c0bef/tokenizers-0.23.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:986670e43691469dcee610ea0f846f91a8f84e91fc6f7a48d4c064414c0ec2bf", size = 3101593, upload-time = "2026-09-03T08:55:28.587Z" },
|
| 785 |
+
{ url = "https://files.pythonhosted.org/packages/2e/4d/8f569ed49372a3ed8e57099bd515055fd48d7c95912c4307cda6973c2168/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a37039b5dfc4af84eb3ef0a92f4307e28936c8f9adccba2629d36f652e9bf7a2", size = 3516830, upload-time = "2026-09-03T08:55:14.741Z" },
|
| 786 |
+
{ url = "https://files.pythonhosted.org/packages/2a/de/e2f14c8919d5bf51874051d00d6c7b7e0e8bde6c6a2dbeddda7f642896ff/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b7e37ba198f24150f523e1242e83c4970de4a525480586be5dcc24d9add32c5", size = 3407975, upload-time = "2026-09-03T08:55:16.842Z" },
|
| 787 |
+
{ url = "https://files.pythonhosted.org/packages/c5/bd/93c69152d02ef06ce47aed8b2bf4952dcf733c935a62791873932b2934d9/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43e4f2071e3cc8d5d86421c874aebc82659bb51a68bcdef5a0da75ee89511ccb", size = 3748165, upload-time = "2026-09-03T08:55:24.769Z" },
|
| 788 |
+
{ url = "https://files.pythonhosted.org/packages/2d/b7/56b84b80bc96942bba8eb23751a9e8a1fce4faaf4390425e7083f721c98c/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:325fee2e0418a9dc6c9ecf736a5f5f0db7875183ace9549ae339da76f7a1fbb7", size = 4024165, upload-time = "2026-09-03T08:55:18.806Z" },
|
| 789 |
+
{ url = "https://files.pythonhosted.org/packages/9b/8a/0175e216f005c2fe08238292663aa41e4c802b216e71047a69a0e9fc6fa3/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:950d7c9426fa72406a0ffeacdbc0bb9985f5db20eb8b263f29c79aaf83105703", size = 3591899, upload-time = "2026-09-03T08:55:22.752Z" },
|
| 790 |
+
{ url = "https://files.pythonhosted.org/packages/2c/ca/ca6b93c7820df123b2662a9469e8facc826ccc94e98fdd0d615f6431e73a/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41c2f84d172449b4dadb9cdc508e3e364076613c35b16e76ecfe47a60d1e3305", size = 3386843, upload-time = "2026-09-03T08:55:26.584Z" },
|
| 791 |
+
{ url = "https://files.pythonhosted.org/packages/e9/a4/4f9106d317b14a80aefea9f0e3a8d07ef25f856a7607eb7f5ab894281fcb/tokenizers-0.23.2-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:12f0835dc2ee694746a76adf7b1567d4346a4a502ebe93fb1f5f80ea49799b78", size = 3577314, upload-time = "2026-09-03T08:55:20.825Z" },
|
| 792 |
+
{ url = "https://files.pythonhosted.org/packages/8d/6a/1552b70fb0d9ab074fd3fc961435d01364e79c9058481822c3af6e8d402c/tokenizers-0.23.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:eb2f9c8a24da020ea8c11a01a19c1c2547912d92121ae4a01cfbca46125dee40", size = 9967367, upload-time = "2026-09-03T08:55:33.188Z" },
|
| 793 |
+
{ url = "https://files.pythonhosted.org/packages/06/01/3ccb3a956c7528b2507b8a9714155c4baf86af593039db6ea375dd0c96c3/tokenizers-0.23.2-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f486f402f6f9abee5bb032553736813af0c710a86b2e0ca592634c55cea1f835", size = 9811886, upload-time = "2026-09-03T08:55:35.642Z" },
|
| 794 |
+
{ url = "https://files.pythonhosted.org/packages/fa/73/7038e612d48bda1599457f712f6bd3854eae1a9dc9c13aa47f835349db48/tokenizers-0.23.2-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:bef235815a067b2648caf6dcc7a71091b0b0fff9ee8057f6451eb9335fae52ef", size = 10146224, upload-time = "2026-09-03T08:55:38.391Z" },
|
| 795 |
+
{ url = "https://files.pythonhosted.org/packages/b5/d8/8e9e4e0b287a338d8f88976729628c9d22e8a54cfaf9777018a7f7cb58a0/tokenizers-0.23.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5c56bda1511921587789163e524d196ed8284174ac23abd7685d5ea8da6c4718", size = 10256304, upload-time = "2026-09-03T08:55:40.977Z" },
|
| 796 |
+
{ url = "https://files.pythonhosted.org/packages/f3/1f/c79a01f671a49728ebb0b61f7ff9ea45663b66cab40bc0858e9859b25c16/tokenizers-0.23.2-cp310-abi3-win32.whl", hash = "sha256:debf978920d93ba9c219bd67cc4bbfaf912c9039e41e7a28b91ec15e3728c95a", size = 2592809, upload-time = "2026-09-03T08:55:48.02Z" },
|
| 797 |
+
{ url = "https://files.pythonhosted.org/packages/db/f7/0a69ac6b82dbccf3f71add938a161c497952749294b8dd6dfe03a819dc40/tokenizers-0.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:2e96f5699d5249c9c64aa8412e044f727aae3a4098cf830f9901ec1afc361cde", size = 2863236, upload-time = "2026-09-03T08:55:46.193Z" },
|
| 798 |
+
{ url = "https://files.pythonhosted.org/packages/d7/b0/dee84cb44175be1b4c35bd2f770727494e78f0bb38e571a623ade94dbebb/tokenizers-0.23.2-cp310-abi3-win_arm64.whl", hash = "sha256:e49c394456dd9985787fec76132438ba3fb8911f857b1bf3d40119f9292d41aa", size = 2729352, upload-time = "2026-09-03T08:55:44.345Z" },
|
| 799 |
+
]
|
| 800 |
+
|
| 801 |
+
[[package]]
|
| 802 |
+
name = "torch"
|
| 803 |
+
version = "2.8.0"
|
| 804 |
+
source = { registry = "https://pypi.org/simple" }
|
| 805 |
+
dependencies = [
|
| 806 |
+
{ name = "filelock" },
|
| 807 |
+
{ name = "fsspec" },
|
| 808 |
+
{ name = "jinja2" },
|
| 809 |
+
{ name = "networkx" },
|
| 810 |
+
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 811 |
+
{ name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 812 |
+
{ name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 813 |
+
{ name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 814 |
+
{ name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 815 |
+
{ name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 816 |
+
{ name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 817 |
+
{ name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 818 |
+
{ name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 819 |
+
{ name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 820 |
+
{ name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 821 |
+
{ name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 822 |
+
{ name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 823 |
+
{ name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 824 |
+
{ name = "setuptools" },
|
| 825 |
+
{ name = "sympy" },
|
| 826 |
+
{ name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 827 |
+
{ name = "typing-extensions" },
|
| 828 |
+
]
|
| 829 |
+
wheels = [
|
| 830 |
+
{ url = "https://files.pythonhosted.org/packages/49/0c/2fd4df0d83a495bb5e54dca4474c4ec5f9c62db185421563deeb5dabf609/torch-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2fab4153768d433f8ed9279c8133a114a034a61e77a3a104dcdf54388838705", size = 101906089, upload-time = "2025-08-06T14:53:52.631Z" },
|
| 831 |
+
{ url = "https://files.pythonhosted.org/packages/99/a8/6acf48d48838fb8fe480597d98a0668c2beb02ee4755cc136de92a0a956f/torch-2.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2aca0939fb7e4d842561febbd4ffda67a8e958ff725c1c27e244e85e982173c", size = 887913624, upload-time = "2025-08-06T14:56:44.33Z" },
|
| 832 |
+
{ url = "https://files.pythonhosted.org/packages/af/8a/5c87f08e3abd825c7dfecef5a0f1d9aa5df5dd0e3fd1fa2f490a8e512402/torch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f4ac52f0130275d7517b03a33d2493bab3693c83dcfadf4f81688ea82147d2e", size = 241326087, upload-time = "2025-08-06T14:53:46.503Z" },
|
| 833 |
+
{ url = "https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0", size = 73630478, upload-time = "2025-08-06T14:53:57.144Z" },
|
| 834 |
+
]
|
| 835 |
+
|
| 836 |
+
[[package]]
|
| 837 |
+
name = "tqdm"
|
| 838 |
+
version = "4.70.1"
|
| 839 |
+
source = { registry = "https://pypi.org/simple" }
|
| 840 |
+
dependencies = [
|
| 841 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 842 |
+
]
|
| 843 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0d/ea/b2a5bd54b28a324dae8211928b2d730b6547500342c7e6c6dea08bd0a485/tqdm-4.70.1.tar.gz", hash = "sha256:cefd0eca11b2a37a3aee776544d4f4ae913f02688135b5556b8788dfa474afc4", size = 171846, upload-time = "2026-09-11T07:25:16.601Z" }
|
| 844 |
+
wheels = [
|
| 845 |
+
{ url = "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl", hash = "sha256:c293e525e6fef9c20e8728fd4612df02a0aa31bb5fe91ecd93e123b1b7bffa73", size = 80199, upload-time = "2026-09-11T07:25:14.599Z" },
|
| 846 |
+
]
|
| 847 |
+
|
| 848 |
+
[[package]]
|
| 849 |
+
name = "transformers"
|
| 850 |
+
version = "5.17.0"
|
| 851 |
+
source = { git = "https://github.com/huggingface/transformers.git?rev=856157a2f3e9594954310df18fdccc31ffddebe9#856157a2f3e9594954310df18fdccc31ffddebe9" }
|
| 852 |
+
dependencies = [
|
| 853 |
+
{ name = "huggingface-hub" },
|
| 854 |
+
{ name = "numpy" },
|
| 855 |
+
{ name = "packaging" },
|
| 856 |
+
{ name = "pyyaml" },
|
| 857 |
+
{ name = "regex" },
|
| 858 |
+
{ name = "safetensors" },
|
| 859 |
+
{ name = "tokenizers" },
|
| 860 |
+
{ name = "tqdm" },
|
| 861 |
+
{ name = "typer" },
|
| 862 |
+
]
|
| 863 |
+
|
| 864 |
+
[[package]]
|
| 865 |
+
name = "triton"
|
| 866 |
+
version = "3.4.0"
|
| 867 |
+
source = { registry = "https://pypi.org/simple" }
|
| 868 |
+
dependencies = [
|
| 869 |
+
{ name = "setuptools" },
|
| 870 |
+
]
|
| 871 |
+
wheels = [
|
| 872 |
+
{ url = "https://files.pythonhosted.org/packages/d0/66/b1eb52839f563623d185f0927eb3530ee4d5ffe9d377cdaf5346b306689e/triton-3.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c1d84a5c0ec2c0f8e8a072d7fd150cab84a9c239eaddc6706c081bfae4eb04", size = 155560068, upload-time = "2025-07-30T19:58:37.081Z" },
|
| 873 |
+
]
|
| 874 |
+
|
| 875 |
+
[[package]]
|
| 876 |
+
name = "typer"
|
| 877 |
+
version = "0.27.2"
|
| 878 |
+
source = { registry = "https://pypi.org/simple" }
|
| 879 |
+
dependencies = [
|
| 880 |
+
{ name = "annotated-doc" },
|
| 881 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 882 |
+
{ name = "rich" },
|
| 883 |
+
{ name = "shellingham" },
|
| 884 |
+
]
|
| 885 |
+
sdist = { url = "https://files.pythonhosted.org/packages/16/f7/57713ba479fd405eb76de31404b2c744c289e336b2d999511ebf51e496f7/typer-0.27.2.tar.gz", hash = "sha256:269b7eb9d3c202ca84b4bc9618cb04ebb43d3d4d1e567e4c768607232c05f945", size = 204045, upload-time = "2026-08-28T10:26:55.046Z" }
|
| 886 |
+
wheels = [
|
| 887 |
+
{ url = "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl", hash = "sha256:b3a5fc4342d5fc8fda8fc3010b1cf117e9249aab7fae800c2eff62fd3842d97d", size = 123130, upload-time = "2026-08-28T10:26:53.752Z" },
|
| 888 |
+
]
|
| 889 |
+
|
| 890 |
+
[[package]]
|
| 891 |
+
name = "typing-extensions"
|
| 892 |
+
version = "4.16.0"
|
| 893 |
+
source = { registry = "https://pypi.org/simple" }
|
| 894 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
|
| 895 |
+
wheels = [
|
| 896 |
+
{ url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
|
| 897 |
+
]
|
| 898 |
+
|
| 899 |
+
[[package]]
|
| 900 |
+
name = "typing-inspection"
|
| 901 |
+
version = "0.4.4"
|
| 902 |
+
source = { registry = "https://pypi.org/simple" }
|
| 903 |
+
dependencies = [
|
| 904 |
+
{ name = "typing-extensions" },
|
| 905 |
+
]
|
| 906 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", size = 76928, upload-time = "2026-08-12T12:37:25.997Z" }
|
| 907 |
+
wheels = [
|
| 908 |
+
{ url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", size = 14750, upload-time = "2026-08-12T12:37:24.648Z" },
|
| 909 |
+
]
|
validation-report.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format_version": 1,
|
| 3 |
+
"lengths_above_65536": "structural validation only",
|
| 4 |
+
"numerical_parity_certified_through_tokens": 65536,
|
| 5 |
+
"source_revision": "f3709948b5e3cc9606a57e74ba62b7a639d17dd3",
|
| 6 |
+
"stages": {
|
| 7 |
+
"client_compatibility": {
|
| 8 |
+
"command": [
|
| 9 |
+
"/Users/imtk/Desktop/OpenThaiONNX-Codex/.venv/bin/python3",
|
| 10 |
+
"-m",
|
| 11 |
+
"pytest",
|
| 12 |
+
"-q",
|
| 13 |
+
"tests/test_client_contract.py",
|
| 14 |
+
"tests/test_export_builder.py",
|
| 15 |
+
"tests/test_validation.py",
|
| 16 |
+
"--junitxml=/Users/imtk/Desktop/OpenThaiONNX-Codex/artifacts/OpenThai-SystemOne-ONNX/.client_compatibility.junit.xml"
|
| 17 |
+
],
|
| 18 |
+
"completed_at": "2026-09-25T07:17:29.243609+00:00",
|
| 19 |
+
"failure_hint": null,
|
| 20 |
+
"passed": true,
|
| 21 |
+
"returncode": 0,
|
| 22 |
+
"test_counts": {
|
| 23 |
+
"errors": 0,
|
| 24 |
+
"failures": 0,
|
| 25 |
+
"skipped": 0,
|
| 26 |
+
"tests": 16
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
"normal_parity": {
|
| 30 |
+
"command": [
|
| 31 |
+
"/Users/imtk/Desktop/OpenThaiONNX-Codex/.venv/bin/python3",
|
| 32 |
+
"-m",
|
| 33 |
+
"pytest",
|
| 34 |
+
"-q",
|
| 35 |
+
"tests/test_parity.py",
|
| 36 |
+
"-m",
|
| 37 |
+
"parity and not slow",
|
| 38 |
+
"--junitxml=/Users/imtk/Desktop/OpenThaiONNX-Codex/artifacts/OpenThai-SystemOne-ONNX/.normal_parity.junit.xml"
|
| 39 |
+
],
|
| 40 |
+
"completed_at": "2026-09-25T07:19:30.694251+00:00",
|
| 41 |
+
"failure_hint": null,
|
| 42 |
+
"passed": true,
|
| 43 |
+
"returncode": 0,
|
| 44 |
+
"test_counts": {
|
| 45 |
+
"errors": 0,
|
| 46 |
+
"failures": 0,
|
| 47 |
+
"skipped": 0,
|
| 48 |
+
"tests": 9
|
| 49 |
+
}
|
| 50 |
+
},
|
| 51 |
+
"slow_65536_parity": {
|
| 52 |
+
"command": [
|
| 53 |
+
"/Users/imtk/Desktop/OpenThaiONNX-Codex/.venv/bin/python3",
|
| 54 |
+
"-m",
|
| 55 |
+
"pytest",
|
| 56 |
+
"-q",
|
| 57 |
+
"tests/test_parity.py",
|
| 58 |
+
"-m",
|
| 59 |
+
"slow",
|
| 60 |
+
"--junitxml=/Users/imtk/Desktop/OpenThaiONNX-Codex/artifacts/OpenThai-SystemOne-ONNX/.slow_65536_parity.junit.xml"
|
| 61 |
+
],
|
| 62 |
+
"completed_at": "2026-09-25T07:59:48.172858+00:00",
|
| 63 |
+
"failure_hint": null,
|
| 64 |
+
"passed": true,
|
| 65 |
+
"returncode": 0,
|
| 66 |
+
"test_counts": {
|
| 67 |
+
"errors": 0,
|
| 68 |
+
"failures": 0,
|
| 69 |
+
"skipped": 0,
|
| 70 |
+
"tests": 1
|
| 71 |
+
}
|
| 72 |
+
},
|
| 73 |
+
"structural_262144": {
|
| 74 |
+
"command": [
|
| 75 |
+
"/Users/imtk/Desktop/OpenThaiONNX-Codex/.venv/bin/python3",
|
| 76 |
+
"-m",
|
| 77 |
+
"pytest",
|
| 78 |
+
"-q",
|
| 79 |
+
"tests/test_structure.py",
|
| 80 |
+
"--junitxml=/Users/imtk/Desktop/OpenThaiONNX-Codex/artifacts/OpenThai-SystemOne-ONNX/.structural_262144.junit.xml"
|
| 81 |
+
],
|
| 82 |
+
"completed_at": "2026-09-25T07:19:46.848105+00:00",
|
| 83 |
+
"failure_hint": null,
|
| 84 |
+
"passed": true,
|
| 85 |
+
"returncode": 0,
|
| 86 |
+
"test_counts": {
|
| 87 |
+
"errors": 0,
|
| 88 |
+
"failures": 0,
|
| 89 |
+
"skipped": 0,
|
| 90 |
+
"tests": 3
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
},
|
| 94 |
+
"upload_gate": {
|
| 95 |
+
"passed": true,
|
| 96 |
+
"required_stages": [
|
| 97 |
+
"client_compatibility",
|
| 98 |
+
"normal_parity",
|
| 99 |
+
"slow_65536_parity",
|
| 100 |
+
"structural_262144"
|
| 101 |
+
]
|
| 102 |
+
}
|
| 103 |
+
}
|