Email / src /output-parsers /json-parser.js
lenzcom's picture
Upload folder using huggingface_hub
e706de2 verified
import { BaseOutputParser, OutputParserException } from './base-parser.js';
/**
* Parser that extracts JSON from LLM output
* Handles markdown code blocks and extra text
*
* Example:
* const parser = new JsonOutputParser();
* const result = await parser.parse('```json\n{"name": "Alice"}\n```');
* // { name: "Alice" }
*/
export class JsonOutputParser extends BaseOutputParser {
constructor(options = {}) {
super();
this.schema = options.schema;
}
/**
* Parse JSON from text
*/
async parse(text) {
try {
// Try to extract JSON from the text
const jsonText = this._extractJson(text);
const parsed = JSON.parse(jsonText);
// Validate against schema if provided
if (this.schema) {
this._validateSchema(parsed);
}
return parsed;
} catch (error) {
throw new OutputParserException(
`Failed to parse JSON: ${error.message}`,
text,
error
);
}
}
/**
* Extract JSON from text (handles markdown, extra text)
*/
_extractJson(text) {
// Try direct parse first
try {
JSON.parse(text.trim());
return text.trim();
} catch {
// Not direct JSON, try to find it
}
// Look for JSON in markdown code blocks
const markdownMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
if (markdownMatch) {
return markdownMatch[1].trim();
}
// Look for JSON object/array patterns
const jsonObjectMatch = text.match(/\{[\s\S]*\}/);
if (jsonObjectMatch) {
return jsonObjectMatch[0];
}
const jsonArrayMatch = text.match(/\[[\s\S]*\]/);
if (jsonArrayMatch) {
return jsonArrayMatch[0];
}
// Give up, return original
return text.trim();
}
/**
* Validate parsed JSON against schema
*/
_validateSchema(parsed) {
if (!this.schema) return;
for (const [key, type] of Object.entries(this.schema)) {
if (!(key in parsed)) {
throw new Error(`Missing required field: ${key}`);
}
const actualType = typeof parsed[key];
if (actualType !== type) {
throw new Error(
`Field ${key} should be ${type}, got ${actualType}`
);
}
}
}
getFormatInstructions() {
let instructions = 'Respond with valid JSON.';
if (this.schema) {
const schemaDesc = Object.entries(this.schema)
.map(([key, type]) => `"${key}": ${type}`)
.join(', ');
instructions += ` Schema: { ${schemaDesc} }`;
}
return instructions;
}
}