diff --git a/chain-forge/package-lock.json b/chain-forge/package-lock.json index 8cc28a7..b362d3a 100644 --- a/chain-forge/package-lock.json +++ b/chain-forge/package-lock.json @@ -14,6 +14,7 @@ "@reactflow/background": "^11.2.0", "@reactflow/controls": "^11.1.11", "@reactflow/core": "^11.7.0", + "@reactflow/node-resizer": "^2.1.0", "@tabler/icons-react": "^2.17.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", @@ -3814,6 +3815,22 @@ "react-dom": ">=17" } }, + "node_modules/@reactflow/node-resizer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.1.0.tgz", + "integrity": "sha512-DVL8nnWsltP8/iANadAcTaDB4wsEkx2mOLlBEPNE3yc5loSm3u9l5m4enXRcBym61MiMuTtDPzZMyYYQUjuYIg==", + "dependencies": { + "@reactflow/core": "^11.6.0", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.3.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", diff --git a/chain-forge/package.json b/chain-forge/package.json index 907e9f7..dc25c0e 100644 --- a/chain-forge/package.json +++ b/chain-forge/package.json @@ -9,6 +9,7 @@ "@reactflow/background": "^11.2.0", "@reactflow/controls": "^11.1.11", "@reactflow/core": "^11.7.0", + "@reactflow/node-resizer": "^2.1.0", "@tabler/icons-react": "^2.17.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", diff --git a/chain-forge/src/ControlledTextArea.js b/chain-forge/src/ControlledTextArea.js new file mode 100644 index 0000000..1d7a0ef --- /dev/null +++ b/chain-forge/src/ControlledTextArea.js @@ -0,0 +1,22 @@ +import React, { useEffect, useRef, useState } from 'react'; + +/* Modified from https://stackoverflow.com/a/68928267 */ +const ControlledTextArea = (props) => { + const { value, onChange, ...rest } = props; + const [cursor, setCursor] = useState(null); + const ref = useRef(null); + + useEffect(() => { + const input = ref.current; + if (input) input.setSelectionRange(cursor, cursor); + }, [ref, cursor, value]); + + const handleChange = (e) => { + setCursor(e.target.selectionStart); + onChange && onChange(e); + }; + + return ; +}; + +export default ControlledTextArea; \ No newline at end of file diff --git a/chain-forge/src/InspectorNode.js b/chain-forge/src/InspectorNode.js index c52f30b..564cedc 100644 --- a/chain-forge/src/InspectorNode.js +++ b/chain-forge/src/InspectorNode.js @@ -39,6 +39,13 @@ const groupResponsesBy = (responses, keyFunc) => { }); return [responses_by_key, unspecified_group]; }; +const getUniqueKeysInResponses = (responses, keyFunc) => { + let ukeys = new Set(); + responses.forEach(res_obj => + ukeys.add(keyFunc(res_obj))); + return Array.from(ukeys); +}; +const getLLMsInResponses = (responses) => getUniqueKeysInResponses(responses, (resp_obj) => resp_obj.llm); const InspectorNode = ({ data, id }) => { @@ -61,17 +68,14 @@ const InspectorNode = ({ data, id }) => { const selected_vars = multiSelectValue; // Find all LLMs in responses and store as array - let found_llms = new Set(); - responses.forEach(res_obj => - found_llms.add(res_obj.llm)); - found_llms = Array.from(found_llms); + let found_llms = getLLMsInResponses(responses); // Assign a color to each LLM in responses const llm_colors = ['#ace1aeb1', '#f1b963b1', '#e46161b1', '#f8f398b1', '#defcf9b1', '#cadefcb1', '#c3bef0b1', '#cca8e9b1']; const llm_badge_colors = ['green', 'orange', 'red', 'yellow', 'cyan', 'indigo', 'grape']; const color_for_llm = (llm) => llm_colors[found_llms.indexOf(llm) % llm_colors.length]; const badge_color_for_llm = (llm) => llm_badge_colors[found_llms.indexOf(llm) % llm_badge_colors.length]; - const response_box_colors = ['#ddd', '#eee', '#ddd', '#eee']; + const response_box_colors = ['#eee', '#fff', '#eee', '#ddd', '#eee', '#ddd', '#eee']; const rgroup_color = (depth) => response_box_colors[depth % response_box_colors.length]; const getHeaderBadge = (key, val) => { diff --git a/chain-forge/src/PlotLegend.js b/chain-forge/src/PlotLegend.js new file mode 100644 index 0000000..a5fd0b8 --- /dev/null +++ b/chain-forge/src/PlotLegend.js @@ -0,0 +1,23 @@ +import React from 'react'; + +const truncStr = (s, maxLen) => { + if (s.length > maxLen) // Cut the name short if it's long + return s.substring(0, maxLen) + '...' + else + return s; +}; + +const PlotLegend = ({ labels }) => { + return ( +