From bce39d355fd515edd32477634c1e8927d7a70e45 Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Sat, 10 May 2025 16:23:32 -0600 Subject: [PATCH] Added Various API Functionality --- Data/Server/WebUI/package.json | 1 + .../Node_Array_Index_Extractor.jsx | 0 .../Node_JSON_Display.jsx | 179 ++++++++++++++++ .../Node_JSON_Value_Extractor.jsx | 132 ++++++++++++ .../Node_OCR_Text_Extraction.jsx | 0 .../Node_Regex_Replace.jsx | 0 .../Node_Regex_Search.jsx | 0 .../Node_TextArray_Display.jsx | 0 .../Data Collection/Node_API_Request.jsx | 193 ++++++++++++++++++ .../Node_Agent.jsx | 0 .../Node_Agent_Role_Screenshot.jsx | 0 .../Node_Upload_Text.jsx | 0 Data/Server/server-requirements.txt | 1 + Data/Server/server.py | 33 ++- 14 files changed, 538 insertions(+), 1 deletion(-) rename Data/Server/WebUI/src/nodes/{Data Manipulation => Data Analysis & Manipulation}/Node_Array_Index_Extractor.jsx (100%) create mode 100644 Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Display.jsx create mode 100644 Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Value_Extractor.jsx rename Data/Server/WebUI/src/nodes/{Data Analysis => Data Analysis & Manipulation}/Node_OCR_Text_Extraction.jsx (100%) rename Data/Server/WebUI/src/nodes/{Data Manipulation => Data Analysis & Manipulation}/Node_Regex_Replace.jsx (100%) rename Data/Server/WebUI/src/nodes/{Data Analysis => Data Analysis & Manipulation}/Node_Regex_Search.jsx (100%) rename Data/Server/WebUI/src/nodes/{Data Analysis => Data Analysis & Manipulation}/Node_TextArray_Display.jsx (100%) create mode 100644 Data/Server/WebUI/src/nodes/Data Collection/Node_API_Request.jsx rename Data/Server/WebUI/src/nodes/{Agents => Data Collection}/Node_Agent.jsx (100%) rename Data/Server/WebUI/src/nodes/{Agents => Data Collection}/Node_Agent_Role_Screenshot.jsx (100%) rename Data/Server/WebUI/src/nodes/{Data Processing => Data Collection}/Node_Upload_Text.jsx (100%) diff --git a/Data/Server/WebUI/package.json b/Data/Server/WebUI/package.json index 068991b..e6ce7f7 100644 --- a/Data/Server/WebUI/package.json +++ b/Data/Server/WebUI/package.json @@ -13,6 +13,7 @@ "@mui/icons-material": "7.0.2", "@mui/material": "7.0.2", "normalize.css": "8.0.1", + "prismjs": "1.30.0", "react": "19.1.0", "react-color": "2.19.3", "react-dom": "19.1.0", diff --git a/Data/Server/WebUI/src/nodes/Data Manipulation/Node_Array_Index_Extractor.jsx b/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_Array_Index_Extractor.jsx similarity index 100% rename from Data/Server/WebUI/src/nodes/Data Manipulation/Node_Array_Index_Extractor.jsx rename to Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_Array_Index_Extractor.jsx diff --git a/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Display.jsx b/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Display.jsx new file mode 100644 index 0000000..a6c5548 --- /dev/null +++ b/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Display.jsx @@ -0,0 +1,179 @@ +////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /Data/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Display.jsx + +import React, { useEffect, useState, useRef, useCallback } from "react"; +import { Handle, Position, useReactFlow, useStore } from "reactflow"; +// For syntax highlighting, ensure prismjs is installed: npm install prismjs +import Prism from "prismjs"; +import "prismjs/components/prism-json"; +import "prismjs/themes/prism-okaidia.css"; + +const JSONPrettyDisplayNode = ({ id, data }) => { + const { setNodes } = useReactFlow(); + const edges = useStore((state) => state.edges); + const containerRef = useRef(null); + const resizingRef = useRef(false); + const startPosRef = useRef({ x: 0, y: 0 }); + const startDimRef = useRef({ width: 0, height: 0 }); + + const [jsonData, setJsonData] = useState(data?.jsonData || {}); + const initW = parseInt(data?.width || "300", 10); + const initH = parseInt(data?.height || "150", 10); + const [dimensions, setDimensions] = useState({ width: initW, height: initH }); + const jsonRef = useRef(jsonData); + + const persistDimensions = useCallback(() => { + const w = `${Math.round(dimensions.width)}px`; + const h = `${Math.round(dimensions.height)}px`; + setNodes((nds) => + nds.map((n) => + n.id === id + ? { ...n, data: { ...n.data, width: w, height: h } } + : n + ) + ); + }, [dimensions, id, setNodes]); + + useEffect(() => { + const onMouseMove = (e) => { + if (!resizingRef.current) return; + const dx = e.clientX - startPosRef.current.x; + const dy = e.clientY - startPosRef.current.y; + setDimensions({ + width: Math.max(100, startDimRef.current.width + dx), + height: Math.max(60, startDimRef.current.height + dy) + }); + }; + const onMouseUp = () => { + if (resizingRef.current) { + resizingRef.current = false; + persistDimensions(); + } + }; + window.addEventListener("mousemove", onMouseMove); + window.addEventListener("mouseup", onMouseUp); + return () => { + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("mouseup", onMouseUp); + }; + }, [persistDimensions]); + + const onResizeMouseDown = (e) => { + e.stopPropagation(); + resizingRef.current = true; + startPosRef.current = { x: e.clientX, y: e.clientY }; + startDimRef.current = { ...dimensions }; + }; + + useEffect(() => { + let rate = window.BorealisUpdateRate; + const tick = () => { + const edge = edges.find((e) => e.target === id); + if (edge && edge.source) { + const upstream = window.BorealisValueBus[edge.source]; + if (typeof upstream === "object") { + if (JSON.stringify(upstream) !== JSON.stringify(jsonRef.current)) { + jsonRef.current = upstream; + setJsonData(upstream); + window.BorealisValueBus[id] = upstream; + setNodes((nds) => + nds.map((n) => + n.id === id ? { ...n, data: { ...n.data, jsonData: upstream } } : n + ) + ); + } + } + } else { + window.BorealisValueBus[id] = jsonRef.current; + } + }; + const iv = setInterval(tick, rate); + const monitor = setInterval(() => { + if (window.BorealisUpdateRate !== rate) { + clearInterval(iv); + clearInterval(monitor); + } + }, 200); + return () => { clearInterval(iv); clearInterval(monitor); }; + }, [id, edges, setNodes]); + + // Generate highlighted HTML + const pretty = JSON.stringify(jsonData, null, 2); + const highlighted = Prism.highlight(pretty, Prism.languages.json, "json"); + + return ( +
+ + + +
Display JSON Data
+
+
+ Display prettified JSON from upstream. +
+
+
+        
+
+ +
+
+ ); +}; + +export default { + type: "Node_JSON_Pretty_Display", + label: "Display JSON Data", + description: "Display upstream JSON object as prettified JSON with syntax highlighting.", + content: "Display prettified multi-line JSON from upstream node.", + component: JSONPrettyDisplayNode +}; diff --git a/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Value_Extractor.jsx b/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Value_Extractor.jsx new file mode 100644 index 0000000..7e581f9 --- /dev/null +++ b/Data/Server/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Value_Extractor.jsx @@ -0,0 +1,132 @@ +////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /Data/WebUI/src/nodes/Data Analysis & Manipulation/Node_JSON_Value_Extractor.jsx + +import React, { useState, useEffect } from "react"; +import { Handle, Position, useReactFlow } from "reactflow"; + +const JSONValueExtractorNode = ({ id, data }) => { + const { setNodes, getEdges } = useReactFlow(); + const [keyName, setKeyName] = useState(data?.keyName || ""); + const [value, setValue] = useState(data?.result || ""); + + const handleKeyChange = (e) => { + const newKey = e.target.value; + setKeyName(newKey); + setNodes((nds) => + nds.map((n) => + n.id === id + ? { ...n, data: { ...n.data, keyName: newKey } } + : n + ) + ); + }; + + useEffect(() => { + let currentRate = window.BorealisUpdateRate; + let intervalId; + + const runNodeLogic = () => { + const edges = getEdges(); + const incoming = edges.filter((e) => e.target === id); + const sourceId = incoming[0]?.source; + let newValue = "Key Not Found"; + + if (sourceId && window.BorealisValueBus[sourceId] !== undefined) { + let upstream = window.BorealisValueBus[sourceId]; + if (upstream && typeof upstream === "object" && keyName) { + const pathSegments = keyName.split("."); + let nodeVal = upstream; + for (let segment of pathSegments) { + if ( + nodeVal != null && + (typeof nodeVal === "object" || Array.isArray(nodeVal)) && + segment in nodeVal + ) { + nodeVal = nodeVal[segment]; + } else { + nodeVal = undefined; + break; + } + } + if (nodeVal !== undefined) { + newValue = String(nodeVal); + } + } + } + + if (newValue !== value) { + setValue(newValue); + window.BorealisValueBus[id] = newValue; + setNodes((nds) => + nds.map((n) => + n.id === id + ? { ...n, data: { ...n.data, result: newValue } } + : n + ) + ); + } + }; + + runNodeLogic(); + intervalId = setInterval(runNodeLogic, currentRate); + + const monitor = setInterval(() => { + const newRate = window.BorealisUpdateRate; + if (newRate !== currentRate) { + clearInterval(intervalId); + currentRate = newRate; + intervalId = setInterval(runNodeLogic, currentRate); + } + }, 250); + + return () => { + clearInterval(intervalId); + clearInterval(monitor); + }; + }, [keyName, id, setNodes, getEdges, value]); + + return ( +
+
JSON Value Extractor
+
+ + + +