brevit 0.1.1 → 0.1.2
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 +59 -15
- package/package.json +1 -1
- package/src/brevit.d.ts +22 -0
- package/src/brevit.js +182 -2
package/README.md
CHANGED
|
@@ -83,26 +83,26 @@ const optimized = await brevit.brevity(data);
|
|
|
83
83
|
### npm
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
npm install brevit
|
|
86
|
+
npm install brevit
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### yarn
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
yarn add brevit
|
|
92
|
+
yarn add brevit
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
### pnpm
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
pnpm add brevit
|
|
98
|
+
pnpm add brevit
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### CDN (Browser)
|
|
102
102
|
|
|
103
103
|
```html
|
|
104
104
|
<script type="module">
|
|
105
|
-
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'https://cdn.jsdelivr.net/npm/brevit
|
|
105
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'https://cdn.jsdelivr.net/npm/brevit@latest/src/brevit.js';
|
|
106
106
|
</script>
|
|
107
107
|
```
|
|
108
108
|
|
|
@@ -118,7 +118,7 @@ import {
|
|
|
118
118
|
BrevitConfig,
|
|
119
119
|
JsonOptimizationMode,
|
|
120
120
|
type BrevitConfigOptions,
|
|
121
|
-
} from 'brevit
|
|
121
|
+
} from 'brevit';
|
|
122
122
|
|
|
123
123
|
const config: BrevitConfigOptions = {
|
|
124
124
|
jsonMode: JsonOptimizationMode.Flatten,
|
|
@@ -137,7 +137,7 @@ Brevit.js supports three main data types: **JSON objects/strings**, **text files
|
|
|
137
137
|
#### Example 1.1: Simple JSON Object
|
|
138
138
|
|
|
139
139
|
```javascript
|
|
140
|
-
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit
|
|
140
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit';
|
|
141
141
|
|
|
142
142
|
const brevit = new BrevitClient(new BrevitConfig({
|
|
143
143
|
jsonMode: JsonOptimizationMode.Flatten
|
|
@@ -153,15 +153,59 @@ const data = {
|
|
|
153
153
|
|
|
154
154
|
// Method 1: Automatic optimization (recommended)
|
|
155
155
|
const optimized = await brevit.brevity(data);
|
|
156
|
-
// Output:
|
|
157
|
-
// user
|
|
158
|
-
//
|
|
159
|
-
//
|
|
156
|
+
// Output (with abbreviations enabled by default):
|
|
157
|
+
// @u=user
|
|
158
|
+
// @u.name:John Doe
|
|
159
|
+
// @u.email:john@example.com
|
|
160
|
+
// @u.age:30
|
|
160
161
|
|
|
161
162
|
// Method 2: Explicit optimization
|
|
162
163
|
const explicit = await brevit.optimize(data);
|
|
163
164
|
```
|
|
164
165
|
|
|
166
|
+
#### Example 1.1a: Abbreviation Feature (New in v0.1.2)
|
|
167
|
+
|
|
168
|
+
Brevit automatically creates abbreviations for frequently repeated prefixes, reducing token usage by 10-25%:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit';
|
|
172
|
+
|
|
173
|
+
const brevit = new BrevitClient(new BrevitConfig({
|
|
174
|
+
jsonMode: JsonOptimizationMode.Flatten,
|
|
175
|
+
enableAbbreviations: true, // Enabled by default
|
|
176
|
+
abbreviationThreshold: 2 // Minimum occurrences to abbreviate
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
const data = {
|
|
180
|
+
user: {
|
|
181
|
+
name: "John Doe",
|
|
182
|
+
email: "john@example.com",
|
|
183
|
+
age: 30
|
|
184
|
+
},
|
|
185
|
+
order: {
|
|
186
|
+
id: "o-456",
|
|
187
|
+
status: "SHIPPED",
|
|
188
|
+
items: [
|
|
189
|
+
{ sku: "A-88", quantity: 1 }
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const optimized = await brevit.brevity(data);
|
|
195
|
+
// Output with abbreviations:
|
|
196
|
+
// @u=user
|
|
197
|
+
// @o=order
|
|
198
|
+
// @u.name:John Doe
|
|
199
|
+
// @u.email:john@example.com
|
|
200
|
+
// @u.age:30
|
|
201
|
+
// @o.id:o-456
|
|
202
|
+
// @o.status:SHIPPED
|
|
203
|
+
// @o.items[1]{quantity,sku}:
|
|
204
|
+
// 1,A-88
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Token Savings**: The abbreviation feature reduces tokens by replacing repeated prefixes like "user." and "order." with short aliases like "@u" and "@o", saving 10-25% on typical nested JSON structures.
|
|
208
|
+
|
|
165
209
|
#### Example 1.2: JSON String
|
|
166
210
|
|
|
167
211
|
```javascript
|
|
@@ -614,7 +658,7 @@ import {
|
|
|
614
658
|
type BrevitClientOptions,
|
|
615
659
|
type TextOptimizerFunction,
|
|
616
660
|
type ImageOptimizerFunction,
|
|
617
|
-
} from 'brevit
|
|
661
|
+
} from 'brevit';
|
|
618
662
|
```
|
|
619
663
|
|
|
620
664
|
### Type-Safe Configuration
|
|
@@ -1126,9 +1170,9 @@ Brevit is available in multiple languages:
|
|
|
1126
1170
|
|
|
1127
1171
|
| Language | Package | Status |
|
|
1128
1172
|
|----------|---------|--------|
|
|
1129
|
-
| JavaScript | `brevit
|
|
1130
|
-
| C# (.NET) | `Brevit
|
|
1131
|
-
| Python | `brevit
|
|
1173
|
+
| JavaScript | `brevit` | ✅ Stable (This) |
|
|
1174
|
+
| C# (.NET) | `Brevit` | ✅ Stable |
|
|
1175
|
+
| Python | `brevit` | ✅ Stable |
|
|
1132
1176
|
|
|
1133
1177
|
## Full Specification
|
|
1134
1178
|
|
|
@@ -1228,7 +1272,7 @@ MIT License - see LICENSE file for details.
|
|
|
1228
1272
|
## Support
|
|
1229
1273
|
|
|
1230
1274
|
- **Documentation**: [https://brevit.dev/docs](https://brevit.dev/docs)
|
|
1231
|
-
- **Issues**: [https://github.com/
|
|
1275
|
+
- **Issues**: [https://github.com/JavianDev/Brevit.js/issues](https://github.com/JavianDev/Brevit.js/issues)
|
|
1232
1276
|
- **Email**: support@javianpicardo.com
|
|
1233
1277
|
|
|
1234
1278
|
## Version History
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brevit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "A high-performance JavaScript library for semantically compressing and optimizing data before sending it to a Large Language Model (LLM).",
|
|
5
5
|
"main": "src/brevit.js",
|
|
6
6
|
"types": "src/brevit.d.ts",
|
package/src/brevit.d.ts
CHANGED
|
@@ -81,6 +81,18 @@ export interface BrevitConfigOptions {
|
|
|
81
81
|
* @default 500
|
|
82
82
|
*/
|
|
83
83
|
longTextThreshold?: number;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Enable abbreviation feature for frequently repeated key prefixes
|
|
87
|
+
* @default true
|
|
88
|
+
*/
|
|
89
|
+
enableAbbreviations?: boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Minimum number of occurrences required to create an abbreviation
|
|
93
|
+
* @default 2
|
|
94
|
+
*/
|
|
95
|
+
abbreviationThreshold?: number;
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
/**
|
|
@@ -112,6 +124,16 @@ export class BrevitConfig {
|
|
|
112
124
|
*/
|
|
113
125
|
longTextThreshold: number;
|
|
114
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Enable abbreviation feature
|
|
129
|
+
*/
|
|
130
|
+
enableAbbreviations: boolean;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Abbreviation threshold
|
|
134
|
+
*/
|
|
135
|
+
abbreviationThreshold: number;
|
|
136
|
+
|
|
115
137
|
/**
|
|
116
138
|
* Creates a new BrevitConfig instance
|
|
117
139
|
* @param options Configuration options
|
package/src/brevit.js
CHANGED
|
@@ -43,6 +43,8 @@ export class BrevitConfig {
|
|
|
43
43
|
* @param {string} options.imageMode - Strategy for Image optimization.
|
|
44
44
|
* @param {string[]} options.jsonPathsToKeep - Paths to keep for Filter mode.
|
|
45
45
|
* @param {number} options.longTextThreshold - Char count to trigger text optimization.
|
|
46
|
+
* @param {boolean} options.enableAbbreviations - Enable abbreviation feature for repeated prefixes.
|
|
47
|
+
* @param {number} options.abbreviationThreshold - Minimum occurrences to create abbreviation.
|
|
46
48
|
*/
|
|
47
49
|
constructor({
|
|
48
50
|
jsonMode = JsonOptimizationMode.Flatten,
|
|
@@ -50,12 +52,16 @@ export class BrevitConfig {
|
|
|
50
52
|
imageMode = ImageOptimizationMode.Ocr,
|
|
51
53
|
jsonPathsToKeep = [],
|
|
52
54
|
longTextThreshold = 500,
|
|
55
|
+
enableAbbreviations = true,
|
|
56
|
+
abbreviationThreshold = 2,
|
|
53
57
|
} = {}) {
|
|
54
58
|
this.jsonMode = jsonMode;
|
|
55
59
|
this.textMode = textMode;
|
|
56
60
|
this.imageMode = imageMode;
|
|
57
61
|
this.jsonPathsToKeep = jsonPathsToKeep;
|
|
58
62
|
this.longTextThreshold = longTextThreshold;
|
|
63
|
+
this.enableAbbreviations = enableAbbreviations;
|
|
64
|
+
this.abbreviationThreshold = abbreviationThreshold;
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -220,7 +226,131 @@ export class BrevitClient {
|
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
/**
|
|
223
|
-
*
|
|
229
|
+
* Generates abbreviations for frequently repeated prefixes.
|
|
230
|
+
* @param {Array<string>} paths - Array of flattened paths
|
|
231
|
+
* @returns {Object} Object with abbreviation map and definitions array
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
_generateAbbreviations(paths) {
|
|
235
|
+
if (!this._config.enableAbbreviations) {
|
|
236
|
+
return { map: new Map(), definitions: [] };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Count prefix frequencies
|
|
240
|
+
const prefixCounts = new Map();
|
|
241
|
+
|
|
242
|
+
paths.forEach(path => {
|
|
243
|
+
// Extract all prefixes (e.g., "user", "user.name", "order.items")
|
|
244
|
+
const parts = path.split('.');
|
|
245
|
+
for (let i = 1; i < parts.length; i++) {
|
|
246
|
+
const prefix = parts.slice(0, i).join('.');
|
|
247
|
+
prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Filter prefixes that meet threshold
|
|
252
|
+
const frequentPrefixes = Array.from(prefixCounts.entries())
|
|
253
|
+
.filter(([prefix, count]) => count >= this._config.abbreviationThreshold)
|
|
254
|
+
.sort((a, b) => {
|
|
255
|
+
// Sort by: 1) count (desc), 2) length (asc) - prefer shorter, more frequent
|
|
256
|
+
if (b[1] !== a[1]) return b[1] - a[1];
|
|
257
|
+
return a[0].length - b[0].length;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Generate abbreviations
|
|
261
|
+
const abbreviationMap = new Map();
|
|
262
|
+
const definitions = [];
|
|
263
|
+
let abbrCounter = 0;
|
|
264
|
+
const usedAbbrs = new Set();
|
|
265
|
+
|
|
266
|
+
frequentPrefixes.forEach(([prefix, count]) => {
|
|
267
|
+
// Calculate savings: (prefix.length - abbr.length) * count
|
|
268
|
+
// Only abbreviate if it saves tokens
|
|
269
|
+
const abbr = this._generateAbbreviation(prefix, abbrCounter, usedAbbrs);
|
|
270
|
+
const definitionCost = prefix.length + abbr.length + 3; // "@x=prefix"
|
|
271
|
+
const savings = (prefix.length - abbr.length - 1) * count; // -1 for "@"
|
|
272
|
+
|
|
273
|
+
// Only create abbreviation if it saves tokens (accounting for definition)
|
|
274
|
+
if (savings > definitionCost) {
|
|
275
|
+
abbreviationMap.set(prefix, abbr);
|
|
276
|
+
definitions.push(`@${abbr}=${prefix}`);
|
|
277
|
+
abbrCounter++;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return { map: abbreviationMap, definitions };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Generates a short abbreviation for a prefix.
|
|
286
|
+
* @param {string} prefix - The prefix to abbreviate
|
|
287
|
+
* @param {number} counter - Counter for fallback abbreviations
|
|
288
|
+
* @param {Set<string>} usedAbbrs - Set of already used abbreviations
|
|
289
|
+
* @returns {string} The abbreviation
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
_generateAbbreviation(prefix, counter, usedAbbrs) {
|
|
293
|
+
// Strategy 1: Use first letter if available and not used
|
|
294
|
+
const firstLetter = prefix.split('.')[0][0].toLowerCase();
|
|
295
|
+
if (!usedAbbrs.has(firstLetter)) {
|
|
296
|
+
usedAbbrs.add(firstLetter);
|
|
297
|
+
return firstLetter;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Strategy 2: Use first letter of each part (e.g., "order.items" -> "oi")
|
|
301
|
+
const parts = prefix.split('.');
|
|
302
|
+
if (parts.length > 1) {
|
|
303
|
+
const multiLetter = parts.map(p => p[0]).join('').toLowerCase();
|
|
304
|
+
if (!usedAbbrs.has(multiLetter) && multiLetter.length <= 3) {
|
|
305
|
+
usedAbbrs.add(multiLetter);
|
|
306
|
+
return multiLetter;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Strategy 3: Use counter-based abbreviation (a, b, c, ..., z, aa, ab, ...)
|
|
311
|
+
let abbr = '';
|
|
312
|
+
let num = counter;
|
|
313
|
+
do {
|
|
314
|
+
abbr = String.fromCharCode(97 + (num % 26)) + abbr; // 97 = 'a'
|
|
315
|
+
num = Math.floor(num / 26) - 1;
|
|
316
|
+
} while (num >= 0);
|
|
317
|
+
|
|
318
|
+
usedAbbrs.add(abbr);
|
|
319
|
+
return abbr;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Applies abbreviations to a path string.
|
|
324
|
+
* @param {string} path - The path to abbreviate
|
|
325
|
+
* @param {Map<string, string>} abbreviationMap - Map of prefix to abbreviation
|
|
326
|
+
* @returns {string} The abbreviated path
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
329
|
+
_applyAbbreviations(path, abbreviationMap) {
|
|
330
|
+
if (!this._config.enableAbbreviations || abbreviationMap.size === 0) {
|
|
331
|
+
return path;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Find the longest matching prefix
|
|
335
|
+
let bestMatch = '';
|
|
336
|
+
let bestAbbr = '';
|
|
337
|
+
|
|
338
|
+
for (const [prefix, abbr] of abbreviationMap.entries()) {
|
|
339
|
+
if (path.startsWith(prefix + '.') && prefix.length > bestMatch.length) {
|
|
340
|
+
bestMatch = prefix;
|
|
341
|
+
bestAbbr = abbr;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (bestMatch) {
|
|
346
|
+
return `@${bestAbbr}.${path.substring(bestMatch.length + 1)}`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return path;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Flattens a JS object into a token-efficient string with tabular optimization and abbreviations.
|
|
224
354
|
* @param {object} obj - The object to flatten.
|
|
225
355
|
* @returns {string} The flattened string.
|
|
226
356
|
* @private
|
|
@@ -228,7 +358,57 @@ export class BrevitClient {
|
|
|
228
358
|
_flattenObject(obj) {
|
|
229
359
|
const output = [];
|
|
230
360
|
this._flatten(obj, '', output);
|
|
231
|
-
|
|
361
|
+
|
|
362
|
+
// Extract paths from output (before values)
|
|
363
|
+
const paths = output.map(line => {
|
|
364
|
+
const colonIndex = line.indexOf(':');
|
|
365
|
+
if (colonIndex > 0) {
|
|
366
|
+
const pathPart = line.substring(0, colonIndex);
|
|
367
|
+
// Handle tabular arrays: "key[count]{fields}:"
|
|
368
|
+
const bracketIndex = pathPart.indexOf('[');
|
|
369
|
+
if (bracketIndex > 0) {
|
|
370
|
+
return pathPart.substring(0, bracketIndex);
|
|
371
|
+
}
|
|
372
|
+
return pathPart;
|
|
373
|
+
}
|
|
374
|
+
return line.split(':')[0];
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Generate abbreviations
|
|
378
|
+
const { map: abbreviationMap, definitions } = this._generateAbbreviations(paths);
|
|
379
|
+
|
|
380
|
+
// Apply abbreviations to output
|
|
381
|
+
const abbreviatedOutput = output.map(line => {
|
|
382
|
+
// Handle different line formats:
|
|
383
|
+
// 1. "key:value"
|
|
384
|
+
// 2. "key[count]:value1,value2"
|
|
385
|
+
// 3. "key[count]{fields}:\nrow1\nrow2"
|
|
386
|
+
|
|
387
|
+
const colonIndex = line.indexOf(':');
|
|
388
|
+
if (colonIndex === -1) return line;
|
|
389
|
+
|
|
390
|
+
const pathPart = line.substring(0, colonIndex);
|
|
391
|
+
const valuePart = line.substring(colonIndex);
|
|
392
|
+
|
|
393
|
+
// Handle tabular arrays - abbreviate the base path
|
|
394
|
+
const bracketIndex = pathPart.indexOf('[');
|
|
395
|
+
if (bracketIndex > 0) {
|
|
396
|
+
const basePath = pathPart.substring(0, bracketIndex);
|
|
397
|
+
const rest = pathPart.substring(bracketIndex);
|
|
398
|
+
const abbreviatedBase = this._applyAbbreviations(basePath, abbreviationMap);
|
|
399
|
+
return abbreviatedBase + rest + valuePart;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const abbreviatedPath = this._applyAbbreviations(pathPart, abbreviationMap);
|
|
403
|
+
return abbreviatedPath + valuePart;
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Combine: definitions first, then abbreviated output
|
|
407
|
+
if (definitions.length > 0) {
|
|
408
|
+
return definitions.join('\n') + '\n' + abbreviatedOutput.join('\n');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return abbreviatedOutput.join('\n');
|
|
232
412
|
}
|
|
233
413
|
|
|
234
414
|
/**
|