@solvers-hub/llm-json 0.1.10 → 0.1.11
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 +1 -1
- package/package.json +2 -5
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -120
- package/docs/assets/icons.js +0 -15
- package/docs/assets/icons.svg +0 -1
- package/docs/assets/main.js +0 -59
- package/docs/assets/navigation.js +0 -1
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1412
- package/docs/classes/LlmJson.html +0 -20
- package/docs/index.html +0 -68
- package/docs/interfaces/ExtractOptions.html +0 -11
- package/docs/interfaces/ExtractResult.html +0 -8
- package/docs/interfaces/JsonBlock.html +0 -12
- package/docs/interfaces/JsonParseError.html +0 -8
- package/docs/interfaces/SchemaDefinition.html +0 -6
- package/docs/interfaces/ValidationResult.html +0 -10
- package/docs/modules.html +0 -9
- package/docs-md/.nojekyll +0 -1
- package/docs-md/COMPREHENSIVE_GUIDE.md +0 -669
- package/docs-md/README.md +0 -108
- package/docs-md/classes/LlmJson.md +0 -147
- package/docs-md/interfaces/ExtractOptions.md +0 -49
- package/docs-md/interfaces/ExtractResult.md +0 -49
- package/docs-md/interfaces/JsonBlock.md +0 -75
- package/docs-md/interfaces/JsonParseError.md +0 -49
- package/docs-md/interfaces/SchemaDefinition.md +0 -36
- package/docs-md/interfaces/ValidationResult.md +0 -62
- package/docs-md/modules.md +0 -28
- package/examples/advanced-patterns-example.ts +0 -533
- package/examples/array-example.ts +0 -69
- package/examples/example.ts +0 -101
- package/examples/schema-validation-example.ts +0 -140
- package/examples/schema-validation-examples.ts +0 -248
- package/examples/zod-integration-example.ts +0 -431
|
@@ -1,533 +0,0 @@
|
|
|
1
|
-
import LlmJson from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ADVANCED PATTERNS AND STRATEGIES
|
|
5
|
-
*
|
|
6
|
-
* This file demonstrates advanced usage patterns including:
|
|
7
|
-
* - Two-stage parsing for performance optimization
|
|
8
|
-
* - Streaming/chunked input handling
|
|
9
|
-
* - Error detection and recovery strategies
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* EXAMPLE 1: Two-Stage Parsing Strategy (Performance Optimization)
|
|
14
|
-
* Question 10: Fast path vs fallback path with attemptCorrection
|
|
15
|
-
*
|
|
16
|
-
* Use Case: High-throughput data pipeline processing millions of LLM responses
|
|
17
|
-
* Goal: Balance speed (fast path) with reliability (fallback path)
|
|
18
|
-
*/
|
|
19
|
-
class TwoStageParser {
|
|
20
|
-
private fastParser: LlmJson;
|
|
21
|
-
private fallbackParser: LlmJson;
|
|
22
|
-
private stats = {
|
|
23
|
-
fastPathSuccess: 0,
|
|
24
|
-
fallbackPathUsed: 0,
|
|
25
|
-
totalFailures: 0
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
constructor() {
|
|
29
|
-
// Stage 1: Fast path - no correction, minimal overhead
|
|
30
|
-
this.fastParser = new LlmJson({
|
|
31
|
-
attemptCorrection: false // Fast: no correction overhead
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Stage 2: Fallback path - with correction for reliability
|
|
35
|
-
this.fallbackParser = new LlmJson({
|
|
36
|
-
attemptCorrection: true // Slower but fixes malformed JSON
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Two-stage parsing with intelligent fallback
|
|
42
|
-
*
|
|
43
|
-
* Stage 1 (Fast Path):
|
|
44
|
-
* - Try parsing without correction
|
|
45
|
-
* - 90%+ of well-formed LLM outputs succeed here
|
|
46
|
-
* - Minimal CPU overhead
|
|
47
|
-
*
|
|
48
|
-
* Stage 2 (Fallback Path):
|
|
49
|
-
* - Triggered when Stage 1 fails
|
|
50
|
-
* - Uses correction to fix malformed JSON
|
|
51
|
-
* - Higher CPU cost but recovers data
|
|
52
|
-
*/
|
|
53
|
-
parse(llmOutput: string): { success: boolean; data: any[]; errors?: any[] } {
|
|
54
|
-
// STAGE 1: FAST PATH
|
|
55
|
-
const fastResult = this.fastParser.extract(llmOutput);
|
|
56
|
-
|
|
57
|
-
// Determine if fast path succeeded
|
|
58
|
-
const fastPathSucceeded = this.shouldUseFastPath(llmOutput, fastResult);
|
|
59
|
-
|
|
60
|
-
if (fastPathSucceeded) {
|
|
61
|
-
this.stats.fastPathSuccess++;
|
|
62
|
-
return {
|
|
63
|
-
success: true,
|
|
64
|
-
data: fastResult.json
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// STAGE 2: FALLBACK PATH
|
|
69
|
-
console.log('Fast path failed, trying fallback with correction...');
|
|
70
|
-
this.stats.fallbackPathUsed++;
|
|
71
|
-
|
|
72
|
-
const fallbackResult = this.fallbackParser.extract(llmOutput);
|
|
73
|
-
|
|
74
|
-
if (fallbackResult.json.length > 0) {
|
|
75
|
-
return {
|
|
76
|
-
success: true,
|
|
77
|
-
data: fallbackResult.json
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Both stages failed
|
|
82
|
-
this.stats.totalFailures++;
|
|
83
|
-
return {
|
|
84
|
-
success: false,
|
|
85
|
-
data: [],
|
|
86
|
-
errors: ['Both fast and fallback parsing failed']
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* CRITICAL LOGIC: When to trigger Stage 2
|
|
92
|
-
*
|
|
93
|
-
* Trigger fallback (Stage 2) when:
|
|
94
|
-
* 1. Input clearly contains JSON-like patterns but extraction failed
|
|
95
|
-
* 2. Detected common malformation patterns
|
|
96
|
-
* 3. Partial JSON detected but parsing failed
|
|
97
|
-
*
|
|
98
|
-
* DO NOT trigger fallback when:
|
|
99
|
-
* 1. Input genuinely contains no JSON (just text)
|
|
100
|
-
* 2. Fast path successfully extracted JSON
|
|
101
|
-
*/
|
|
102
|
-
private shouldUseFastPath(input: string, result: any): boolean {
|
|
103
|
-
// Success case: JSON was extracted
|
|
104
|
-
if (result.json.length > 0) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Check if input contains JSON-like patterns
|
|
109
|
-
const hasJsonPattern = this.detectJsonPattern(input);
|
|
110
|
-
|
|
111
|
-
// If no JSON-like patterns detected, input genuinely has no JSON
|
|
112
|
-
// Fast path succeeded (nothing to extract)
|
|
113
|
-
if (!hasJsonPattern) {
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Input has JSON-like patterns but extraction failed
|
|
118
|
-
// Trigger fallback (return false)
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Detect if input contains JSON-like patterns
|
|
124
|
-
* This helps distinguish between:
|
|
125
|
-
* - Input with no JSON (fast path success)
|
|
126
|
-
* - Input with malformed JSON (needs fallback)
|
|
127
|
-
*/
|
|
128
|
-
private detectJsonPattern(input: string): boolean {
|
|
129
|
-
// Check for common JSON indicators
|
|
130
|
-
const jsonIndicators = [
|
|
131
|
-
/\{[^}]*:/, // Object pattern: { "key":
|
|
132
|
-
/\[[^\]]*\{/, // Array of objects: [{
|
|
133
|
-
/:\s*["{\[]/, // Property with object/array/string value
|
|
134
|
-
/```json/i, // Markdown JSON code block
|
|
135
|
-
/"[^"]+"\s*:\s*/, // Quoted property name
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
return jsonIndicators.some(pattern => pattern.test(input));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
getStats() {
|
|
142
|
-
return {
|
|
143
|
-
...this.stats,
|
|
144
|
-
fastPathPercentage: (this.stats.fastPathSuccess /
|
|
145
|
-
(this.stats.fastPathSuccess + this.stats.fallbackPathUsed) * 100).toFixed(2) + '%'
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Example usage of two-stage parser
|
|
152
|
-
*/
|
|
153
|
-
function example1_TwoStageParsingDemo() {
|
|
154
|
-
console.log('=== Example 1: Two-Stage Parsing Strategy ===\n');
|
|
155
|
-
|
|
156
|
-
const parser = new TwoStageParser();
|
|
157
|
-
|
|
158
|
-
// Test Case 1: Well-formed JSON (fast path succeeds)
|
|
159
|
-
console.log('Test 1: Well-formed JSON');
|
|
160
|
-
const test1 = parser.parse('{"name": "John", "age": 30}');
|
|
161
|
-
console.log('Result:', test1);
|
|
162
|
-
console.log();
|
|
163
|
-
|
|
164
|
-
// Test Case 2: No JSON in input (fast path succeeds - nothing to extract)
|
|
165
|
-
console.log('Test 2: No JSON in input');
|
|
166
|
-
const test2 = parser.parse('This is just plain text without any JSON data');
|
|
167
|
-
console.log('Result:', test2);
|
|
168
|
-
console.log();
|
|
169
|
-
|
|
170
|
-
// Test Case 3: Malformed JSON (fast path fails, fallback succeeds)
|
|
171
|
-
console.log('Test 3: Malformed JSON (triggers fallback)');
|
|
172
|
-
const test3 = parser.parse('Here is data: {name: "John", age: 30}'); // Missing quotes on keys
|
|
173
|
-
console.log('Result:', test3);
|
|
174
|
-
console.log();
|
|
175
|
-
|
|
176
|
-
// Test Case 4: Multiple malformed objects
|
|
177
|
-
console.log('Test 4: Multiple malformed objects');
|
|
178
|
-
const test4 = parser.parse(`
|
|
179
|
-
First object: {id: 1, value: "test"}
|
|
180
|
-
Second object: {"id": 2, "value": "valid"}
|
|
181
|
-
Third object: {id: 3 value: "broken"}
|
|
182
|
-
`);
|
|
183
|
-
console.log('Result:', test4);
|
|
184
|
-
console.log();
|
|
185
|
-
|
|
186
|
-
console.log('Performance Stats:', parser.getStats());
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* EXAMPLE 2: Streaming/Chunked Input Handler
|
|
191
|
-
* Question 9: Handle real-time streaming text from LLM
|
|
192
|
-
*
|
|
193
|
-
* Challenge: LLM sends JSON in chunks, but .extract() needs complete strings
|
|
194
|
-
* Solution: Buffer chunks and detect JSON boundaries before extraction
|
|
195
|
-
*/
|
|
196
|
-
class StreamingJsonHandler {
|
|
197
|
-
private buffer: string = '';
|
|
198
|
-
private extractedObjects: any[] = [];
|
|
199
|
-
private llmJson: LlmJson;
|
|
200
|
-
|
|
201
|
-
constructor() {
|
|
202
|
-
this.llmJson = new LlmJson({ attemptCorrection: true });
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Process a chunk of streaming data
|
|
207
|
-
*
|
|
208
|
-
* Strategy:
|
|
209
|
-
* 1. Append chunk to buffer
|
|
210
|
-
* 2. Detect complete JSON objects in buffer
|
|
211
|
-
* 3. Extract complete objects
|
|
212
|
-
* 4. Keep incomplete data in buffer
|
|
213
|
-
*/
|
|
214
|
-
processChunk(chunk: string): {
|
|
215
|
-
extractedNow: any[];
|
|
216
|
-
bufferStatus: string;
|
|
217
|
-
totalExtracted: number;
|
|
218
|
-
} {
|
|
219
|
-
// Append chunk to buffer
|
|
220
|
-
this.buffer += chunk;
|
|
221
|
-
|
|
222
|
-
// Try to detect and extract complete JSON objects
|
|
223
|
-
const { extracted, remaining } = this.extractCompleteJson(this.buffer);
|
|
224
|
-
|
|
225
|
-
// Update buffer with remaining incomplete data
|
|
226
|
-
this.buffer = remaining;
|
|
227
|
-
|
|
228
|
-
// Store extracted objects
|
|
229
|
-
this.extractedObjects.push(...extracted);
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
extractedNow: extracted,
|
|
233
|
-
bufferStatus: this.getBufferStatus(),
|
|
234
|
-
totalExtracted: this.extractedObjects.length
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* CRITICAL: Detect complete JSON boundaries in stream
|
|
240
|
-
*
|
|
241
|
-
* Challenges:
|
|
242
|
-
* 1. Brace counting: Must match { and } pairs
|
|
243
|
-
* 2. String handling: Braces inside strings don't count
|
|
244
|
-
* 3. Nested objects: Track nesting depth
|
|
245
|
-
* 4. Multiple objects: May have multiple complete objects
|
|
246
|
-
*/
|
|
247
|
-
private extractCompleteJson(text: string): { extracted: any[]; remaining: string } {
|
|
248
|
-
const extracted: any[] = [];
|
|
249
|
-
let remaining = text;
|
|
250
|
-
let lastExtractedEnd = 0;
|
|
251
|
-
|
|
252
|
-
// Try to find complete JSON objects
|
|
253
|
-
while (true) {
|
|
254
|
-
const boundary = this.findNextCompleteJsonBoundary(remaining);
|
|
255
|
-
|
|
256
|
-
if (boundary === null) {
|
|
257
|
-
// No complete JSON found, keep in buffer
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Extract the complete JSON substring
|
|
262
|
-
const jsonString = remaining.substring(0, boundary.end);
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
// Use llm-json to parse the complete object
|
|
266
|
-
const result = this.llmJson.extract(jsonString);
|
|
267
|
-
if (result.json.length > 0) {
|
|
268
|
-
extracted.push(...result.json);
|
|
269
|
-
lastExtractedEnd = boundary.end;
|
|
270
|
-
remaining = remaining.substring(boundary.end);
|
|
271
|
-
} else {
|
|
272
|
-
// No valid JSON found, might be text
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
} catch (error) {
|
|
276
|
-
// Failed to parse, stop trying
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return {
|
|
282
|
-
extracted,
|
|
283
|
-
remaining: lastExtractedEnd > 0 ? text.substring(lastExtractedEnd) : text
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Find the boundary of the next complete JSON object
|
|
289
|
-
* Returns the end index if found, null otherwise
|
|
290
|
-
*/
|
|
291
|
-
private findNextCompleteJsonBoundary(text: string): { start: number; end: number } | null {
|
|
292
|
-
// Find first opening brace
|
|
293
|
-
const objectStart = text.indexOf('{');
|
|
294
|
-
const arrayStart = text.indexOf('[');
|
|
295
|
-
|
|
296
|
-
let start = -1;
|
|
297
|
-
let openChar = '';
|
|
298
|
-
let closeChar = '';
|
|
299
|
-
|
|
300
|
-
if (objectStart !== -1 && (arrayStart === -1 || objectStart < arrayStart)) {
|
|
301
|
-
start = objectStart;
|
|
302
|
-
openChar = '{';
|
|
303
|
-
closeChar = '}';
|
|
304
|
-
} else if (arrayStart !== -1) {
|
|
305
|
-
start = arrayStart;
|
|
306
|
-
openChar = '[';
|
|
307
|
-
closeChar = ']';
|
|
308
|
-
} else {
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Track brace depth
|
|
313
|
-
let depth = 0;
|
|
314
|
-
let inString = false;
|
|
315
|
-
let escapeNext = false;
|
|
316
|
-
|
|
317
|
-
for (let i = start; i < text.length; i++) {
|
|
318
|
-
const char = text[i];
|
|
319
|
-
|
|
320
|
-
// Handle string escaping
|
|
321
|
-
if (escapeNext) {
|
|
322
|
-
escapeNext = false;
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (char === '\\') {
|
|
327
|
-
escapeNext = true;
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Track string boundaries
|
|
332
|
-
if (char === '"') {
|
|
333
|
-
inString = !inString;
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Only count braces outside strings
|
|
338
|
-
if (!inString) {
|
|
339
|
-
if (char === openChar) {
|
|
340
|
-
depth++;
|
|
341
|
-
} else if (char === closeChar) {
|
|
342
|
-
depth--;
|
|
343
|
-
|
|
344
|
-
// Found complete JSON object
|
|
345
|
-
if (depth === 0) {
|
|
346
|
-
return { start, end: i + 1 };
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// No complete object found
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Get buffer status for debugging
|
|
358
|
-
*/
|
|
359
|
-
private getBufferStatus(): string {
|
|
360
|
-
if (this.buffer.length === 0) return 'empty';
|
|
361
|
-
if (this.buffer.trim().length === 0) return 'whitespace';
|
|
362
|
-
|
|
363
|
-
const hasOpenBrace = this.buffer.includes('{');
|
|
364
|
-
const hasCloseBrace = this.buffer.includes('}');
|
|
365
|
-
|
|
366
|
-
if (hasOpenBrace && !hasCloseBrace) return 'incomplete object';
|
|
367
|
-
if (hasOpenBrace && hasCloseBrace) return 'potential complete object';
|
|
368
|
-
|
|
369
|
-
return `buffering (${this.buffer.length} chars)`;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Finalize stream - try to extract any remaining data
|
|
374
|
-
*/
|
|
375
|
-
finalize(): any[] {
|
|
376
|
-
if (this.buffer.trim().length > 0) {
|
|
377
|
-
try {
|
|
378
|
-
const result = this.llmJson.extract(this.buffer);
|
|
379
|
-
this.extractedObjects.push(...result.json);
|
|
380
|
-
} catch (error) {
|
|
381
|
-
console.warn('Failed to parse remaining buffer:', this.buffer);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
return this.extractedObjects;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
getExtracted(): any[] {
|
|
388
|
-
return this.extractedObjects;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
getBuffer(): string {
|
|
392
|
-
return this.buffer;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Example usage of streaming handler
|
|
398
|
-
*/
|
|
399
|
-
function example2_StreamingJsonDemo() {
|
|
400
|
-
console.log('\n\n=== Example 2: Streaming JSON Handler ===\n');
|
|
401
|
-
|
|
402
|
-
const handler = new StreamingJsonHandler();
|
|
403
|
-
|
|
404
|
-
// Simulate streaming chunks
|
|
405
|
-
const chunks = [
|
|
406
|
-
'{ "key": "val', // Incomplete object start
|
|
407
|
-
'ue1", "anoth', // Middle of object
|
|
408
|
-
'erKey": 123 }', // Object complete
|
|
409
|
-
' Some text ', // Text between objects
|
|
410
|
-
'{"second": "obj', // Second object starts
|
|
411
|
-
'ect", "num": 456}' // Second object complete
|
|
412
|
-
];
|
|
413
|
-
|
|
414
|
-
console.log('Processing streaming chunks:\n');
|
|
415
|
-
|
|
416
|
-
chunks.forEach((chunk, index) => {
|
|
417
|
-
console.log(`Chunk ${index + 1}: "${chunk}"`);
|
|
418
|
-
const result = handler.processChunk(chunk);
|
|
419
|
-
console.log(' Extracted now:', result.extractedNow);
|
|
420
|
-
console.log(' Buffer status:', result.bufferStatus);
|
|
421
|
-
console.log(' Total extracted:', result.totalExtracted);
|
|
422
|
-
console.log();
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
const final = handler.finalize();
|
|
426
|
-
console.log('Final extracted objects:', JSON.stringify(final, null, 2));
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* EXAMPLE 3: Detecting Parse Failures vs Empty Input
|
|
431
|
-
* Question 10: How to distinguish between failure and genuinely no JSON
|
|
432
|
-
*/
|
|
433
|
-
function example3_DetectingParseFailures() {
|
|
434
|
-
console.log('\n\n=== Example 3: Detecting Parse Failures vs Empty Input ===\n');
|
|
435
|
-
|
|
436
|
-
const llmJson = new LlmJson({ attemptCorrection: false });
|
|
437
|
-
|
|
438
|
-
// Test cases
|
|
439
|
-
const testCases = [
|
|
440
|
-
{
|
|
441
|
-
name: 'Valid JSON',
|
|
442
|
-
input: '{"name": "test"}',
|
|
443
|
-
expected: 'success'
|
|
444
|
-
},
|
|
445
|
-
{
|
|
446
|
-
name: 'No JSON (just text)',
|
|
447
|
-
input: 'This is plain text without any JSON',
|
|
448
|
-
expected: 'no_json'
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
name: 'Malformed JSON',
|
|
452
|
-
input: '{name: "test"}', // Missing quotes on key
|
|
453
|
-
expected: 'parse_failure'
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
name: 'Incomplete JSON',
|
|
457
|
-
input: '{"name": "test"', // Missing closing brace
|
|
458
|
-
expected: 'parse_failure'
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
name: 'Empty string',
|
|
462
|
-
input: '',
|
|
463
|
-
expected: 'no_json'
|
|
464
|
-
}
|
|
465
|
-
];
|
|
466
|
-
|
|
467
|
-
testCases.forEach(test => {
|
|
468
|
-
const result = llmJson.extract(test.input);
|
|
469
|
-
const diagnosis = diagnoseResult(test.input, result);
|
|
470
|
-
|
|
471
|
-
console.log(`\nTest: ${test.name}`);
|
|
472
|
-
console.log(`Input: "${test.input}"`);
|
|
473
|
-
console.log(`Expected: ${test.expected}`);
|
|
474
|
-
console.log(`Diagnosed: ${diagnosis.status}`);
|
|
475
|
-
console.log(`Reasoning: ${diagnosis.reason}`);
|
|
476
|
-
console.log(`Match: ${diagnosis.status === test.expected ? '✅' : '❌'}`);
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Diagnose extraction result to determine:
|
|
482
|
-
* - Success: JSON was extracted
|
|
483
|
-
* - No JSON: Input genuinely contains no JSON
|
|
484
|
-
* - Parse Failure: Input has JSON-like content but parsing failed
|
|
485
|
-
*/
|
|
486
|
-
function diagnoseResult(input: string, result: any): { status: string; reason: string } {
|
|
487
|
-
// Case 1: Extraction succeeded
|
|
488
|
-
if (result.json.length > 0) {
|
|
489
|
-
return {
|
|
490
|
-
status: 'success',
|
|
491
|
-
reason: `Successfully extracted ${result.json.length} JSON object(s)`
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// Case 2: No extraction, but does input contain JSON-like patterns?
|
|
496
|
-
const jsonPatterns = [
|
|
497
|
-
/\{[^}]*:/, // Object pattern
|
|
498
|
-
/\[[^\]]*\{/, // Array with object
|
|
499
|
-
/```json/i, // Markdown code block
|
|
500
|
-
/"[^"]+"\s*:\s*/, // Quoted property
|
|
501
|
-
];
|
|
502
|
-
|
|
503
|
-
const hasJsonLikeContent = jsonPatterns.some(pattern => pattern.test(input));
|
|
504
|
-
|
|
505
|
-
if (!hasJsonLikeContent) {
|
|
506
|
-
return {
|
|
507
|
-
status: 'no_json',
|
|
508
|
-
reason: 'Input contains no JSON-like patterns'
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// Case 3: Has JSON-like patterns but extraction failed
|
|
513
|
-
return {
|
|
514
|
-
status: 'parse_failure',
|
|
515
|
-
reason: 'Input contains JSON-like patterns but extraction failed (likely malformed)'
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// Run all examples
|
|
520
|
-
if (require.main === module) {
|
|
521
|
-
example1_TwoStageParsingDemo();
|
|
522
|
-
example2_StreamingJsonDemo();
|
|
523
|
-
example3_DetectingParseFailures();
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
export {
|
|
527
|
-
TwoStageParser,
|
|
528
|
-
StreamingJsonHandler,
|
|
529
|
-
example1_TwoStageParsingDemo,
|
|
530
|
-
example2_StreamingJsonDemo,
|
|
531
|
-
example3_DetectingParseFailures,
|
|
532
|
-
diagnoseResult
|
|
533
|
-
};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import LlmJson from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example demonstrating how to use the LLM-JSON library for arrays.
|
|
5
|
-
*/
|
|
6
|
-
function runArrayExample() {
|
|
7
|
-
// Create an instance with auto-correction enabled
|
|
8
|
-
const llmJson = new LlmJson({ attemptCorrection: true });
|
|
9
|
-
|
|
10
|
-
// Simple array example
|
|
11
|
-
const simpleArrayInput = `Here is a list of names: ["John", "Jane", "Bob"]`;
|
|
12
|
-
|
|
13
|
-
console.log("=== Simple Array Example ===");
|
|
14
|
-
|
|
15
|
-
// Using extract - might not properly handle standalone arrays
|
|
16
|
-
const simpleExtractResult = llmJson.extract(simpleArrayInput);
|
|
17
|
-
console.log("With extract():");
|
|
18
|
-
console.log("Text:", simpleExtractResult.text);
|
|
19
|
-
console.log("JSON:", JSON.stringify(simpleExtractResult.json, null, 2));
|
|
20
|
-
console.log();
|
|
21
|
-
|
|
22
|
-
// Using extractAll - properly handles arrays
|
|
23
|
-
const simpleExtractAllResult = llmJson.extractAll(simpleArrayInput);
|
|
24
|
-
console.log("With extractAll():");
|
|
25
|
-
console.log("Text:", simpleExtractAllResult.text);
|
|
26
|
-
console.log("JSON:", JSON.stringify(simpleExtractAllResult.json, null, 2));
|
|
27
|
-
console.log();
|
|
28
|
-
|
|
29
|
-
// Complex array example
|
|
30
|
-
const complexArrayInput = `Here's an array of users:
|
|
31
|
-
[
|
|
32
|
-
{
|
|
33
|
-
"name": "John Doe",
|
|
34
|
-
"age": 30,
|
|
35
|
-
"skills": ["JavaScript", "TypeScript"]
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"name": "Jane Smith",
|
|
39
|
-
"age": 28,
|
|
40
|
-
"skills": ["Python", "Machine Learning"]
|
|
41
|
-
}
|
|
42
|
-
]`;
|
|
43
|
-
|
|
44
|
-
console.log("=== Complex Array Example ===");
|
|
45
|
-
|
|
46
|
-
// Using extractAll - properly handles complex arrays
|
|
47
|
-
const complexResult = llmJson.extractAll(complexArrayInput);
|
|
48
|
-
console.log("With extractAll():");
|
|
49
|
-
console.log("Text:", complexResult.text);
|
|
50
|
-
console.log("JSON:", JSON.stringify(complexResult.json, null, 2));
|
|
51
|
-
console.log();
|
|
52
|
-
|
|
53
|
-
// Multiple JSON structures example
|
|
54
|
-
const mixedInput = `Here's an object: {"name": "John", "age": 30}
|
|
55
|
-
|
|
56
|
-
And here's an array: [1, 2, 3, 4, 5]
|
|
57
|
-
|
|
58
|
-
And another object: {"city": "New York", "country": "USA"}`;
|
|
59
|
-
|
|
60
|
-
console.log("=== Mixed JSON Types Example ===");
|
|
61
|
-
|
|
62
|
-
// Using extractAll - handles both objects and arrays
|
|
63
|
-
const mixedResult = llmJson.extractAll(mixedInput);
|
|
64
|
-
console.log("With extractAll():");
|
|
65
|
-
console.log("Text:", mixedResult.text);
|
|
66
|
-
console.log("JSON:", JSON.stringify(mixedResult.json, null, 2));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
runArrayExample();
|
package/examples/example.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import LlmJson from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example demonstrating how to use the LLM-JSON library.
|
|
5
|
-
*/
|
|
6
|
-
function runExample() {
|
|
7
|
-
// Create an instance with auto-correction enabled
|
|
8
|
-
const llmJson = new LlmJson({ attemptCorrection: true });
|
|
9
|
-
|
|
10
|
-
// Example from the requirements
|
|
11
|
-
const input = `<research_planning>
|
|
12
|
-
a. Summary: The given organization is unnamed and works in the area of "something new," which suggests an innovative or emerging field. This could involve novel technologies, fresh market approaches, or unexplored domains. Without specific details, assumptions about the sector or industry may involve startups, tech innovation, or trendsetting industries. The focus and goals may lean toward exploration, user adoption, and refinement of novel concepts.
|
|
13
|
-
|
|
14
|
-
b. Potential Product Features:
|
|
15
|
-
- Exploration of new technologies (VR/AR interfaces, IoT integration)
|
|
16
|
-
- User onboarding and education tools
|
|
17
|
-
- Novel interaction models or user interfaces
|
|
18
|
-
- Feedback and improvement loops
|
|
19
|
-
- Community engagement and collaboration spaces
|
|
20
|
-
|
|
21
|
-
c. User Persona: Considering the organization's innovative nature, the primary user could be an early adopter, tech-savvy individual who is curious and willing to explore new technologies. This persona is likely someone who enjoys experimenting with novel ideas and is motivated by the excitement of participating in pioneering efforts.
|
|
22
|
-
Study Name: "Demo - Innovator Insight"
|
|
23
|
-
|
|
24
|
-
d. Potential Research Objectives:
|
|
25
|
-
- Evaluate user onboarding process effectiveness in helping users understand the product's novel features.
|
|
26
|
-
- Assess user engagement with community collaboration spaces to identify areas for increased interaction.
|
|
27
|
-
- Verify the intuitiveness of new interaction models and user interfaces.
|
|
28
|
-
- Explore user satisfaction with feedback and improvement loops.
|
|
29
|
-
- Measure the impact of educational tools on user empowerment and confidence.
|
|
30
|
-
- Analyze user behavior patterns to refine product workflows.
|
|
31
|
-
- Investigate potential barriers to user adoption and retention.
|
|
32
|
-
|
|
33
|
-
e. Narrowing Down Objectives:
|
|
34
|
-
After considering the potential research objectives, the focus shifted towards objectives that can be directly evaluated through a live web application. The final objectives chosen were geared towards user onboarding, interaction intuitiveness, and community engagement, as they align with the persona of an early adopter and focus on improving user experience in areas relevant to the organization's innovative nature.
|
|
35
|
-
</research_planning>
|
|
36
|
-
|
|
37
|
-
\`\`\`json
|
|
38
|
-
{
|
|
39
|
-
"studyName": "Demo - Innovator Insight",
|
|
40
|
-
"userPersona": "Tech-savvy early adopter exploring new innovations.",
|
|
41
|
-
"objectives": [
|
|
42
|
-
{
|
|
43
|
-
"objectiveTitle": "Onboarding Process Evaluation",
|
|
44
|
-
"objectiveDescription": "Assess the effectiveness of the user onboarding process in enabling users to grasp the novel features of the product quickly and efficiently, ensuring that it enhances initial user engagement and reduces learning curves."
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"objectiveTitle": "Community Interaction Analysis",
|
|
48
|
-
"objectiveDescription": "Investigate user engagement within community collaboration spaces, identifying potential improvements to foster more interaction, sharing, and collaboration among users, enhancing overall community dynamics."
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"objectiveTitle": "Interface Intuition Verification",
|
|
52
|
-
"objectiveDescription": "Verify the intuitiveness of new interaction models and user interfaces, focusing on how users adapt and navigate through the product, aiming to identify any areas needing refinement for better usability."
|
|
53
|
-
}
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
\`\`\``;
|
|
57
|
-
|
|
58
|
-
// Extract JSON and text
|
|
59
|
-
const result = llmJson.extract(input);
|
|
60
|
-
|
|
61
|
-
console.log("Extracted text:");
|
|
62
|
-
console.log("------------------");
|
|
63
|
-
result.text.forEach((text, index) => {
|
|
64
|
-
console.log(`Text block ${index + 1}:`);
|
|
65
|
-
console.log(text);
|
|
66
|
-
console.log();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
console.log("Extracted JSON:");
|
|
70
|
-
console.log("------------------");
|
|
71
|
-
result.json.forEach((json, index) => {
|
|
72
|
-
console.log(`JSON object ${index + 1}:`);
|
|
73
|
-
console.log(JSON.stringify(json, null, 2));
|
|
74
|
-
console.log();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Example with malformed JSON
|
|
78
|
-
console.log("\nExample with malformed JSON:");
|
|
79
|
-
console.log("---------------------------");
|
|
80
|
-
|
|
81
|
-
const malformedInput = `Here is some information:
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
name: "John",
|
|
85
|
-
age: 30,
|
|
86
|
-
skills: ["JavaScript", "TypeScript"],
|
|
87
|
-
preferences: {
|
|
88
|
-
theme: "dark",
|
|
89
|
-
notifications: true,
|
|
90
|
-
}
|
|
91
|
-
}`;
|
|
92
|
-
|
|
93
|
-
const malformedResult = llmJson.extract(malformedInput);
|
|
94
|
-
|
|
95
|
-
console.log("Text:");
|
|
96
|
-
console.log(malformedResult.text[0]);
|
|
97
|
-
console.log("\nCorrected JSON:");
|
|
98
|
-
console.log(JSON.stringify(malformedResult.json[0], null, 2));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
runExample();
|