mirror of
https://github.com/ianarawjo/ChainForge.git
synced 2025-03-14 08:16:37 +00:00
Right-click to Duplicate (v0.2.6.7) (#150)
* Auto-change shortname upon model settings edit * Adding context menu to nodes on right-click * Add BaseNode and subclass all CF nodes with BaseNode component * Add BaseNode to CSVNode * Move HF and Aleph up in LLM list. * Rebuild react
This commit is contained in:
parent
136fe70458
commit
e456ce6f1c
@ -1,15 +1,15 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.60127273.css",
|
||||
"main.js": "/static/js/main.ee990fc8.js",
|
||||
"main.css": "/static/css/main.8665fcca.css",
|
||||
"main.js": "/static/js/main.3027e2a4.js",
|
||||
"static/js/787.4c72bb55.chunk.js": "/static/js/787.4c72bb55.chunk.js",
|
||||
"index.html": "/index.html",
|
||||
"main.60127273.css.map": "/static/css/main.60127273.css.map",
|
||||
"main.ee990fc8.js.map": "/static/js/main.ee990fc8.js.map",
|
||||
"main.8665fcca.css.map": "/static/css/main.8665fcca.css.map",
|
||||
"main.3027e2a4.js.map": "/static/js/main.3027e2a4.js.map",
|
||||
"787.4c72bb55.chunk.js.map": "/static/js/787.4c72bb55.chunk.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.60127273.css",
|
||||
"static/js/main.ee990fc8.js"
|
||||
"static/css/main.8665fcca.css",
|
||||
"static/js/main.3027e2a4.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><script async src="https://www.googletagmanager.com/gtag/js?id=G-RN3FDBLMCR"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-RN3FDBLMCR")</script><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A visual programming environment for prompt engineering"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>ChainForge</title><script defer="defer" src="/static/js/main.ee990fc8.js"></script><link href="/static/css/main.60127273.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><script async src="https://www.googletagmanager.com/gtag/js?id=G-RN3FDBLMCR"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-RN3FDBLMCR")</script><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A visual programming environment for prompt engineering"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>ChainForge</title><script defer="defer" src="/static/js/main.3027e2a4.js"></script><link href="/static/css/main.8665fcca.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
75
chainforge/react-server/src/BaseNode.js
vendored
Normal file
75
chainforge/react-server/src/BaseNode.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* The base class for every node in ChainForge.
|
||||
* Used to wrap common behavior like right-click context menu.
|
||||
*/
|
||||
|
||||
import { useCallback, useMemo, useState, useRef } from "react";
|
||||
import { Menu } from '@mantine/core';
|
||||
import { IconCopy, IconX } from '@tabler/icons-react';
|
||||
import AreYouSureModal from "./AreYouSureModal";
|
||||
import useStore from './store';
|
||||
|
||||
export const BaseNode = ({children, classNames, nodeId, style}) => {
|
||||
|
||||
const removeNode = useStore((state) => state.removeNode);
|
||||
const duplicateNode = useStore((state) => state.duplicateNode);
|
||||
|
||||
const [contextMenuStyle, setContextMenuStyle] = useState({left: -100, top:0});
|
||||
const [contextMenuOpened, setContextMenuOpened] = useState(false);
|
||||
|
||||
// For 'delete node' confirmation popup
|
||||
const deleteConfirmModal = useRef(null);
|
||||
|
||||
// Class styles for ChainForge nodes
|
||||
const classes = useMemo(() => {
|
||||
return "cfnode " + (classNames ?? "");
|
||||
}, [classNames]);
|
||||
|
||||
// Duplicate the node
|
||||
const handleDuplicateNode = useCallback(() => {
|
||||
duplicateNode(nodeId, { x: 28, y: 28 });
|
||||
}, [nodeId, duplicateNode]);
|
||||
|
||||
// Remove the node, after user confirmation dialog
|
||||
const handleRemoveNode = useCallback(() => {
|
||||
// Open the 'are you sure' modal:
|
||||
if (deleteConfirmModal && deleteConfirmModal.current)
|
||||
deleteConfirmModal.current.trigger();
|
||||
}, [deleteConfirmModal]);
|
||||
|
||||
const handleOpenContextMenu = (e) => {
|
||||
// Ignore all right-clicked elements that aren't divs:
|
||||
// (for instance, textfields should still have normal right-click)
|
||||
if (e.target.localName !== "div")
|
||||
return;
|
||||
|
||||
e.preventDefault();
|
||||
setContextMenuStyle({
|
||||
dropdown: {
|
||||
position: 'absolute',
|
||||
left: e.pageX + 'px !important',
|
||||
top: e.pageY + 'px !important',
|
||||
boxShadow: '2px 2px 4px #ccc',
|
||||
}
|
||||
});
|
||||
setContextMenuOpened(true);
|
||||
};
|
||||
|
||||
// A BaseNode is just a div with "cfnode" as a class, and optional other className(s) for the specific node.
|
||||
// It adds a context menu to all nodes upon right-click of the node itself (the div), to duplicate or delete the node.
|
||||
return (<div className={classes} onPointerDown={() => setContextMenuOpened(false)} onContextMenu={handleOpenContextMenu} style={style}>
|
||||
<AreYouSureModal ref={deleteConfirmModal}
|
||||
title="Delete node"
|
||||
message="Are you sure you want to delete this node? This action is irreversible."
|
||||
onConfirm={() => removeNode(nodeId)} />
|
||||
<Menu opened={contextMenuOpened} withinPortal={true} onChange={setContextMenuOpened} styles={contextMenuStyle}>
|
||||
{children}
|
||||
<Menu.Dropdown>
|
||||
<Menu.Item key='duplicate' onClick={handleDuplicateNode}><IconCopy size='10pt' /> Duplicate Node</Menu.Item>
|
||||
<Menu.Item key='delete' onClick={handleRemoveNode}><IconX size='10pt' /> Delete Node</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
</div>);
|
||||
};
|
||||
|
||||
export default BaseNode;
|
7
chainforge/react-server/src/CommentNode.js
vendored
7
chainforge/react-server/src/CommentNode.js
vendored
@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import useStore from './store';
|
||||
import NodeLabel from './NodeLabelComponent'
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import BaseNode from './BaseNode';
|
||||
import { Textarea } from '@mantine/core';
|
||||
|
||||
/**
|
||||
@ -19,7 +20,7 @@ const CommentNode = ({ data, id }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="cfnode" style={{backgroundColor: '#eee'}}>
|
||||
<BaseNode nodeId={id} style={{backgroundColor: '#eee'}}>
|
||||
<NodeLabel title={data.title || 'Comment'}
|
||||
nodeId={id}
|
||||
icon={'✏️'} />
|
||||
@ -31,7 +32,7 @@ const CommentNode = ({ data, id }) => {
|
||||
w={'260px'}
|
||||
minRows={2}
|
||||
styles={{input: { border: 'none', backgroundColor: '#eee' }}} />
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
28
chainforge/react-server/src/CsvNode.js
vendored
28
chainforge/react-server/src/CsvNode.js
vendored
@ -4,6 +4,7 @@ import useStore from './store';
|
||||
import NodeLabel from './NodeLabelComponent'
|
||||
import { IconCsv } from '@tabler/icons-react';
|
||||
import { Handle } from 'reactflow';
|
||||
import BaseNode from './BaseNode';
|
||||
|
||||
const CsvNode = ({ data, id }) => {
|
||||
const setDataPropsForNode = useStore((state) => state.setDataPropsForNode);
|
||||
@ -108,20 +109,19 @@ const CsvNode = ({ data, id }) => {
|
||||
}, [id, data.text]);
|
||||
|
||||
return (
|
||||
<div className="text-fields-node cfnode">
|
||||
<NodeLabel title={data.title || 'CSV Node'} nodeId={id} icon={<IconCsv size="16px" />} />
|
||||
{csvInput}
|
||||
{contentDiv}
|
||||
{countText ? countText : <></>}
|
||||
<Handle
|
||||
type="source"
|
||||
position="right"
|
||||
id="output"
|
||||
className="grouped-handle"
|
||||
style={{ top: "50%" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
<BaseNode classNames="text-fields-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'CSV Node'} nodeId={id} icon={<IconCsv size="16px" />} />
|
||||
{csvInput}
|
||||
{contentDiv}
|
||||
{countText ? countText : <></>}
|
||||
<Handle
|
||||
type="source"
|
||||
position="right"
|
||||
id="output"
|
||||
className="grouped-handle"
|
||||
style={{ top: "50%" }}
|
||||
/>
|
||||
</BaseNode>);
|
||||
};
|
||||
|
||||
export default CsvNode;
|
9
chainforge/react-server/src/EvaluatorNode.js
vendored
9
chainforge/react-server/src/EvaluatorNode.js
vendored
@ -4,8 +4,9 @@ import { Button, Code, Modal, Tooltip, Box, Text } from '@mantine/core';
|
||||
import { Prism } from '@mantine/prism';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import useStore from './store';
|
||||
import NodeLabel from './NodeLabelComponent'
|
||||
import { IconTerminal, IconSearch, IconInfoCircle } from '@tabler/icons-react'
|
||||
import BaseNode from "./BaseNode";
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import { IconTerminal, IconSearch, IconInfoCircle } from '@tabler/icons-react';
|
||||
import LLMResponseInspectorModal from './LLMResponseInspectorModal';
|
||||
|
||||
// Ace code editor
|
||||
@ -255,7 +256,7 @@ const EvaluatorNode = ({ data, id }) => {
|
||||
const node_header = data.title || default_header;
|
||||
|
||||
return (
|
||||
<div className="evaluator-node cfnode">
|
||||
<BaseNode classNames="evaluator-node" nodeId={id}>
|
||||
<NodeLabel title={node_header}
|
||||
nodeId={id}
|
||||
onEdit={hideStatusIndicator}
|
||||
@ -353,7 +354,7 @@ const EvaluatorNode = ({ data, id }) => {
|
||||
onClick={showResponseInspector}
|
||||
showNotificationDot={uninspectedResponses} />
|
||||
) : <></>}
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
5
chainforge/react-server/src/InspectorNode.js
vendored
5
chainforge/react-server/src/InspectorNode.js
vendored
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Handle } from 'reactflow';
|
||||
import useStore from './store';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import LLMResponseInspector, { exportToExcel } from './LLMResponseInspector';
|
||||
import fetch_from_backend from './fetch_from_backend';
|
||||
@ -55,7 +56,7 @@ const InspectorNode = ({ data, id }) => {
|
||||
}, [data, id, handleOnConnect, setDataPropsForNode]);
|
||||
|
||||
return (
|
||||
<div className="inspector-node cfnode">
|
||||
<BaseNode classNames="inspector-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'Inspect Node'}
|
||||
nodeId={id}
|
||||
icon={'🔍'}
|
||||
@ -73,7 +74,7 @@ const InspectorNode = ({ data, id }) => {
|
||||
style={{ top: "50%" }}
|
||||
onConnect={handleOnConnect}
|
||||
/>
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
5
chainforge/react-server/src/JoinNode.js
vendored
5
chainforge/react-server/src/JoinNode.js
vendored
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Handle } from 'reactflow';
|
||||
import useStore from './store';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import fetch_from_backend from './fetch_from_backend';
|
||||
import { IconArrowMerge, IconList } from '@tabler/icons-react';
|
||||
@ -332,7 +333,7 @@ const JoinNode = ({ data, id }) => {
|
||||
}, [data, id, handleOnConnect, setDataPropsForNode]);
|
||||
|
||||
return (
|
||||
<div className="join-node cfnode">
|
||||
<BaseNode classNames="join-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'Join Node'}
|
||||
nodeId={id}
|
||||
icon={<IconArrowMerge size='14pt'/>}
|
||||
@ -389,7 +390,7 @@ const JoinNode = ({ data, id }) => {
|
||||
className="grouped-handle"
|
||||
style={{ top: "50%" }}
|
||||
/>
|
||||
</div>);
|
||||
</BaseNode>);
|
||||
};
|
||||
|
||||
export default JoinNode;
|
5
chainforge/react-server/src/LLMEvalNode.js
vendored
5
chainforge/react-server/src/LLMEvalNode.js
vendored
@ -4,6 +4,7 @@ import { Alert, Progress, Textarea } from '@mantine/core';
|
||||
import { IconAlertTriangle, IconRobot, IconSearch } from "@tabler/icons-react";
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import useStore from './store';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import fetch_from_backend from './fetch_from_backend';
|
||||
import { getDefaultModelSettings } from './ModelSettingSchemas';
|
||||
@ -139,7 +140,7 @@ const LLMEvaluatorNode = ({ data, id }) => {
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<div className="evaluator-node cfnode">
|
||||
<BaseNode classNames="evaluator-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'LLM Scorer'}
|
||||
nodeId={id}
|
||||
icon={<IconRobot size="16px" />}
|
||||
@ -200,7 +201,7 @@ const LLMEvaluatorNode = ({ data, id }) => {
|
||||
onClick={showResponseInspector}
|
||||
showNotificationDot={uninspectedResponses}
|
||||
/>) : <></>}
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -342,7 +342,11 @@ const PaLM2Settings = {
|
||||
"title": "Model",
|
||||
"description": "Select a PaLM model to query. For more details on the differences, see the Google PaLM API documentation.",
|
||||
"enum": ["text-bison-001", "chat-bison-001"],
|
||||
"default": "chat-bison-001"
|
||||
"default": "chat-bison-001",
|
||||
"shortname_map": {
|
||||
"text-bison-001": "PaLM2-text",
|
||||
"chat-bison-001": "PaLM2-chat",
|
||||
}
|
||||
},
|
||||
"temperature": {
|
||||
"type": "number",
|
||||
@ -614,9 +618,19 @@ const HuggingFaceTextInferenceSettings = {
|
||||
"model": {
|
||||
"type": "string",
|
||||
"title": "Model",
|
||||
"description": "Select a suggested HuggingFace-hosted model to query using the Inference API. For more details, check out https://huggingface.co/inference-api",
|
||||
"enum": ["mistralai/Mistral-7B-Instruct-v0.1", "HuggingFaceH4/zephyr-7b-beta", "tiiuae/falcon-7b-instruct", "microsoft/DialoGPT-large", "bigscience/bloom-560m", "gpt2", "bigcode/santacoder", "bigcode/starcoder", "Other (HuggingFace)"],
|
||||
"default": "tiiuae/falcon-7b-instruct",
|
||||
"description": "Select a suggested HuggingFace-hosted model to query using the Inference API. For more details, check out https://huggingface.co/inference-api",
|
||||
"enum": ["mistralai/Mistral-7B-Instruct-v0.1", "HuggingFaceH4/zephyr-7b-beta", "tiiuae/falcon-7b-instruct", "microsoft/DialoGPT-large", "bigscience/bloom-560m", "gpt2", "bigcode/santacoder", "bigcode/starcoder", "Other (HuggingFace)"],
|
||||
"default": "tiiuae/falcon-7b-instruct",
|
||||
"shortname_map": {
|
||||
"mistralai/Mistral-7B-Instruct-v0.1": "Mistral-7B",
|
||||
"HuggingFaceH4/zephyr-7b-beta": "Zephyr-7B",
|
||||
"tiiuae/falcon-7b-instruct": "Falcon-7B",
|
||||
"microsoft/DialoGPT-large": "DialoGPT",
|
||||
"bigscience/bloom-560m": "Bloom560M",
|
||||
"gpt2": "GPT-2",
|
||||
"bigcode/santacoder": "santacoder",
|
||||
"bigcode/starcoder": "starcoder"
|
||||
}
|
||||
},
|
||||
"custom_model": {
|
||||
"type": "string",
|
||||
@ -769,6 +783,14 @@ const AlephAlphaLuminousSettings = {
|
||||
"luminous-supreme-control",
|
||||
],
|
||||
default: "luminous-base",
|
||||
shortname_map: {
|
||||
"luminous-extended": "luminous-ext",
|
||||
"luminous-extended-control": "luminous-ext-ctrl",
|
||||
"luminous-base-control": "luminous-base-ctrl",
|
||||
"luminous-base": "luminous-base",
|
||||
"luminous-supreme": "luminous-supr",
|
||||
"luminous-supreme-control": "luminous-supr-ctrl",
|
||||
}
|
||||
},
|
||||
temperature: {
|
||||
type: "number",
|
||||
@ -1075,7 +1097,7 @@ export const getTemperatureSpecForModel = (modelName) => {
|
||||
};
|
||||
|
||||
export const postProcessFormData = (settingsSpec, formData) => {
|
||||
// Strip all 'model' and 'shortname' props in the submitted form, as these are passed elsewhere or unecessary for the backend
|
||||
// Strip all 'model' and 'shortname' props in the submitted form, as these are passed elsewhere or unnecessary for the backend
|
||||
const skip_keys = {'model': true, 'shortname': true};
|
||||
|
||||
let new_data = {};
|
||||
|
@ -19,11 +19,14 @@ const ModelSettingsModal = forwardRef((props, ref) => {
|
||||
|
||||
const [schema, setSchema] = useState({'type': 'object', 'description': 'No model info object was passed to settings modal.'});
|
||||
const [uiSchema, setUISchema] = useState({});
|
||||
const [modelName, setModelName] = useState("(unknown)");
|
||||
const [baseModelName, setBaseModelName] = useState("(unknown)");
|
||||
|
||||
const [initShortname, setInitShortname] = useState(undefined);
|
||||
const [initModelName, setInitModelName] = useState(undefined);
|
||||
|
||||
// Totally necessary emoji picker
|
||||
const [modelEmoji, setModelEmoji] = useState('');
|
||||
const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
|
||||
const [emojiPickerOpen, setEmojiPickerOpen] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.model && props.model.base_model) {
|
||||
@ -31,22 +34,26 @@ const ModelSettingsModal = forwardRef((props, ref) => {
|
||||
if (!(props.model.base_model in ModelSettings)) {
|
||||
setSchema({'type': 'object', 'description': `Did not find settings schema for base model ${props.model.base_model}. Maybe you are missing importing a custom provider script?`});
|
||||
setUISchema({});
|
||||
setModelName(props.model.base_model);
|
||||
setBaseModelName(props.model.base_model);
|
||||
return;
|
||||
}
|
||||
const settingsSpec = ModelSettings[props.model.base_model];
|
||||
const schema = settingsSpec.schema;
|
||||
setSchema(schema);
|
||||
setUISchema(settingsSpec.uiSchema);
|
||||
setModelName(settingsSpec.fullName);
|
||||
setBaseModelName(settingsSpec.fullName);
|
||||
if (props.model.formData) {
|
||||
setFormData(props.model.formData);
|
||||
setInitShortname(props.model.formData.shortname);
|
||||
setInitModelName(props.model.formData.model);
|
||||
} else {
|
||||
// Create settings from schema
|
||||
let default_settings = {};
|
||||
Object.keys(schema.properties).forEach(key => {
|
||||
default_settings[key] = 'default' in schema.properties[key] ? schema.properties[key]['default'] : undefined;
|
||||
});
|
||||
setInitShortname(default_settings.shortname);
|
||||
setInitModelName(default_settings.model);
|
||||
setFormData(getDefaultModelFormData(settingsSpec));
|
||||
}
|
||||
}
|
||||
@ -58,7 +65,6 @@ const ModelSettingsModal = forwardRef((props, ref) => {
|
||||
}, [props.model]);
|
||||
|
||||
const saveFormState = useCallback((fdata) => {
|
||||
|
||||
// For some reason react-json-form-schema returns 'undefined' on empty strings.
|
||||
// We need to (1) detect undefined values for keys in formData and (2) if they are of type string, replace with "",
|
||||
// if that property is marked with a special "allow_empty_str" property.
|
||||
@ -82,9 +88,24 @@ const ModelSettingsModal = forwardRef((props, ref) => {
|
||||
saveFormState(submitInfo.formData);
|
||||
}, [saveFormState]);
|
||||
|
||||
// On every edit to the form...
|
||||
const onFormDataChange = (state) => {
|
||||
if (state && state.formData)
|
||||
if (state && state.formData) {
|
||||
|
||||
// This checks if the model name has changed, but the shortname wasn't edited (in this window).
|
||||
// In this case, we auto-change the shortname, to save user's time and nickname models appropriately.
|
||||
if (state.formData.shortname === initShortname && state.formData.model !== initModelName) {
|
||||
const shortname_map = schema.properties?.model?.shortname_map;
|
||||
if (shortname_map && state.formData.model in shortname_map)
|
||||
state.formData.shortname = shortname_map[state.formData.model];
|
||||
else
|
||||
state.formData.shortname = state.formData.model;
|
||||
setInitShortname(state.formData.shortname);
|
||||
setInitModelName(state.formData.model);
|
||||
}
|
||||
|
||||
setFormData(state.formData);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickSubmit = useCallback(() => {
|
||||
@ -103,7 +124,7 @@ const ModelSettingsModal = forwardRef((props, ref) => {
|
||||
// This gives the parent access to triggering the modal
|
||||
const trigger = useCallback(() => {
|
||||
open();
|
||||
}, [schema, uiSchema, modelName, open]);
|
||||
}, [schema, uiSchema, baseModelName, open]);
|
||||
useImperativeHandle(ref, () => ({
|
||||
trigger,
|
||||
}));
|
||||
@ -118,10 +139,9 @@ return (
|
||||
<Popover.Dropdown>
|
||||
<Picker data={emojidata} onEmojiSelect={onEmojiSelect} theme="light" />
|
||||
</Popover.Dropdown>
|
||||
</Popover><span>{`Model Settings: ${modelName}`}</span>
|
||||
</Popover><span>{`Model Settings: ${baseModelName}`}</span>
|
||||
</div>
|
||||
} closeOnClickOutside={false} style={{position: 'relative', 'left': '-5%'}}>
|
||||
|
||||
<Form schema={schema} uiSchema={uiSchema} formData={formData} validator={validator} onChange={onFormDataChange} onSubmit={onSubmit} style={{width: '100%'}}>
|
||||
<Button title='Submit' onClick={onClickSubmit} style={{float: 'right', marginRight: '30px'}}>Submit</Button>
|
||||
<div style={{height: '50px'}}></div>
|
||||
|
@ -90,6 +90,5 @@ export default function NodeLabel({ title, nodeId, icon, onEdit, onSave, editabl
|
||||
</div>
|
||||
{/* <button className="AmitSahoo45-button-3 nodrag" onClick={handleRunClick}><div className="play-button"></div></button> */}
|
||||
</div>
|
||||
|
||||
</>);
|
||||
}
|
7
chainforge/react-server/src/PromptNode.js
vendored
7
chainforge/react-server/src/PromptNode.js
vendored
@ -4,7 +4,8 @@ import { Switch, Progress, Textarea, Text, Popover, Center, Modal, Box, Tooltip
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconList } from '@tabler/icons-react';
|
||||
import useStore from './store';
|
||||
import NodeLabel from './NodeLabelComponent'
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import TemplateHooks, { extractBracketedSubstrings } from './TemplateHooksComponent'
|
||||
import { LLMListContainer } from './LLMListComponent'
|
||||
import LLMResponseInspectorModal from './LLMResponseInspectorModal';
|
||||
@ -640,7 +641,7 @@ const PromptNode = ({ data, id, type: node_type }) => {
|
||||
}, [textAreaRef]);
|
||||
|
||||
return (
|
||||
<div className="prompt-node cfnode">
|
||||
<BaseNode classNames="prompt-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || node_default_title}
|
||||
nodeId={id}
|
||||
onEdit={hideStatusIndicator}
|
||||
@ -741,7 +742,7 @@ const PromptNode = ({ data, id, type: node_type }) => {
|
||||
) : <></>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
5
chainforge/react-server/src/ScriptNode.js
vendored
5
chainforge/react-server/src/ScriptNode.js
vendored
@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import useStore from './store';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import { IconSettingsAutomation } from '@tabler/icons-react';
|
||||
|
||||
@ -66,7 +67,7 @@ const ScriptNode = ({ data, id }) => {
|
||||
}, [data, id, setDataPropsForNode]);
|
||||
|
||||
return (
|
||||
<div className="script-node cfnode">
|
||||
<BaseNode classNames="script-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'Global Python Scripts'} nodeId={id} editable={false} icon={<IconSettingsAutomation size="16px" />}/>
|
||||
<label htmlFor="num-generations" style={{fontSize: '10pt'}}>Enter folder paths for external modules you wish to import.</label> <br/><br/>
|
||||
<div>
|
||||
@ -75,7 +76,7 @@ const ScriptNode = ({ data, id }) => {
|
||||
<div className="add-text-field-btn">
|
||||
<button onClick={handleAddField}>+</button>
|
||||
</div>
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { useState, useCallback, useEffect, useRef } from "react";
|
||||
import { Handle } from "reactflow";
|
||||
import { NativeSelect, TextInput, Flex, Text, Box, Select, ActionIcon, Menu, Tooltip } from "@mantine/core";
|
||||
import { IconCaretDown, IconHash, IconRuler2, IconSearch, IconX } from "@tabler/icons-react";
|
||||
import BaseNode from "./BaseNode";
|
||||
import NodeLabel from "./NodeLabelComponent";
|
||||
import InspectFooter from "./InspectFooter";
|
||||
import LLMResponseInspectorModal from "./LLMResponseInspectorModal";
|
||||
@ -196,7 +197,7 @@ const SimpleEvalNode = ({data, id}) => {
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<div className="evaluator-node cfnode">
|
||||
<BaseNode classNames="evaluator-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'Simple Evaluator'}
|
||||
nodeId={id}
|
||||
icon={<IconRuler2 size="16px" />}
|
||||
@ -295,7 +296,7 @@ const SimpleEvalNode = ({data, id}) => {
|
||||
onClick={showResponseInspector}
|
||||
showNotificationDot={uninspectedResponses}
|
||||
/>) : <></>}
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ import Papa from 'papaparse';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { IconX, IconArrowBarToUp, IconArrowBarToDown } from '@tabler/icons-react';
|
||||
import TemplateHooks from './TemplateHooksComponent';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import AlertModal from './AlertModal';
|
||||
import RenameValueModal from './RenameValueModal';
|
||||
@ -389,7 +390,7 @@ const TabularDataNode = ({ data, id }) => {
|
||||
}, [ref]);
|
||||
|
||||
return (
|
||||
<div className="tabular-data-node cfnode" onPointerDown={() => setContextMenuOpened(false)}>
|
||||
<BaseNode classNames="tabular-data-node" nodeId={id} onPointerDown={() => setContextMenuOpened(false)}>
|
||||
<NodeLabel title={data.title || 'Tabular Data Node'}
|
||||
nodeId={id}
|
||||
icon={'🗂️'}
|
||||
@ -434,7 +435,7 @@ const TabularDataNode = ({ data, id }) => {
|
||||
<TemplateHooks vars={tableColumns.map(col => col.header)} nodeId={id} startY={hooksY} position='right' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { IconTextPlus, IconEye, IconEyeOff } from '@tabler/icons-react';
|
||||
import useStore from './store';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import TemplateHooks, { extractBracketedSubstrings } from './TemplateHooksComponent';
|
||||
import BaseNode from './BaseNode';
|
||||
|
||||
// Helper funcs
|
||||
const union = (setA, setB) => {
|
||||
@ -164,7 +165,7 @@ const TextFieldsNode = ({ data, id }) => {
|
||||
}, [data, id, pingOutputNodes]);
|
||||
|
||||
return (
|
||||
<div className="text-fields-node cfnode">
|
||||
<BaseNode classNames="text-fields-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'TextFields Node'} nodeId={id} icon={<IconTextPlus size="16px" />} />
|
||||
<div ref={setRef}>
|
||||
{Object.keys(textfieldsValues).map(i => (
|
||||
@ -205,7 +206,7 @@ const TextFieldsNode = ({ data, id }) => {
|
||||
<div className="add-text-field-btn">
|
||||
<button onClick={handleAddField}>+</button>
|
||||
</div>
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
5
chainforge/react-server/src/VisNode.js
vendored
5
chainforge/react-server/src/VisNode.js
vendored
@ -3,6 +3,7 @@ import { Handle } from 'reactflow';
|
||||
import { NativeSelect } from '@mantine/core';
|
||||
import useStore, { colorPalettes } from './store';
|
||||
import Plot from 'react-plotly.js';
|
||||
import BaseNode from './BaseNode';
|
||||
import NodeLabel from './NodeLabelComponent';
|
||||
import PlotLegend from './PlotLegend';
|
||||
import fetch_from_backend from './fetch_from_backend';
|
||||
@ -728,7 +729,7 @@ const VisNode = ({ data, id }) => {
|
||||
}, [plotDivRef, plotlySpec]);
|
||||
|
||||
return (
|
||||
<div className="vis-node cfnode">
|
||||
<BaseNode classNames="vis-node" nodeId={id}>
|
||||
<NodeLabel title={data.title || 'Vis Node'}
|
||||
nodeId={id}
|
||||
status={status}
|
||||
@ -786,7 +787,7 @@ const VisNode = ({ data, id }) => {
|
||||
style={{ top: '50%' }}
|
||||
onConnect={handleOnConnect}
|
||||
/>
|
||||
</div>
|
||||
</BaseNode>
|
||||
);
|
||||
};
|
||||
|
||||
|
41
chainforge/react-server/src/store.js
vendored
41
chainforge/react-server/src/store.js
vendored
@ -33,9 +33,9 @@ export let initLLMProviders = [
|
||||
{ name: "GPT4", emoji: "🥵", model: "gpt-4", base_model: "gpt-4", temp: 1.0 },
|
||||
{ name: "Claude", emoji: "📚", model: "claude-2", base_model: "claude-v1", temp: 0.5 },
|
||||
{ name: "PaLM2", emoji: "🦬", model: "chat-bison-001", base_model: "palm2-bison", temp: 0.7 },
|
||||
{ name: "Azure OpenAI", emoji: "🔷", model: "azure-openai", base_model: "azure-openai", temp: 1.0 },
|
||||
{ name: "HuggingFace", emoji: "🤗", model: "tiiuae/falcon-7b-instruct", base_model: "hf", temp: 1.0 },
|
||||
{ name: "Aleph Alpha", emoji: "💡", model: "luminous-base", base_model: "luminous-base", temp: 0.0 }
|
||||
{ name: "Aleph Alpha", emoji: "💡", model: "luminous-base", base_model: "luminous-base", temp: 0.0 },
|
||||
{ name: "Azure OpenAI", emoji: "🔷", model: "azure-openai", base_model: "azure-openai", temp: 1.0 },
|
||||
];
|
||||
if (APP_IS_RUNNING_LOCALLY()) {
|
||||
initLLMProviders.push({ name: "Dalai (Alpaca.7B)", emoji: "🦙", model: "alpaca.7B", base_model: "dalai", temp: 0.5 });
|
||||
@ -270,6 +270,12 @@ const useStore = create((set, get) => ({
|
||||
},
|
||||
getNode: (id) => get().nodes.find(n => n.id === id),
|
||||
addNode: (newnode) => {
|
||||
// Make sure we select the added node.
|
||||
// This will float it to the top.
|
||||
get().deselectAllNodes();
|
||||
newnode.selected = true;
|
||||
|
||||
// Add the node to the internal state
|
||||
set({
|
||||
nodes: get().nodes.concat(newnode)
|
||||
});
|
||||
@ -279,6 +285,37 @@ const useStore = create((set, get) => ({
|
||||
nodes: get().nodes.filter(n => n.id !== id)
|
||||
});
|
||||
},
|
||||
deselectAllNodes: () => {
|
||||
// Deselect all nodes
|
||||
set({
|
||||
nodes: get().nodes.map((n) => {
|
||||
n.selected = false;
|
||||
return n;
|
||||
})
|
||||
});
|
||||
},
|
||||
duplicateNode: (id, offset) => {
|
||||
const nodes = get().nodes;
|
||||
const node = nodes.find(n => n.id === id);
|
||||
if (!node) {
|
||||
console.error(`Could not duplicate node: No node found with id ${id}`);
|
||||
return undefined;
|
||||
}
|
||||
// Deep copy node data
|
||||
let dup = JSON.parse(JSON.stringify(node));
|
||||
// Shift position
|
||||
dup.position.x += offset && offset.x !== undefined ? offset.x : 0;
|
||||
dup.position.y += offset && offset.y !== undefined ? offset.y : 0;
|
||||
// Change id to new unique id
|
||||
dup.id = `${dup.type}-${Date.now()}`;
|
||||
// Select it (floats it to top)
|
||||
dup.selected = true;
|
||||
// Deselect all previous nodes
|
||||
get().deselectAllNodes();
|
||||
// Declare new node with copied data, at the shifted position
|
||||
get().addNode(dup);
|
||||
return dup;
|
||||
},
|
||||
setNodes: (newnodes) => {
|
||||
set({
|
||||
nodes: newnodes
|
||||
|
@ -171,6 +171,9 @@
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.node-header:hover {
|
||||
border-bottom-color: #888;
|
||||
}
|
||||
|
||||
.prompt-node {
|
||||
background-color: #fff;
|
||||
|
Loading…
x
Reference in New Issue
Block a user