From 783c03659477cd9c50c305d35a90b62799c2e7a6 Mon Sep 17 00:00:00 2001 From: Andrew Patton Date: Thu, 21 Mar 2024 16:43:15 -0700 Subject: [PATCH] Update parsePartialJSON to handle trailing commas --- packages/parsing/src/as-json.test.ts | 34 ++++++++++++++++++++++++++++ packages/parsing/src/as-json.ts | 11 ++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/packages/parsing/src/as-json.test.ts b/packages/parsing/src/as-json.test.ts index a74380a8..dc72211a 100644 --- a/packages/parsing/src/as-json.test.ts +++ b/packages/parsing/src/as-json.test.ts @@ -72,6 +72,40 @@ Here is the JSON output for the "About Us" page based on the provided props: }); }); + it('should handle JSON with trailing comma-separators', () => { + const response = `\ + { + "sectionTitle": "Meet the Team", + "item1Content": "Tom Ryder - Owner & Wine Director", + "item1AttributionLine1": "Learn more about Tom's passion for wine and his journey to opening Ryders", + "item1AttributionLine2": "Read about Tom's experience in the wine industry and his approach to curating Ryders' wine list", + "item2Content": "Sarah Johnson - Wine Educator", + "item2AttributionLine1": "Discover Sarah's background in wine and her role in educating customers at Ryders", + "item2AttributionLine2": "Learn about Sarah's favorite wine pairings and her recommendations for beginners", + "item3Content": "Mike Smith - Cheese Specialist", + "item3AttributionLine1": "Find out more about Mike's expertise in cheese and his role in curating Ryders' selection", + "item3AttributionLine2": "Read about Mike's favorite cheese pairings and his recommendations for unique flavor combinations", + }`; + expect(asJSON(response)).toEqual({ + item1AttributionLine1: + "Learn more about Tom's passion for wine and his journey to opening Ryders", + item1AttributionLine2: + "Read about Tom's experience in the wine industry and his approach to curating Ryders' wine list", + item1Content: 'Tom Ryder - Owner & Wine Director', + item2AttributionLine1: + "Discover Sarah's background in wine and her role in educating customers at Ryders", + item2AttributionLine2: + "Learn about Sarah's favorite wine pairings and her recommendations for beginners", + item2Content: 'Sarah Johnson - Wine Educator', + item3AttributionLine1: + "Find out more about Mike's expertise in cheese and his role in curating Ryders' selection", + item3AttributionLine2: + "Read about Mike's favorite cheese pairings and his recommendations for unique flavor combinations", + item3Content: 'Mike Smith - Cheese Specialist', + sectionTitle: 'Meet the Team', + }); + }); + it('should strip invalid JSON when the LLM response goes off the rails', () => { const response = `\ Here is the JSON output for the "Meet the Team" page: diff --git a/packages/parsing/src/as-json.ts b/packages/parsing/src/as-json.ts index 133797f4..4c06148d 100644 --- a/packages/parsing/src/as-json.ts +++ b/packages/parsing/src/as-json.ts @@ -49,14 +49,19 @@ export const parsePartialJSON = (text: string) => { stack.pop(); } else { // Mismatched closing character; the input is malformed. - // If this is the last character in the text, remove it, else return null. + // If this is the last character in the text, just remove it. + // Otherwise, return null. if (index === text.length - 1) { - console.log('mismatched closing character', char); char = ''; } else { return null; } } + } else if (char === ',') { + // If this is a trailing comma, remove it. + if (/^[^"]*[\]}]/.test(text.slice(index + 1))) { + char = ''; + } } } @@ -64,7 +69,7 @@ export const parsePartialJSON = (text: string) => { newText += char; } - // If we're still inside a string at the end of processing, + // If we’re still inside a string at the end of processing, // we need to close the string. if (isInsideString) { newText += '"';