const fs = require('fs'); const content = fs.readFileSync('temp/rich-outline-fail_57_1779015509994.txt', 'utf-8'); const marker = '========== AI εŽŸε§‹ε“εΊ” '; const markerIdx = content.indexOf(marker); const headerEndIdx = content.indexOf(' ==========', markerIdx); const aiStart = content.indexOf('\n', headerEndIdx) + 1; const aiEnd = content.indexOf('\n\n', aiStart); const aiResponse = content.substring(aiStart, aiEnd); console.log('Length:', aiResponse.length); // Goal: Find the chapters that are COMPLETE (both opening and closing braces) // by finding the last position where we have a valid chapter object // Strategy: Find all "chapters": [ patterns, then find where each chapter ends // A chapter ends when we see "}," or "]," patterns that close the chapter object // Actually, let's try a different approach: find the last complete "number":X in a chapters array // and work backwards to find the full chapter // First, find where chapters array starts const chaptersStart = aiResponse.indexOf('"chapters":['); console.log('Chapters array starts at:', chaptersStart); if (chaptersStart === -1) { console.log('No chapters array found'); process.exit(1); } // Try to find where the JSON becomes invalid - that's our truncation point // Then extract all chapters before that let lastGoodPos = chaptersStart; let braceLevel = 0; let inString = false; let escapeNext = false; for (let i = chaptersStart; i < aiResponse.length; i++) { const ch = aiResponse[i]; if (escapeNext) { escapeNext = false; continue; } if (ch === '\\') { escapeNext = true; continue; } if (ch === '"') { inString = !inString; continue; } if (inString) continue; if (ch === '{') braceLevel++; else if (ch === '}') braceLevel--; else if (ch === '[') braceLevel++; else if (ch === ']') braceLevel--; if (braceLevel < 0) { console.log('JSON goes negative at position', i, '- char', JSON.stringify(ch)); break; } // Try to parse up to this point const sub = '{"outline":' + aiResponse.substring(chaptersStart, i + 1) + '}'; try { JSON.parse(sub); lastGoodPos = i + 1; } catch(e) { // If it fails because braces are unbalanced, that's ok - we might be mid-chapter if (!e.message.includes('Unexpected end')) { // Some other error } } } console.log('Last position where prefix might be valid:', lastGoodPos); console.log('Prefix length:', lastGoodPos - chaptersStart); // Try to extract the complete chapters from the prefix const prefix = '{"outline":{"chapters":' + aiResponse.substring(chaptersStart + 13, lastGoodPos) + '}}'; console.log('\nTrying to parse prefix as complete outline...'); try { const data = JSON.parse(prefix); console.log('SUCCESS! Chapters:', data.outline?.chapters?.length); if (data.outline?.chapters?.length > 0) { console.log('First chapter:', data.outline.chapters[0].title); console.log('Last chapter:', data.outline.chapters[data.outline.chapters.length - 1].title); } } catch(e) { console.log('FAILED:', e.message.substring(0, 100)); // Try a more aggressive approach - just extract complete chapter objects console.log('\n=== Trying chapter-by-chapter extraction ==='); // Find all occurrences of "number":N where N is a number const chapterNumRegex = /"number":(\d+)/g; let match; let chapters = []; let lastEnd = chaptersStart + 13; // After "chapters":[ while ((match = chapterNumRegex.exec(aiResponse)) !== null) { const num = parseInt(match[1]); const startPos = match.index; // Find the end of this chapter - look for }], or }},{ patterns let endSearchStart = startPos + match[0].length; // Find the next "number": pattern or end of chapters array const nextNumMatch = chapterNumRegex.exec(aiResponse.substring(endSearchStart)); const endPos = nextNumMatch ? endSearchStart + nextNumMatch.index : aiResponse.lastIndexOf(']}', aiResponse.length); const chapterJson = '{"number":' + num + aiResponse.substring(startPos + 9, endPos); try { const chapter = JSON.parse(chapterJson); if (chapter.title && chapter.summary) { chapters.push(chapter); console.log('Found chapter', num + ':', chapter.title, 'length:', chapterJson.length); } } catch(e) { console.log('Chapter', num, 'parse failed:', e.message.substring(0, 50)); } } console.log('\nTotal complete chapters found:', chapters.length); }