@sohqureshi/tokenwise 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/{chunk-ZVQRYJU5.js → chunk-IOMOVRC7.js} +22 -6
- package/dist/{chunk-HFMW3K22.js → chunk-P6KXISNT.js} +3 -3
- package/dist/chunk-U433WUUT.js +55 -0
- package/dist/cli.cjs +61 -7
- package/dist/cli.js +3 -3
- package/dist/core/analyze.cjs +59 -5
- package/dist/core/analyze.d.cts +3 -0
- package/dist/core/analyze.d.ts +3 -0
- package/dist/core/analyze.js +2 -2
- package/dist/core/token.cjs +44 -1
- package/dist/core/token.d.cts +18 -12
- package/dist/core/token.d.ts +18 -12
- package/dist/core/token.js +3 -1
- package/dist/index.cjs +64 -7
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/package.json +4 -1
- package/dist/chunk-7CL7GVRF.js +0 -14
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
TokenWise is a lightweight utility for preparing JSON before sending it to AI models. It helps reduce payload noise, shrink token usage, and turn structured data into formats that are easier for LLMs to consume.
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-

|
|
7
|
-

|
|
6
|
+
[](https://www.npmjs.com/package/@sohqureshi/tokenwise)
|
|
7
|
+
[](https://www.npmjs.com/package/@sohqureshi/tokenwise)
|
|
8
8
|

|
|
9
9
|

|
|
10
10
|
[](https://sohqureshi.github.io/tokenwise/)
|
|
@@ -36,6 +36,8 @@ Raw JSON is:
|
|
|
36
36
|
npm install @sohqureshi/tokenwise
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
Available on [npm](https://www.npmjs.com/package/@sohqureshi/tokenwise).
|
|
40
|
+
|
|
39
41
|
## Quick Usage
|
|
40
42
|
|
|
41
43
|
```js
|
|
@@ -68,7 +70,7 @@ console.log(ai(product).compact().value());
|
|
|
68
70
|
Removes fields you do not want to send to the model. By default it also removes `null`, `undefined`, and empty objects.
|
|
69
71
|
|
|
70
72
|
```js
|
|
71
|
-
import { prune } from "tokenwise";
|
|
73
|
+
import { prune } from "@sohqureshi/tokenwise";
|
|
72
74
|
|
|
73
75
|
const input = {
|
|
74
76
|
user: { name: "John", age: 28 },
|
|
@@ -209,8 +211,9 @@ node demo.js
|
|
|
209
211
|
```
|
|
210
212
|
|
|
211
213
|
Use `--analyze` to compare serialized input and output with TokenWise's
|
|
212
|
-
four-characters-per-token heuristic.
|
|
213
|
-
|
|
214
|
+
four-characters-per-token heuristic. For model-accurate counts, pass
|
|
215
|
+
`exact: true` and a `model` name to `estimateTokens()` or `analyze()`.
|
|
216
|
+
This is still only as exact as the tokenizer implementation you use.
|
|
214
217
|
|
|
215
218
|
---
|
|
216
219
|
|
|
@@ -11,12 +11,17 @@ import {
|
|
|
11
11
|
prune
|
|
12
12
|
} from "./chunk-ZD536GZF.js";
|
|
13
13
|
import {
|
|
14
|
-
|
|
14
|
+
estimateTokensWithMeta,
|
|
15
15
|
serializeForTokenEstimate
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-U433WUUT.js";
|
|
17
17
|
|
|
18
18
|
// src/core/analyze.ts
|
|
19
19
|
function analyze(input, options = {}) {
|
|
20
|
+
const {
|
|
21
|
+
exact = false,
|
|
22
|
+
model = "gpt-4o-mini",
|
|
23
|
+
fallbackToHeuristic = true
|
|
24
|
+
} = options;
|
|
20
25
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
21
26
|
return {
|
|
22
27
|
originalTokens: 0,
|
|
@@ -27,10 +32,15 @@ function analyze(input, options = {}) {
|
|
|
27
32
|
reductionRatio: 1,
|
|
28
33
|
originalCharacters: 0,
|
|
29
34
|
optimizedCharacters: 0,
|
|
30
|
-
estimator: "heuristic: 1 token \u2248 4 characters"
|
|
35
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
|
-
const
|
|
38
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
39
|
+
exact,
|
|
40
|
+
model,
|
|
41
|
+
fallbackToHeuristic
|
|
42
|
+
});
|
|
43
|
+
const originalTokens = originalMeta.count;
|
|
34
44
|
let optimizedData = input;
|
|
35
45
|
if (options.prune && Array.isArray(options.prune)) {
|
|
36
46
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -44,10 +54,16 @@ function analyze(input, options = {}) {
|
|
|
44
54
|
if (options.toTOON === true || options.toon === true) {
|
|
45
55
|
optimizedData = toTOON(optimizedData);
|
|
46
56
|
}
|
|
47
|
-
const
|
|
57
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
58
|
+
exact,
|
|
59
|
+
model,
|
|
60
|
+
fallbackToHeuristic
|
|
61
|
+
});
|
|
62
|
+
const optimizedTokens = optimizedMeta.count;
|
|
48
63
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
49
64
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
50
65
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
66
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
51
67
|
return {
|
|
52
68
|
originalTokens,
|
|
53
69
|
optimizedTokens,
|
|
@@ -57,7 +73,7 @@ function analyze(input, options = {}) {
|
|
|
57
73
|
reductionRatio,
|
|
58
74
|
originalCharacters: serializeForTokenEstimate(input).length,
|
|
59
75
|
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
60
|
-
estimator:
|
|
76
|
+
estimator: estimatorLabel
|
|
61
77
|
};
|
|
62
78
|
}
|
|
63
79
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyze
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IOMOVRC7.js";
|
|
4
4
|
import {
|
|
5
5
|
toTOON
|
|
6
6
|
} from "./chunk-6VRLDRJK.js";
|
|
@@ -41,8 +41,8 @@ var AIChain = class {
|
|
|
41
41
|
toNatural() {
|
|
42
42
|
return toNatural(this.data);
|
|
43
43
|
}
|
|
44
|
-
analyze() {
|
|
45
|
-
return analyze(this.data);
|
|
44
|
+
analyze(options) {
|
|
45
|
+
return analyze(this.data, options);
|
|
46
46
|
}
|
|
47
47
|
value() {
|
|
48
48
|
return this.data;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/core/token.ts
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
var require2 = createRequire(import.meta.url);
|
|
4
|
+
function serializeForTokenEstimate(value) {
|
|
5
|
+
if (typeof value === "string") return value;
|
|
6
|
+
const serialized = JSON.stringify(value);
|
|
7
|
+
return serialized ?? "";
|
|
8
|
+
}
|
|
9
|
+
function estimateTokensHeuristic(value) {
|
|
10
|
+
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
11
|
+
}
|
|
12
|
+
function estimateTokens(value, options = {}) {
|
|
13
|
+
return estimateTokensWithMeta(value, options).count;
|
|
14
|
+
}
|
|
15
|
+
function estimateTokensWithMeta(value, options = {}) {
|
|
16
|
+
const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
|
|
17
|
+
const heuristic = estimateTokensHeuristic(value);
|
|
18
|
+
const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
|
|
19
|
+
if (!exact) {
|
|
20
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const tiktoken = require2("tiktoken");
|
|
24
|
+
const encoder = tiktoken.encoding_for_model(model);
|
|
25
|
+
const text = serializeForTokenEstimate(value);
|
|
26
|
+
const count = encoder.encode(text).length;
|
|
27
|
+
let encodingName = null;
|
|
28
|
+
if (encoder.name) encodingName = encoder.name;
|
|
29
|
+
if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
|
|
30
|
+
try {
|
|
31
|
+
encodingName = tiktoken.model_to_encoding(model);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
encodingName = null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (!encodingName) {
|
|
37
|
+
const m = String(model || "").toLowerCase();
|
|
38
|
+
if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
|
|
39
|
+
else encodingName = "cl100k_base";
|
|
40
|
+
}
|
|
41
|
+
const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
|
|
42
|
+
return { count, estimator };
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (!fallbackToHeuristic) {
|
|
45
|
+
return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
|
|
46
|
+
}
|
|
47
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
serializeForTokenEstimate,
|
|
53
|
+
estimateTokens,
|
|
54
|
+
estimateTokensWithMeta
|
|
55
|
+
};
|
package/dist/cli.cjs
CHANGED
|
@@ -142,17 +142,60 @@ function isPlainObject(value) {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// src/core/token.ts
|
|
145
|
+
var import_node_module = require("module");
|
|
146
|
+
var import_meta = {};
|
|
147
|
+
var require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
145
148
|
function serializeForTokenEstimate(value) {
|
|
146
149
|
if (typeof value === "string") return value;
|
|
147
150
|
const serialized = JSON.stringify(value);
|
|
148
151
|
return serialized ?? "";
|
|
149
152
|
}
|
|
150
|
-
function
|
|
153
|
+
function estimateTokensHeuristic(value) {
|
|
151
154
|
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
152
155
|
}
|
|
156
|
+
function estimateTokensWithMeta(value, options = {}) {
|
|
157
|
+
const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
|
|
158
|
+
const heuristic = estimateTokensHeuristic(value);
|
|
159
|
+
const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
|
|
160
|
+
if (!exact) {
|
|
161
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const tiktoken = require2("tiktoken");
|
|
165
|
+
const encoder = tiktoken.encoding_for_model(model);
|
|
166
|
+
const text = serializeForTokenEstimate(value);
|
|
167
|
+
const count = encoder.encode(text).length;
|
|
168
|
+
let encodingName = null;
|
|
169
|
+
if (encoder.name) encodingName = encoder.name;
|
|
170
|
+
if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
|
|
171
|
+
try {
|
|
172
|
+
encodingName = tiktoken.model_to_encoding(model);
|
|
173
|
+
} catch (e) {
|
|
174
|
+
encodingName = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!encodingName) {
|
|
178
|
+
const m = String(model || "").toLowerCase();
|
|
179
|
+
if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
|
|
180
|
+
else encodingName = "cl100k_base";
|
|
181
|
+
}
|
|
182
|
+
const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
|
|
183
|
+
return { count, estimator };
|
|
184
|
+
} catch (e) {
|
|
185
|
+
if (!fallbackToHeuristic) {
|
|
186
|
+
return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
|
|
187
|
+
}
|
|
188
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
153
191
|
|
|
154
192
|
// src/core/analyze.ts
|
|
155
193
|
function analyze(input, options = {}) {
|
|
194
|
+
const {
|
|
195
|
+
exact = false,
|
|
196
|
+
model = "gpt-4o-mini",
|
|
197
|
+
fallbackToHeuristic = true
|
|
198
|
+
} = options;
|
|
156
199
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
157
200
|
return {
|
|
158
201
|
originalTokens: 0,
|
|
@@ -163,10 +206,15 @@ function analyze(input, options = {}) {
|
|
|
163
206
|
reductionRatio: 1,
|
|
164
207
|
originalCharacters: 0,
|
|
165
208
|
optimizedCharacters: 0,
|
|
166
|
-
estimator: "heuristic: 1 token \u2248 4 characters"
|
|
209
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
167
210
|
};
|
|
168
211
|
}
|
|
169
|
-
const
|
|
212
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
213
|
+
exact,
|
|
214
|
+
model,
|
|
215
|
+
fallbackToHeuristic
|
|
216
|
+
});
|
|
217
|
+
const originalTokens = originalMeta.count;
|
|
170
218
|
let optimizedData = input;
|
|
171
219
|
if (options.prune && Array.isArray(options.prune)) {
|
|
172
220
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -180,10 +228,16 @@ function analyze(input, options = {}) {
|
|
|
180
228
|
if (options.toTOON === true || options.toon === true) {
|
|
181
229
|
optimizedData = toTOON(optimizedData);
|
|
182
230
|
}
|
|
183
|
-
const
|
|
231
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
232
|
+
exact,
|
|
233
|
+
model,
|
|
234
|
+
fallbackToHeuristic
|
|
235
|
+
});
|
|
236
|
+
const optimizedTokens = optimizedMeta.count;
|
|
184
237
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
185
238
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
186
239
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
240
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
187
241
|
return {
|
|
188
242
|
originalTokens,
|
|
189
243
|
optimizedTokens,
|
|
@@ -193,7 +247,7 @@ function analyze(input, options = {}) {
|
|
|
193
247
|
reductionRatio,
|
|
194
248
|
originalCharacters: serializeForTokenEstimate(input).length,
|
|
195
249
|
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
196
|
-
estimator:
|
|
250
|
+
estimator: estimatorLabel
|
|
197
251
|
};
|
|
198
252
|
}
|
|
199
253
|
|
|
@@ -323,8 +377,8 @@ var AIChain = class {
|
|
|
323
377
|
toNatural() {
|
|
324
378
|
return toNatural(this.data);
|
|
325
379
|
}
|
|
326
|
-
analyze() {
|
|
327
|
-
return analyze(this.data);
|
|
380
|
+
analyze(options) {
|
|
381
|
+
return analyze(this.data, options);
|
|
328
382
|
}
|
|
329
383
|
value() {
|
|
330
384
|
return this.data;
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
AIChain
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-P6KXISNT.js";
|
|
5
|
+
import "./chunk-IOMOVRC7.js";
|
|
6
6
|
import "./chunk-6VRLDRJK.js";
|
|
7
7
|
import "./chunk-XE36GLJP.js";
|
|
8
8
|
import "./chunk-L7BC62MT.js";
|
|
9
9
|
import "./chunk-D4CFTFM3.js";
|
|
10
10
|
import "./chunk-ZD536GZF.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-U433WUUT.js";
|
|
12
12
|
|
|
13
13
|
// src/cli.ts
|
|
14
14
|
import fs from "fs";
|
package/dist/core/analyze.cjs
CHANGED
|
@@ -139,17 +139,60 @@ function isPlainObject(value) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// src/core/token.ts
|
|
142
|
+
var import_node_module = require("module");
|
|
143
|
+
var import_meta = {};
|
|
144
|
+
var require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
142
145
|
function serializeForTokenEstimate(value) {
|
|
143
146
|
if (typeof value === "string") return value;
|
|
144
147
|
const serialized = JSON.stringify(value);
|
|
145
148
|
return serialized ?? "";
|
|
146
149
|
}
|
|
147
|
-
function
|
|
150
|
+
function estimateTokensHeuristic(value) {
|
|
148
151
|
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
149
152
|
}
|
|
153
|
+
function estimateTokensWithMeta(value, options = {}) {
|
|
154
|
+
const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
|
|
155
|
+
const heuristic = estimateTokensHeuristic(value);
|
|
156
|
+
const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
|
|
157
|
+
if (!exact) {
|
|
158
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const tiktoken = require2("tiktoken");
|
|
162
|
+
const encoder = tiktoken.encoding_for_model(model);
|
|
163
|
+
const text = serializeForTokenEstimate(value);
|
|
164
|
+
const count = encoder.encode(text).length;
|
|
165
|
+
let encodingName = null;
|
|
166
|
+
if (encoder.name) encodingName = encoder.name;
|
|
167
|
+
if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
|
|
168
|
+
try {
|
|
169
|
+
encodingName = tiktoken.model_to_encoding(model);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
encodingName = null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!encodingName) {
|
|
175
|
+
const m = String(model || "").toLowerCase();
|
|
176
|
+
if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
|
|
177
|
+
else encodingName = "cl100k_base";
|
|
178
|
+
}
|
|
179
|
+
const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
|
|
180
|
+
return { count, estimator };
|
|
181
|
+
} catch (e) {
|
|
182
|
+
if (!fallbackToHeuristic) {
|
|
183
|
+
return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
|
|
184
|
+
}
|
|
185
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
150
188
|
|
|
151
189
|
// src/core/analyze.ts
|
|
152
190
|
function analyze(input, options = {}) {
|
|
191
|
+
const {
|
|
192
|
+
exact = false,
|
|
193
|
+
model = "gpt-4o-mini",
|
|
194
|
+
fallbackToHeuristic = true
|
|
195
|
+
} = options;
|
|
153
196
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
154
197
|
return {
|
|
155
198
|
originalTokens: 0,
|
|
@@ -160,10 +203,15 @@ function analyze(input, options = {}) {
|
|
|
160
203
|
reductionRatio: 1,
|
|
161
204
|
originalCharacters: 0,
|
|
162
205
|
optimizedCharacters: 0,
|
|
163
|
-
estimator: "heuristic: 1 token \u2248 4 characters"
|
|
206
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
164
207
|
};
|
|
165
208
|
}
|
|
166
|
-
const
|
|
209
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
210
|
+
exact,
|
|
211
|
+
model,
|
|
212
|
+
fallbackToHeuristic
|
|
213
|
+
});
|
|
214
|
+
const originalTokens = originalMeta.count;
|
|
167
215
|
let optimizedData = input;
|
|
168
216
|
if (options.prune && Array.isArray(options.prune)) {
|
|
169
217
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -177,10 +225,16 @@ function analyze(input, options = {}) {
|
|
|
177
225
|
if (options.toTOON === true || options.toon === true) {
|
|
178
226
|
optimizedData = toTOON(optimizedData);
|
|
179
227
|
}
|
|
180
|
-
const
|
|
228
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
229
|
+
exact,
|
|
230
|
+
model,
|
|
231
|
+
fallbackToHeuristic
|
|
232
|
+
});
|
|
233
|
+
const optimizedTokens = optimizedMeta.count;
|
|
181
234
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
182
235
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
183
236
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
237
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
184
238
|
return {
|
|
185
239
|
originalTokens,
|
|
186
240
|
optimizedTokens,
|
|
@@ -190,7 +244,7 @@ function analyze(input, options = {}) {
|
|
|
190
244
|
reductionRatio,
|
|
191
245
|
originalCharacters: serializeForTokenEstimate(input).length,
|
|
192
246
|
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
193
|
-
estimator:
|
|
247
|
+
estimator: estimatorLabel
|
|
194
248
|
};
|
|
195
249
|
}
|
|
196
250
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/core/analyze.d.cts
CHANGED
package/dist/core/analyze.d.ts
CHANGED
package/dist/core/analyze.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyze
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-IOMOVRC7.js";
|
|
4
4
|
import "../chunk-6VRLDRJK.js";
|
|
5
5
|
import "../chunk-XE36GLJP.js";
|
|
6
6
|
import "../chunk-L7BC62MT.js";
|
|
7
7
|
import "../chunk-ZD536GZF.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-U433WUUT.js";
|
|
9
9
|
export {
|
|
10
10
|
analyze
|
|
11
11
|
};
|
package/dist/core/token.cjs
CHANGED
|
@@ -21,19 +21,62 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var token_exports = {};
|
|
22
22
|
__export(token_exports, {
|
|
23
23
|
estimateTokens: () => estimateTokens,
|
|
24
|
+
estimateTokensWithMeta: () => estimateTokensWithMeta,
|
|
24
25
|
serializeForTokenEstimate: () => serializeForTokenEstimate
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(token_exports);
|
|
28
|
+
var import_node_module = require("module");
|
|
29
|
+
var import_meta = {};
|
|
30
|
+
var require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
27
31
|
function serializeForTokenEstimate(value) {
|
|
28
32
|
if (typeof value === "string") return value;
|
|
29
33
|
const serialized = JSON.stringify(value);
|
|
30
34
|
return serialized ?? "";
|
|
31
35
|
}
|
|
32
|
-
function
|
|
36
|
+
function estimateTokensHeuristic(value) {
|
|
33
37
|
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
34
38
|
}
|
|
39
|
+
function estimateTokens(value, options = {}) {
|
|
40
|
+
return estimateTokensWithMeta(value, options).count;
|
|
41
|
+
}
|
|
42
|
+
function estimateTokensWithMeta(value, options = {}) {
|
|
43
|
+
const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
|
|
44
|
+
const heuristic = estimateTokensHeuristic(value);
|
|
45
|
+
const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
|
|
46
|
+
if (!exact) {
|
|
47
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const tiktoken = require2("tiktoken");
|
|
51
|
+
const encoder = tiktoken.encoding_for_model(model);
|
|
52
|
+
const text = serializeForTokenEstimate(value);
|
|
53
|
+
const count = encoder.encode(text).length;
|
|
54
|
+
let encodingName = null;
|
|
55
|
+
if (encoder.name) encodingName = encoder.name;
|
|
56
|
+
if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
|
|
57
|
+
try {
|
|
58
|
+
encodingName = tiktoken.model_to_encoding(model);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
encodingName = null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!encodingName) {
|
|
64
|
+
const m = String(model || "").toLowerCase();
|
|
65
|
+
if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
|
|
66
|
+
else encodingName = "cl100k_base";
|
|
67
|
+
}
|
|
68
|
+
const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
|
|
69
|
+
return { count, estimator };
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (!fallbackToHeuristic) {
|
|
72
|
+
return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
|
|
73
|
+
}
|
|
74
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
35
77
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36
78
|
0 && (module.exports = {
|
|
37
79
|
estimateTokens,
|
|
80
|
+
estimateTokensWithMeta,
|
|
38
81
|
serializeForTokenEstimate
|
|
39
82
|
});
|
package/dist/core/token.d.cts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* @param text - Input string
|
|
8
|
-
* @returns Estimated token count
|
|
9
|
-
*/
|
|
1
|
+
interface TokenEstimateOptions {
|
|
2
|
+
exact?: boolean;
|
|
3
|
+
model?: string;
|
|
4
|
+
fallbackToHeuristic?: boolean;
|
|
5
|
+
}
|
|
10
6
|
declare function serializeForTokenEstimate(value: unknown): string;
|
|
11
7
|
/**
|
|
12
8
|
* Estimates tokens using a transparent four-characters-per-token heuristic.
|
|
13
9
|
* JSON values are serialized first, matching the compact form normally sent
|
|
14
|
-
* to an API.
|
|
10
|
+
* to an API. Set exact=true to attempt a model-specific tokenizer count when
|
|
11
|
+
* the runtime has the tokenizer installed.
|
|
12
|
+
*/
|
|
13
|
+
type TokenEstimateResult = {
|
|
14
|
+
count: number;
|
|
15
|
+
estimator: string;
|
|
16
|
+
};
|
|
17
|
+
declare function estimateTokens(value: unknown, options?: TokenEstimateOptions): number;
|
|
18
|
+
/**
|
|
19
|
+
* Returns both a token count and an estimator string describing how the count was
|
|
20
|
+
* obtained (exact tokenizer + encoding when available, or heuristic otherwise).
|
|
15
21
|
*/
|
|
16
|
-
declare function
|
|
22
|
+
declare function estimateTokensWithMeta(value: unknown, options?: TokenEstimateOptions): TokenEstimateResult;
|
|
17
23
|
|
|
18
|
-
export { estimateTokens, serializeForTokenEstimate };
|
|
24
|
+
export { type TokenEstimateOptions, type TokenEstimateResult, estimateTokens, estimateTokensWithMeta, serializeForTokenEstimate };
|
package/dist/core/token.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* @param text - Input string
|
|
8
|
-
* @returns Estimated token count
|
|
9
|
-
*/
|
|
1
|
+
interface TokenEstimateOptions {
|
|
2
|
+
exact?: boolean;
|
|
3
|
+
model?: string;
|
|
4
|
+
fallbackToHeuristic?: boolean;
|
|
5
|
+
}
|
|
10
6
|
declare function serializeForTokenEstimate(value: unknown): string;
|
|
11
7
|
/**
|
|
12
8
|
* Estimates tokens using a transparent four-characters-per-token heuristic.
|
|
13
9
|
* JSON values are serialized first, matching the compact form normally sent
|
|
14
|
-
* to an API.
|
|
10
|
+
* to an API. Set exact=true to attempt a model-specific tokenizer count when
|
|
11
|
+
* the runtime has the tokenizer installed.
|
|
12
|
+
*/
|
|
13
|
+
type TokenEstimateResult = {
|
|
14
|
+
count: number;
|
|
15
|
+
estimator: string;
|
|
16
|
+
};
|
|
17
|
+
declare function estimateTokens(value: unknown, options?: TokenEstimateOptions): number;
|
|
18
|
+
/**
|
|
19
|
+
* Returns both a token count and an estimator string describing how the count was
|
|
20
|
+
* obtained (exact tokenizer + encoding when available, or heuristic otherwise).
|
|
15
21
|
*/
|
|
16
|
-
declare function
|
|
22
|
+
declare function estimateTokensWithMeta(value: unknown, options?: TokenEstimateOptions): TokenEstimateResult;
|
|
17
23
|
|
|
18
|
-
export { estimateTokens, serializeForTokenEstimate };
|
|
24
|
+
export { type TokenEstimateOptions, type TokenEstimateResult, estimateTokens, estimateTokensWithMeta, serializeForTokenEstimate };
|
package/dist/core/token.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -148,17 +148,63 @@ function isPlainObject(value) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/core/token.ts
|
|
151
|
+
var import_node_module = require("module");
|
|
152
|
+
var import_meta = {};
|
|
153
|
+
var require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
151
154
|
function serializeForTokenEstimate(value) {
|
|
152
155
|
if (typeof value === "string") return value;
|
|
153
156
|
const serialized = JSON.stringify(value);
|
|
154
157
|
return serialized ?? "";
|
|
155
158
|
}
|
|
156
|
-
function
|
|
159
|
+
function estimateTokensHeuristic(value) {
|
|
157
160
|
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
158
161
|
}
|
|
162
|
+
function estimateTokens(value, options = {}) {
|
|
163
|
+
return estimateTokensWithMeta(value, options).count;
|
|
164
|
+
}
|
|
165
|
+
function estimateTokensWithMeta(value, options = {}) {
|
|
166
|
+
const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
|
|
167
|
+
const heuristic = estimateTokensHeuristic(value);
|
|
168
|
+
const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
|
|
169
|
+
if (!exact) {
|
|
170
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const tiktoken = require2("tiktoken");
|
|
174
|
+
const encoder = tiktoken.encoding_for_model(model);
|
|
175
|
+
const text = serializeForTokenEstimate(value);
|
|
176
|
+
const count = encoder.encode(text).length;
|
|
177
|
+
let encodingName = null;
|
|
178
|
+
if (encoder.name) encodingName = encoder.name;
|
|
179
|
+
if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
|
|
180
|
+
try {
|
|
181
|
+
encodingName = tiktoken.model_to_encoding(model);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
encodingName = null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!encodingName) {
|
|
187
|
+
const m = String(model || "").toLowerCase();
|
|
188
|
+
if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
|
|
189
|
+
else encodingName = "cl100k_base";
|
|
190
|
+
}
|
|
191
|
+
const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
|
|
192
|
+
return { count, estimator };
|
|
193
|
+
} catch (e) {
|
|
194
|
+
if (!fallbackToHeuristic) {
|
|
195
|
+
return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
|
|
196
|
+
}
|
|
197
|
+
return { count: heuristic, estimator: heuristicEstimator };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
159
200
|
|
|
160
201
|
// src/core/analyze.ts
|
|
161
202
|
function analyze(input, options = {}) {
|
|
203
|
+
const {
|
|
204
|
+
exact = false,
|
|
205
|
+
model = "gpt-4o-mini",
|
|
206
|
+
fallbackToHeuristic = true
|
|
207
|
+
} = options;
|
|
162
208
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
163
209
|
return {
|
|
164
210
|
originalTokens: 0,
|
|
@@ -169,10 +215,15 @@ function analyze(input, options = {}) {
|
|
|
169
215
|
reductionRatio: 1,
|
|
170
216
|
originalCharacters: 0,
|
|
171
217
|
optimizedCharacters: 0,
|
|
172
|
-
estimator: "heuristic: 1 token \u2248 4 characters"
|
|
218
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
173
219
|
};
|
|
174
220
|
}
|
|
175
|
-
const
|
|
221
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
222
|
+
exact,
|
|
223
|
+
model,
|
|
224
|
+
fallbackToHeuristic
|
|
225
|
+
});
|
|
226
|
+
const originalTokens = originalMeta.count;
|
|
176
227
|
let optimizedData = input;
|
|
177
228
|
if (options.prune && Array.isArray(options.prune)) {
|
|
178
229
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -186,10 +237,16 @@ function analyze(input, options = {}) {
|
|
|
186
237
|
if (options.toTOON === true || options.toon === true) {
|
|
187
238
|
optimizedData = toTOON(optimizedData);
|
|
188
239
|
}
|
|
189
|
-
const
|
|
240
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
241
|
+
exact,
|
|
242
|
+
model,
|
|
243
|
+
fallbackToHeuristic
|
|
244
|
+
});
|
|
245
|
+
const optimizedTokens = optimizedMeta.count;
|
|
190
246
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
191
247
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
192
248
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
249
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
193
250
|
return {
|
|
194
251
|
originalTokens,
|
|
195
252
|
optimizedTokens,
|
|
@@ -199,7 +256,7 @@ function analyze(input, options = {}) {
|
|
|
199
256
|
reductionRatio,
|
|
200
257
|
originalCharacters: serializeForTokenEstimate(input).length,
|
|
201
258
|
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
202
|
-
estimator:
|
|
259
|
+
estimator: estimatorLabel
|
|
203
260
|
};
|
|
204
261
|
}
|
|
205
262
|
|
|
@@ -329,8 +386,8 @@ var AIChain = class {
|
|
|
329
386
|
toNatural() {
|
|
330
387
|
return toNatural(this.data);
|
|
331
388
|
}
|
|
332
|
-
analyze() {
|
|
333
|
-
return analyze(this.data);
|
|
389
|
+
analyze(options) {
|
|
390
|
+
return analyze(this.data, options);
|
|
334
391
|
}
|
|
335
392
|
value() {
|
|
336
393
|
return this.data;
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AIChain
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P6KXISNT.js";
|
|
4
4
|
import {
|
|
5
5
|
analyze
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IOMOVRC7.js";
|
|
7
7
|
import {
|
|
8
8
|
toTOON
|
|
9
9
|
} from "./chunk-6VRLDRJK.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import {
|
|
23
23
|
estimateTokens,
|
|
24
24
|
serializeForTokenEstimate
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-U433WUUT.js";
|
|
26
26
|
|
|
27
27
|
// src/index.ts
|
|
28
28
|
function ai(data) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sohqureshi/tokenwise",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Optimize JSON data for AI by reducing token usage",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -75,6 +75,9 @@
|
|
|
75
75
|
],
|
|
76
76
|
"author": "Mohammad Sohail",
|
|
77
77
|
"license": "MIT",
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"tiktoken": "^1.0.22"
|
|
80
|
+
},
|
|
78
81
|
"devDependencies": {
|
|
79
82
|
"@types/node": "^25.6.0",
|
|
80
83
|
"tsup": "^8.0.0",
|
package/dist/chunk-7CL7GVRF.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// src/core/token.ts
|
|
2
|
-
function serializeForTokenEstimate(value) {
|
|
3
|
-
if (typeof value === "string") return value;
|
|
4
|
-
const serialized = JSON.stringify(value);
|
|
5
|
-
return serialized ?? "";
|
|
6
|
-
}
|
|
7
|
-
function estimateTokens(value) {
|
|
8
|
-
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
serializeForTokenEstimate,
|
|
13
|
-
estimateTokens
|
|
14
|
-
};
|