diff --git a/src/routes/learningAI.js b/src/routes/learningAI.js index 86f6526..8b18b55 100644 --- a/src/routes/learningAI.js +++ b/src/routes/learningAI.js @@ -242,22 +242,44 @@ router.post('/ai-generate', upload.single('file'), async function(req, res) { var lastBrace = raw.lastIndexOf('}'); if (lastBrace !== -1 && lastBrace < raw.length - 1) raw = raw.substring(0, lastBrace + 1); + // Fix unescaped control characters inside JSON string values. + // Models sometimes output literal newlines/tabs inside strings instead of \n \t. + function sanitizeJsonString(s) { + var inStr = false, escaped = false, out = ''; + for (var i = 0; i < s.length; i++) { + var c = s[i]; + if (escaped) { out += c; escaped = false; continue; } + if (c === '\\' && inStr) { out += c; escaped = true; continue; } + if (c === '"') { inStr = !inStr; out += c; continue; } + if (inStr && c === '\n') { out += '\\n'; continue; } + if (inStr && c === '\r') { continue; } + if (inStr && c === '\t') { out += '\\t'; continue; } + out += c; + } + return out; + } + var parsed; try { parsed = JSON.parse(raw); } catch (e) { - // Try extracting from first { to last } - var firstBrace = raw.indexOf('{'); - var extractedJson = firstBrace >= 0 ? raw.substring(firstBrace, lastBrace + 1) : null; - if (extractedJson) { - try { parsed = JSON.parse(extractedJson); } - catch (e2) { - console.error('[LearningAI] JSON parse failed. Raw (first 500):', raw.substring(0, 500)); + console.error('[LearningAI] Direct parse failed:', e.message, '| Pos:', e.message.match(/position (\d+)/)?.[1], '| Char context:', raw.substring(parseInt(e.message.match(/position (\d+)/)?.[1] || 0) - 40, parseInt(e.message.match(/position (\d+)/)?.[1] || 0) + 40)); + // Attempt 2: sanitize control chars and retry + try { parsed = JSON.parse(sanitizeJsonString(raw)); } + catch (e2) { + // Attempt 3: extract first { to last } + var firstBrace = raw.indexOf('{'); + var extractedJson = firstBrace >= 0 ? raw.substring(firstBrace, lastBrace + 1) : null; + if (extractedJson) { + try { parsed = JSON.parse(sanitizeJsonString(extractedJson)); } + catch (e3) { + console.error('[LearningAI] All parse attempts failed:', e3.message); + return res.status(500).json({ error: 'AI returned invalid JSON. Try again.' }); + } + } else { + console.error('[LearningAI] No JSON braces found'); return res.status(500).json({ error: 'AI returned invalid JSON. Try again.' }); } - } else { - console.error('[LearningAI] No JSON found. Raw (first 500):', raw.substring(0, 500)); - return res.status(500).json({ error: 'AI returned invalid JSON. Try again.' }); } }