@sohqureshi/tokenwise 1.0.3 → 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 +13 -8
- package/dist/{chunk-3ECVBELU.js → chunk-6VRLDRJK.js} +5 -3
- package/dist/{chunk-GQ62V6ZK.js → chunk-IOMOVRC7.js} +33 -12
- package/dist/{chunk-YMOSWQGE.js → chunk-L7BC62MT.js} +11 -3
- package/dist/{chunk-2IQAGI7Q.js → chunk-P6KXISNT.js} +7 -7
- package/dist/chunk-U433WUUT.js +55 -0
- package/dist/{chunk-EUFLW42L.js → chunk-XE36GLJP.js} +1 -1
- package/dist/{chunk-IAV75SZA.js → chunk-ZD536GZF.js} +1 -1
- package/dist/cli.cjs +91 -19
- package/dist/cli.js +8 -8
- package/dist/core/analyze.cjs +88 -16
- package/dist/core/analyze.d.cts +16 -3
- package/dist/core/analyze.d.ts +16 -3
- package/dist/core/analyze.js +6 -6
- package/dist/core/compact.cjs +1 -1
- package/dist/core/compact.js +2 -2
- package/dist/core/flatten.cjs +11 -3
- package/dist/core/flatten.d.cts +1 -1
- package/dist/core/flatten.d.ts +1 -1
- package/dist/core/flatten.js +1 -1
- package/dist/core/prune.cjs +1 -1
- package/dist/core/prune.js +1 -1
- package/dist/core/token.cjs +54 -5
- package/dist/core/token.d.cts +21 -9
- package/dist/core/token.d.ts +21 -9
- package/dist/core/token.js +7 -3
- package/dist/core/toon.cjs +5 -3
- package/dist/core/toon.js +1 -1
- package/dist/index.cjs +96 -18
- package/dist/index.d.cts +13 -9
- package/dist/index.d.ts +13 -9
- package/dist/index.js +11 -8
- package/package.json +6 -1
- package/dist/chunk-TM6L7YF2.js +0 -9
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,10 +36,12 @@ 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
|
|
42
|
-
import ai, { compact, flatten, toNatural, toTOON } from "tokenwise";
|
|
44
|
+
import ai, { compact, flatten, toNatural, toTOON } from "@sohqureshi/tokenwise";
|
|
43
45
|
|
|
44
46
|
const product = {
|
|
45
47
|
product: {
|
|
@@ -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 },
|
|
@@ -208,14 +210,17 @@ LLMs charge and reason over tokens. Sending raw JSON often includes repeated key
|
|
|
208
210
|
node demo.js
|
|
209
211
|
```
|
|
210
212
|
|
|
211
|
-
|
|
213
|
+
Use `--analyze` to compare serialized input and output with TokenWise's
|
|
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.
|
|
212
217
|
|
|
213
218
|
---
|
|
214
219
|
|
|
215
220
|
## 🚀 Roadmap
|
|
216
221
|
|
|
217
|
-
* [x] CLI support
|
|
218
|
-
* [
|
|
222
|
+
* [x] CLI support
|
|
223
|
+
* [x] NPM Support
|
|
219
224
|
* [ ] Streaming support (GB+ data)
|
|
220
225
|
* [ ] Schema-aware optimization
|
|
221
226
|
* [ ] SaaS API
|
|
@@ -259,4 +264,4 @@ If it helps you, consider supporting its development:
|
|
|
259
264
|
|
|
260
265
|
## 💡 Vision
|
|
261
266
|
|
|
262
|
-
Make AI cheaper and faster by optimizing data before it reaches the model.
|
|
267
|
+
Make AI cheaper and faster by optimizing data before it reaches the model.
|
|
@@ -14,11 +14,11 @@ function toTOON(data, indent = 0) {
|
|
|
14
14
|
}
|
|
15
15
|
return result;
|
|
16
16
|
}
|
|
17
|
-
return `${space}[${data.length}]: ${data.join(",")}`;
|
|
17
|
+
return `${space}[${data.length}]: ${data.map(formatValue).join(",")}`;
|
|
18
18
|
}
|
|
19
19
|
if (typeof data === "object" && data !== null) {
|
|
20
20
|
let result = "";
|
|
21
|
-
for (const key
|
|
21
|
+
for (const key of Object.keys(data)) {
|
|
22
22
|
const value = data[key];
|
|
23
23
|
if (typeof value === "object" && value !== null) {
|
|
24
24
|
result += `${space}${key}:
|
|
@@ -37,7 +37,9 @@ ${toTOON(value, indent + 1)}
|
|
|
37
37
|
}
|
|
38
38
|
function formatValue(val) {
|
|
39
39
|
if (val === null || val === void 0) return "";
|
|
40
|
-
if (typeof val === "string")
|
|
40
|
+
if (typeof val === "string") {
|
|
41
|
+
return val === "" || /[,\n\r]/.test(val) ? JSON.stringify(val) : val;
|
|
42
|
+
}
|
|
41
43
|
return String(val);
|
|
42
44
|
}
|
|
43
45
|
function isPlainObject(value) {
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
toTOON
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6VRLDRJK.js";
|
|
4
4
|
import {
|
|
5
5
|
compact
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XE36GLJP.js";
|
|
7
7
|
import {
|
|
8
8
|
flatten
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-L7BC62MT.js";
|
|
10
10
|
import {
|
|
11
11
|
prune
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZD536GZF.js";
|
|
13
13
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
estimateTokensWithMeta,
|
|
15
|
+
serializeForTokenEstimate
|
|
16
|
+
} from "./chunk-U433WUUT.js";
|
|
16
17
|
|
|
17
18
|
// src/core/analyze.ts
|
|
18
19
|
function analyze(input, options = {}) {
|
|
20
|
+
const {
|
|
21
|
+
exact = false,
|
|
22
|
+
model = "gpt-4o-mini",
|
|
23
|
+
fallbackToHeuristic = true
|
|
24
|
+
} = options;
|
|
19
25
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
20
26
|
return {
|
|
21
27
|
originalTokens: 0,
|
|
@@ -23,11 +29,18 @@ function analyze(input, options = {}) {
|
|
|
23
29
|
savings: 0,
|
|
24
30
|
savingsPercent: 0,
|
|
25
31
|
optimizedData: null,
|
|
26
|
-
reductionRatio: 1
|
|
32
|
+
reductionRatio: 1,
|
|
33
|
+
originalCharacters: 0,
|
|
34
|
+
optimizedCharacters: 0,
|
|
35
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
27
36
|
};
|
|
28
37
|
}
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
39
|
+
exact,
|
|
40
|
+
model,
|
|
41
|
+
fallbackToHeuristic
|
|
42
|
+
});
|
|
43
|
+
const originalTokens = originalMeta.count;
|
|
31
44
|
let optimizedData = input;
|
|
32
45
|
if (options.prune && Array.isArray(options.prune)) {
|
|
33
46
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -41,18 +54,26 @@ function analyze(input, options = {}) {
|
|
|
41
54
|
if (options.toTOON === true || options.toon === true) {
|
|
42
55
|
optimizedData = toTOON(optimizedData);
|
|
43
56
|
}
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
58
|
+
exact,
|
|
59
|
+
model,
|
|
60
|
+
fallbackToHeuristic
|
|
61
|
+
});
|
|
62
|
+
const optimizedTokens = optimizedMeta.count;
|
|
46
63
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
47
64
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
48
65
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
66
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
49
67
|
return {
|
|
50
68
|
originalTokens,
|
|
51
69
|
optimizedTokens,
|
|
52
70
|
savings,
|
|
53
71
|
savingsPercent,
|
|
54
72
|
optimizedData,
|
|
55
|
-
reductionRatio
|
|
73
|
+
reductionRatio,
|
|
74
|
+
originalCharacters: serializeForTokenEstimate(input).length,
|
|
75
|
+
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
76
|
+
estimator: estimatorLabel
|
|
56
77
|
};
|
|
57
78
|
}
|
|
58
79
|
|
|
@@ -2,20 +2,28 @@
|
|
|
2
2
|
function flatten(obj, prefix = "", res = {}) {
|
|
3
3
|
if (obj === null || obj === void 0) return res;
|
|
4
4
|
if (typeof obj !== "object") {
|
|
5
|
-
res
|
|
5
|
+
setValue(res, prefix, obj);
|
|
6
6
|
return res;
|
|
7
7
|
}
|
|
8
|
-
for (const key
|
|
8
|
+
for (const key of Object.keys(obj)) {
|
|
9
9
|
const value = obj[key];
|
|
10
10
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
11
11
|
if (typeof value === "object" && value !== null) {
|
|
12
12
|
flatten(value, newKey, res);
|
|
13
13
|
} else {
|
|
14
|
-
res
|
|
14
|
+
setValue(res, newKey, value);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
return res;
|
|
18
18
|
}
|
|
19
|
+
function setValue(res, key, value) {
|
|
20
|
+
if (Object.prototype.hasOwnProperty.call(res, key)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Cannot flatten input: the path "${key}" collides with an existing key. Use keys without dots or rename one of the conflicting properties.`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
res[key] = value;
|
|
26
|
+
}
|
|
19
27
|
|
|
20
28
|
export {
|
|
21
29
|
flatten
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyze
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IOMOVRC7.js";
|
|
4
4
|
import {
|
|
5
5
|
toTOON
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6VRLDRJK.js";
|
|
7
7
|
import {
|
|
8
8
|
compact
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XE36GLJP.js";
|
|
10
10
|
import {
|
|
11
11
|
flatten
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-L7BC62MT.js";
|
|
13
13
|
import {
|
|
14
14
|
toNatural
|
|
15
15
|
} from "./chunk-D4CFTFM3.js";
|
|
16
16
|
import {
|
|
17
17
|
prune
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-ZD536GZF.js";
|
|
19
19
|
|
|
20
20
|
// src/chain.ts
|
|
21
21
|
var AIChain = class {
|
|
@@ -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
|
+
};
|
|
@@ -19,7 +19,7 @@ function prune(obj, options = {}) {
|
|
|
19
19
|
return arr;
|
|
20
20
|
}
|
|
21
21
|
const result = {};
|
|
22
|
-
for (const key
|
|
22
|
+
for (const key of Object.keys(obj)) {
|
|
23
23
|
if (removeKeys.includes(key)) continue;
|
|
24
24
|
const value = prune(obj[key], normalizedOptions);
|
|
25
25
|
if (value === void 0) continue;
|
package/dist/cli.cjs
CHANGED
|
@@ -48,7 +48,7 @@ function prune(obj, options = {}) {
|
|
|
48
48
|
return arr;
|
|
49
49
|
}
|
|
50
50
|
const result = {};
|
|
51
|
-
for (const key
|
|
51
|
+
for (const key of Object.keys(obj)) {
|
|
52
52
|
if (removeKeys.includes(key)) continue;
|
|
53
53
|
const value = prune(obj[key], normalizedOptions);
|
|
54
54
|
if (value === void 0) continue;
|
|
@@ -64,20 +64,28 @@ function prune(obj, options = {}) {
|
|
|
64
64
|
function flatten(obj, prefix = "", res = {}) {
|
|
65
65
|
if (obj === null || obj === void 0) return res;
|
|
66
66
|
if (typeof obj !== "object") {
|
|
67
|
-
res
|
|
67
|
+
setValue(res, prefix, obj);
|
|
68
68
|
return res;
|
|
69
69
|
}
|
|
70
|
-
for (const key
|
|
70
|
+
for (const key of Object.keys(obj)) {
|
|
71
71
|
const value = obj[key];
|
|
72
72
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
73
73
|
if (typeof value === "object" && value !== null) {
|
|
74
74
|
flatten(value, newKey, res);
|
|
75
75
|
} else {
|
|
76
|
-
res
|
|
76
|
+
setValue(res, newKey, value);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
return res;
|
|
80
80
|
}
|
|
81
|
+
function setValue(res, key, value) {
|
|
82
|
+
if (Object.prototype.hasOwnProperty.call(res, key)) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Cannot flatten input: the path "${key}" collides with an existing key. Use keys without dots or rename one of the conflicting properties.`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
res[key] = value;
|
|
88
|
+
}
|
|
81
89
|
|
|
82
90
|
// src/core/compact.ts
|
|
83
91
|
function compact(obj) {
|
|
@@ -101,11 +109,11 @@ function toTOON(data, indent = 0) {
|
|
|
101
109
|
}
|
|
102
110
|
return result;
|
|
103
111
|
}
|
|
104
|
-
return `${space}[${data.length}]: ${data.join(",")}`;
|
|
112
|
+
return `${space}[${data.length}]: ${data.map(formatValue).join(",")}`;
|
|
105
113
|
}
|
|
106
114
|
if (typeof data === "object" && data !== null) {
|
|
107
115
|
let result = "";
|
|
108
|
-
for (const key
|
|
116
|
+
for (const key of Object.keys(data)) {
|
|
109
117
|
const value = data[key];
|
|
110
118
|
if (typeof value === "object" && value !== null) {
|
|
111
119
|
result += `${space}${key}:
|
|
@@ -124,7 +132,9 @@ ${toTOON(value, indent + 1)}
|
|
|
124
132
|
}
|
|
125
133
|
function formatValue(val) {
|
|
126
134
|
if (val === null || val === void 0) return "";
|
|
127
|
-
if (typeof val === "string")
|
|
135
|
+
if (typeof val === "string") {
|
|
136
|
+
return val === "" || /[,\n\r]/.test(val) ? JSON.stringify(val) : val;
|
|
137
|
+
}
|
|
128
138
|
return String(val);
|
|
129
139
|
}
|
|
130
140
|
function isPlainObject(value) {
|
|
@@ -132,13 +142,60 @@ function isPlainObject(value) {
|
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
// src/core/token.ts
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
var import_node_module = require("module");
|
|
146
|
+
var import_meta = {};
|
|
147
|
+
var require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
148
|
+
function serializeForTokenEstimate(value) {
|
|
149
|
+
if (typeof value === "string") return value;
|
|
150
|
+
const serialized = JSON.stringify(value);
|
|
151
|
+
return serialized ?? "";
|
|
152
|
+
}
|
|
153
|
+
function estimateTokensHeuristic(value) {
|
|
154
|
+
return Math.ceil(serializeForTokenEstimate(value).length / 4);
|
|
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
|
+
}
|
|
138
190
|
}
|
|
139
191
|
|
|
140
192
|
// src/core/analyze.ts
|
|
141
193
|
function analyze(input, options = {}) {
|
|
194
|
+
const {
|
|
195
|
+
exact = false,
|
|
196
|
+
model = "gpt-4o-mini",
|
|
197
|
+
fallbackToHeuristic = true
|
|
198
|
+
} = options;
|
|
142
199
|
if (!input || typeof input === "object" && input !== null && Object.keys(input).length === 0) {
|
|
143
200
|
return {
|
|
144
201
|
originalTokens: 0,
|
|
@@ -146,11 +203,18 @@ function analyze(input, options = {}) {
|
|
|
146
203
|
savings: 0,
|
|
147
204
|
savingsPercent: 0,
|
|
148
205
|
optimizedData: null,
|
|
149
|
-
reductionRatio: 1
|
|
206
|
+
reductionRatio: 1,
|
|
207
|
+
originalCharacters: 0,
|
|
208
|
+
optimizedCharacters: 0,
|
|
209
|
+
estimator: exact ? `exact tokenizer: model=${model}` : "heuristic: 1 token \u2248 4 characters"
|
|
150
210
|
};
|
|
151
211
|
}
|
|
152
|
-
|
|
153
|
-
|
|
212
|
+
const originalMeta = estimateTokensWithMeta(input, {
|
|
213
|
+
exact,
|
|
214
|
+
model,
|
|
215
|
+
fallbackToHeuristic
|
|
216
|
+
});
|
|
217
|
+
const originalTokens = originalMeta.count;
|
|
154
218
|
let optimizedData = input;
|
|
155
219
|
if (options.prune && Array.isArray(options.prune)) {
|
|
156
220
|
optimizedData = prune(optimizedData, options.prune);
|
|
@@ -164,18 +228,26 @@ function analyze(input, options = {}) {
|
|
|
164
228
|
if (options.toTOON === true || options.toon === true) {
|
|
165
229
|
optimizedData = toTOON(optimizedData);
|
|
166
230
|
}
|
|
167
|
-
|
|
168
|
-
|
|
231
|
+
const optimizedMeta = estimateTokensWithMeta(optimizedData, {
|
|
232
|
+
exact,
|
|
233
|
+
model,
|
|
234
|
+
fallbackToHeuristic
|
|
235
|
+
});
|
|
236
|
+
const optimizedTokens = optimizedMeta.count;
|
|
169
237
|
const savings = Math.max(0, originalTokens - optimizedTokens);
|
|
170
238
|
const savingsPercent = originalTokens > 0 ? Math.round(savings / originalTokens * 100) : 0;
|
|
171
239
|
const reductionRatio = originalTokens > 0 ? optimizedTokens / originalTokens : 1;
|
|
240
|
+
const estimatorLabel = originalMeta && originalMeta.estimator ? originalMeta.estimator : optimizedMeta.estimator;
|
|
172
241
|
return {
|
|
173
242
|
originalTokens,
|
|
174
243
|
optimizedTokens,
|
|
175
244
|
savings,
|
|
176
245
|
savingsPercent,
|
|
177
246
|
optimizedData,
|
|
178
|
-
reductionRatio
|
|
247
|
+
reductionRatio,
|
|
248
|
+
originalCharacters: serializeForTokenEstimate(input).length,
|
|
249
|
+
optimizedCharacters: serializeForTokenEstimate(optimizedData).length,
|
|
250
|
+
estimator: estimatorLabel
|
|
179
251
|
};
|
|
180
252
|
}
|
|
181
253
|
|
|
@@ -305,8 +377,8 @@ var AIChain = class {
|
|
|
305
377
|
toNatural() {
|
|
306
378
|
return toNatural(this.data);
|
|
307
379
|
}
|
|
308
|
-
analyze() {
|
|
309
|
-
return analyze(this.data);
|
|
380
|
+
analyze(options) {
|
|
381
|
+
return analyze(this.data, options);
|
|
310
382
|
}
|
|
311
383
|
value() {
|
|
312
384
|
return this.data;
|
|
@@ -323,7 +395,7 @@ Usage:
|
|
|
323
395
|
Options:
|
|
324
396
|
--toon Convert JSON to TOON format
|
|
325
397
|
--compact Convert JSON to compact format
|
|
326
|
-
--analyze Show token analysis
|
|
398
|
+
--analyze Show token analysis (heuristic estimate)
|
|
327
399
|
`);
|
|
328
400
|
process.exit(0);
|
|
329
401
|
}
|
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-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-P6KXISNT.js";
|
|
5
|
+
import "./chunk-IOMOVRC7.js";
|
|
6
|
+
import "./chunk-6VRLDRJK.js";
|
|
7
|
+
import "./chunk-XE36GLJP.js";
|
|
8
|
+
import "./chunk-L7BC62MT.js";
|
|
9
9
|
import "./chunk-D4CFTFM3.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-ZD536GZF.js";
|
|
11
|
+
import "./chunk-U433WUUT.js";
|
|
12
12
|
|
|
13
13
|
// src/cli.ts
|
|
14
14
|
import fs from "fs";
|
|
@@ -22,7 +22,7 @@ Usage:
|
|
|
22
22
|
Options:
|
|
23
23
|
--toon Convert JSON to TOON format
|
|
24
24
|
--compact Convert JSON to compact format
|
|
25
|
-
--analyze Show token analysis
|
|
25
|
+
--analyze Show token analysis (heuristic estimate)
|
|
26
26
|
`);
|
|
27
27
|
process.exit(0);
|
|
28
28
|
}
|