Explorar el Código

udpate for graph display

enzo hace 5 días
padre
commit
cb0245f197
Se han modificado 1 ficheros con 68 adiciones y 1 borrados
  1. 68 1
      src/palm-oil/vision.gateway.ts

+ 68 - 1
src/palm-oil/vision.gateway.ts

@@ -73,6 +73,26 @@ interface ChatPayload {
   message: string;
 }
 
+// ─── n8n intelligent-response schema ────────────────────────────────────────
+
+interface ChatVisualDataset {
+  label: string;
+  data: number[];
+}
+
+interface ChatVisualData {
+  type: string;
+  title: string;
+  labels: string[];
+  datasets: ChatVisualDataset[];
+}
+
+interface ChatResponse {
+  text: string;
+  has_visuals: boolean;
+  visual_data: ChatVisualData | null;
+}
+
 interface HistoryDeletePayload {
   archiveId: string;
 }
@@ -95,6 +115,53 @@ interface EdgeResultPayload {
 
 const N8N_WEBHOOK_URL = process.env['N8N_WEBHOOK_URL'] ?? '';
 
+/**
+ * n8n's AI agent node is only allowed to emit text — the enforced JSON schema
+ * (text/has_visuals/visual_data) arrives as a *string* inside `output` (or
+ * `text`/`message`, depending on node config), sometimes fenced in ```json.
+ * This normalizes whatever shape comes back into a strict ChatResponse.
+ */
+function normalizeChatResponse(raw: any): ChatResponse {
+  const node = Array.isArray(raw) ? raw[0] : raw;
+
+  const candidate =
+    node && typeof node === 'object'
+      ? (node.text !== undefined || node.has_visuals !== undefined
+          ? node
+          : (node.output ?? node.message ?? node))
+      : node;
+
+  let parsed: any = candidate;
+  if (typeof candidate === 'string') {
+    const unfenced = candidate.trim().replace(/^```json\s*|```$/g, '').trim();
+    try {
+      parsed = JSON.parse(unfenced);
+    } catch {
+      parsed = { text: candidate };
+    }
+  }
+
+  if (!parsed || typeof parsed !== 'object') {
+    parsed = { text: String(parsed ?? '') };
+  }
+
+  const visualData: ChatVisualData | null =
+    parsed.has_visuals && parsed.visual_data
+      ? {
+          type: String(parsed.visual_data.type ?? 'bar'),
+          title: String(parsed.visual_data.title ?? ''),
+          labels: Array.isArray(parsed.visual_data.labels) ? parsed.visual_data.labels : [],
+          datasets: Array.isArray(parsed.visual_data.datasets) ? parsed.visual_data.datasets : [],
+        }
+      : null;
+
+  return {
+    text: String(parsed.text ?? parsed.output ?? parsed.message ?? ''),
+    has_visuals: Boolean(parsed.has_visuals && visualData),
+    visual_data: visualData,
+  };
+}
+
 // ─── Gateway ──────────────────────────────────────────────────────────────────
 
 @WebSocketGateway({
@@ -297,7 +364,7 @@ export class VisionGateway
           });
 
           const raw = await response.json();
-          const chatResult = Array.isArray(raw) ? raw[0] : raw;
+          const chatResult = normalizeChatResponse(raw);
           reply(chatResult);
           break;
         }