fix: Improve n8n chat response parsing
All checks were successful
Dev Deployment (Zero Downtime) / deploy-dev (push) Successful in 13m6s
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:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user