fix: Improve n8n chat response parsing
All checks were successful
Dev Deployment (Zero Downtime) / deploy-dev (push) Successful in 13m6s

- Add comprehensive parsing for various n8n response formats
- Check multiple field names (reply, message, response, text, content, answer, output, result)
- Handle array responses and nested structures (data, json, items)
- Add recursive search for string values in complex objects
- Improve logging to show full n8n response structure
- Only use fallback if truly no response found
This commit is contained in:
2026-01-09 18:10:51 +01:00
parent 42a586d183
commit c5b607a253

View File

@@ -73,35 +73,108 @@ export async function POST(request: NextRequest) {
const data = await response.json(); const data = await response.json();
console.log("n8n response data:", data); console.log("n8n response data (full):", JSON.stringify(data, null, 2));
console.log("n8n response data type:", typeof data);
console.log("n8n response is array:", Array.isArray(data));
const reply = // Try multiple ways to extract the reply
data.reply || let reply: string | undefined = undefined;
data.message ||
data.response ||
data.text ||
data.content ||
(Array.isArray(data) && data[0]?.reply);
if (!reply) { // Direct fields
console.warn("n8n response missing reply field:", data); if (data.reply) reply = data.reply;
// If n8n returns successfully but without a clear reply field, else if (data.message) reply = data.message;
// we might want to show the fallback or a generic error, else if (data.response) reply = data.response;
// but strictly speaking we shouldn't show "Couldn't process". else if (data.text) reply = data.text;
// Let's try to stringify the whole data if it's small, or use fallback. else if (data.content) reply = data.content;
if (data && typeof data === "object" && Object.keys(data).length > 0) { else if (data.answer) reply = data.answer;
// It returned something, but we don't know what field to use. else if (data.output) reply = data.output;
// Check for common n8n structure else if (data.result) reply = data.result;
if (data.output) {
const decoded = decodeHtmlEntitiesServer(String(data.output)); // Array handling
return NextResponse.json({ reply: decoded }); else if (Array.isArray(data) && data.length > 0) {
} const firstItem = data[0];
if (data.data) { if (typeof firstItem === 'string') {
const decoded = decodeHtmlEntitiesServer(String(data.data)); reply = firstItem;
return NextResponse.json({ reply: decoded }); } else if (typeof firstItem === 'object') {
reply = firstItem.reply || firstItem.message || firstItem.response ||
firstItem.text || firstItem.content || firstItem.answer ||
firstItem.output || firstItem.result;
}
}
// Nested structures (common in n8n)
else if (data && typeof data === "object") {
// Check nested data field
if (data.data) {
if (typeof data.data === 'string') {
reply = data.data;
} else if (typeof data.data === 'object') {
reply = data.data.reply || data.data.message || data.data.response ||
data.data.text || data.data.content || data.data.answer;
} }
} }
throw new Error("Invalid response format from n8n");
// Check nested json field
if (!reply && data.json) {
if (typeof data.json === 'string') {
reply = data.json;
} else if (typeof data.json === 'object') {
reply = data.json.reply || data.json.message || data.json.response ||
data.json.text || data.json.content || data.json.answer;
}
}
// Check items array (n8n often wraps in items)
if (!reply && Array.isArray(data.items) && data.items.length > 0) {
const firstItem = data.items[0];
if (typeof firstItem === 'string') {
reply = firstItem;
} else if (typeof firstItem === 'object') {
reply = firstItem.reply || firstItem.message || firstItem.response ||
firstItem.text || firstItem.content || firstItem.answer ||
firstItem.json?.reply || firstItem.json?.message;
}
}
// Last resort: if it's a single string value object, try to extract
if (!reply && Object.keys(data).length === 1) {
const value = Object.values(data)[0];
if (typeof value === 'string') {
reply = value;
}
}
// If still no reply but data exists, stringify it (for debugging)
if (!reply && Object.keys(data).length > 0) {
console.warn("n8n response structure not recognized, attempting to extract any string value");
// Try to find any string value in the object
const findStringValue = (obj: unknown): string | undefined => {
if (typeof obj === 'string' && obj.length > 0) return obj;
if (Array.isArray(obj) && obj.length > 0) {
return findStringValue(obj[0]);
}
if (obj && typeof obj === 'object' && obj !== null) {
const objRecord = obj as Record<string, unknown>;
for (const key of ['reply', 'message', 'response', 'text', 'content', 'answer', 'output', 'result']) {
if (objRecord[key] && typeof objRecord[key] === 'string') {
return objRecord[key] as string;
}
}
// Recursively search
for (const value of Object.values(objRecord)) {
const found = findStringValue(value);
if (found) return found;
}
}
return undefined;
};
reply = findStringValue(data);
}
}
if (!reply) {
console.error("n8n response missing reply field. Full response:", JSON.stringify(data, null, 2));
throw new Error("Invalid response format from n8n - no reply field found");
} }
// Decode HTML entities in the reply // Decode HTML entities in the reply