Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions chainforge/flask_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ def fetchEnvironAPIKeys():
'AWS_SESSION_TOKEN': 'AWS_Session_Token',
'TOGETHER_API_KEY': 'Together',
'DEEPSEEK_API_KEY': 'DeepSeek',
'MINIMAX_API_KEY': 'MiniMax',
}
d = { alias: os.environ.get(key) for key, alias in keymap.items() }
ret = jsonify(d)
Expand Down
8 changes: 8 additions & 0 deletions chainforge/react-server/craco.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ module.exports = {
},
webpack: {
configure: {
// WebLLM currently publishes sourcemap references to TS sources that are
// not included in the npm package. Ignore only those warnings.
ignoreWarnings: [
{
module: /@mlc-ai\/web-llm/,
message: /Failed to parse source map/,
},
],
resolve: {
fallback: {
process: require.resolve("process/browser"),
Expand Down
23 changes: 23 additions & 0 deletions chainforge/react-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions chainforge/react-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@mantine/form": "^6.0.11",
"@mantine/prism": "^6.0.15",
"@mirai73/bedrock-fm": "^0.4.10",
"@mlc-ai/web-llm": "^0.2.84",
"@reactflow/background": "^11.2.0",
"@reactflow/controls": "^11.1.11",
"@reactflow/core": "^11.7.0",
Expand Down
51 changes: 19 additions & 32 deletions chainforge/react-server/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
getDefaultModelFormData,
getDefaultModelSettings,
} from "./ModelSettingSchemas";
import { NativeLLM } from "./backend/models";
import { v4 as uuid } from "uuid";
import axios from "axios";
import LZString from "lz-string";
Expand Down Expand Up @@ -112,6 +113,7 @@ import {
isEdgeChromium,
isChromium,
isMobileSafari,
isSafari,
} from "react-device-detect";
import MultiEvalNode from "./MultiEvalNode";
import FlowSidebar from "./FlowSidebar";
Expand All @@ -125,6 +127,7 @@ const IS_ACCEPTED_BROWSER =
isChromium ||
isEdgeChromium ||
isFirefox ||
isSafari ||
(navigator as any)?.brave !== undefined) &&
(!isMobile || (isTablet && !isMobileSafari));

Expand Down Expand Up @@ -167,37 +170,19 @@ const selector = (state: StoreHandles) => ({

// The initial LLM to use when new flows are created, or upon first load
const INITIAL_LLM = () => {
if (!IS_RUNNING_LOCALLY) {
// Prefer HF if running on server, as it's free.
const falcon7b = {
key: uuid(),
name: "Mistral-7B",
emoji: "🤗",
model: "mistralai/Mistral-7B-Instruct-v0.1",
base_model: "hf",
temp: 1.0,
settings: getDefaultModelSettings("hf"),
formData: getDefaultModelFormData("hf"),
} satisfies LLMSpec;
falcon7b.formData.shortname = falcon7b.name;
falcon7b.formData.model = falcon7b.model;
return falcon7b;
} else {
// Prefer OpenAI for majority of local users.
const chatgpt = {
key: uuid(),
name: "GPT-4o-mini",
emoji: "🤖",
model: "gpt-4o-mini",
base_model: "gpt-4",
temp: 1.0,
settings: getDefaultModelSettings("gpt-4"),
formData: getDefaultModelFormData("gpt-4"),
} satisfies LLMSpec;
chatgpt.formData.shortname = chatgpt.name;
chatgpt.formData.model = chatgpt.model;
return chatgpt;
}
const qwenWebLLM = {
key: uuid(),
name: "Qwen2.5 0.5B",
emoji: "🌐",
model: NativeLLM.WebLLM_Qwen2_5_0_5B,
base_model: "webllm",
temp: 0.7,
settings: getDefaultModelSettings("webllm"),
formData: getDefaultModelFormData("webllm"),
} satisfies LLMSpec;
qwenWebLLM.formData.shortname = qwenWebLLM.name;
qwenWebLLM.formData.model = qwenWebLLM.model;
return qwenWebLLM;
};

const nodeTypes = {
Expand Down Expand Up @@ -1497,6 +1482,7 @@ const App = () => {
<List.Item>Mozilla Firefox</List.Item>
<List.Item>Microsoft Edge (Chromium)</List.Item>
<List.Item>Brave</List.Item>
<List.Item>Safari</List.Item>
</List>

<Text m="xl" size={"11pt"}>
Expand Down Expand Up @@ -1677,8 +1663,9 @@ const App = () => {
variant={colorScheme === "light" ? "gradient" : "filled"}
color={colorScheme === "light" ? "blue" : "gray"}
compact
style={{ width: "32px", minWidth: "32px", padding: 0 }}
>
<IconSettings size={"90%"} />
<IconSettings size={18} />
</Button>
</div>
<div
Expand Down
21 changes: 18 additions & 3 deletions chainforge/react-server/src/BaseNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,23 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
{icon}&nbsp;{text}
</Menu.Item>
))}
<Menu.Item key="duplicate" onClick={handleDuplicateNode}>
<Menu.Item
key="duplicate"
onClick={() => {
handleDuplicateNode();
setContextMenuOpened(false);
}}
>
<IconCopy size="10pt" />
&nbsp;Duplicate Node
</Menu.Item>
{IS_RUNNING_LOCALLY && (
<Menu.Item
key="favorite"
onClick={() => setFavoriteNameModalOpen(true)}
onClick={() => {
setFavoriteNameModalOpen(true);
setContextMenuOpened(false);
}}
>
<IconHeart
size="12pt"
Expand All @@ -169,7 +178,13 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
&nbsp;Favorite Node
</Menu.Item>
)}
<Menu.Item key="delete" onClick={handleRemoveNode}>
<Menu.Item
key="delete"
onClick={() => {
handleRemoveNode();
setContextMenuOpened(false);
}}
>
<IconX size="10pt" />
&nbsp;Delete Node
</Menu.Item>
Expand Down
22 changes: 16 additions & 6 deletions chainforge/react-server/src/CodeEvaluatorNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
toStandardResponseFormat,
} from "./backend/utils";
import InspectFooter from "./InspectFooter";
import ResizeHandle from "./ResizeHandle";
import { escapeBraces } from "./backend/template";
import LLMResponseInspectorDrawer from "./LLMResponseInspectorDrawer";
import { AIGenCodeEvaluatorPopover } from "./AiPopover";
Expand Down Expand Up @@ -243,6 +244,8 @@ export const CodeEvaluatorComponent = forwardRef<
const [codeTextOnLastRun, setCodeTextOnLastRun] = useState<boolean | string>(
false,
);
const aceEditorRef = useRef<any>(null);
const aceContainerRef = useRef<HTMLDivElement>(null);

// Color theme
const { colorScheme } = useMantineColorScheme();
Expand Down Expand Up @@ -352,7 +355,11 @@ export const CodeEvaluatorComponent = forwardRef<
return (
<div className="core-mirror-field">
{showUserInstruction ? code_instruct_header : <></>}
<div className="ace-editor-container nodrag">
<div
ref={aceContainerRef}
className="ace-editor-container nodrag"
style={{ minWidth: "310px", minHeight: "60px", height: "100px" }}
>
<AceEditor
mode={progLang}
theme={colorScheme === "light" ? "xcode" : "monokai"}
Expand All @@ -361,16 +368,19 @@ export const CodeEvaluatorComponent = forwardRef<
name={"aceeditor_" + id}
editorProps={{ $blockScrolling: true }}
width="100%"
height="100px"
style={{ minWidth: "310px" }}
height="100%"
setOptions={{ useWorker: false }}
tabSize={2}
onLoad={(editorInstance) => {
// Make Ace Editor div resizeable.
editorInstance.container.style.resize = "both";
document.addEventListener("mouseup", () => editorInstance.resize());
aceEditorRef.current = editorInstance;
}}
/>
<ResizeHandle
targetRef={aceContainerRef}
minWidth={310}
minHeight={60}
onResizeEnd={() => aceEditorRef.current?.resize()}
/>
</div>
</div>
);
Expand Down
6 changes: 5 additions & 1 deletion chainforge/react-server/src/InspectorNode.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useContext } from "react";
import React, { useState, useEffect, useContext, useRef } from "react";
import { Handle, Position } from "reactflow";
import useStore from "./store";
import BaseNode from "./BaseNode";
Expand All @@ -7,6 +7,7 @@ import LLMResponseInspector, { exportToExcel } from "./LLMResponseInspector";
import { grabResponses } from "./backend/backend";
import { LLMResponse } from "./backend/typing";
import { AlertModalContext } from "./AlertModal";
import ResizeHandle from "./ResizeHandle";

export interface InspectorNodeProps {
data: {
Expand All @@ -28,6 +29,7 @@ const InspectorNode: React.FC<InspectorNodeProps> = ({ data, id }) => {
const inputEdgesForNode = useStore((state) => state.inputEdgesForNode);
const setDataPropsForNode = useStore((state) => state.setDataPropsForNode);
const showAlert = useContext(AlertModalContext);
const containerRef = useRef<HTMLDivElement>(null);

const handleOnConnect = () => {
// For some reason, 'on connect' is called twice upon connection.
Expand Down Expand Up @@ -89,6 +91,7 @@ const InspectorNode: React.FC<InspectorNodeProps> = ({ data, id }) => {
]}
/>
<div
ref={containerRef}
className="inspect-response-container nowheel nodrag"
style={{ marginTop: "-8pt" }}
>
Expand All @@ -97,6 +100,7 @@ const InspectorNode: React.FC<InspectorNodeProps> = ({ data, id }) => {
isOpen={true}
wideFormat={false}
/>
<ResizeHandle targetRef={containerRef} minWidth={150} minHeight={270} />
</div>
<Handle
type="target"
Expand Down
55 changes: 29 additions & 26 deletions chainforge/react-server/src/LLMItemButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,37 +47,40 @@ export default function LLMItemButtonGroup({
hideTrashIcon,
}: LLMItemButtonGroupProps) {
return (
<div>
<Group
position="right"
spacing="xs"
style={{ float: "right", height: "20px" }}
>
<GatheringResponsesRingProgress progress={ringProgress} />
{hideTrashIcon ? (
<></>
) : (
<Button
onClick={onClickTrash}
size="xs"
variant="light"
compact
color="red"
style={{ padding: "0px" }}
>
<IconTrash size={"95%"} />
</Button>
)}
<Group
spacing="xs"
style={{ flexShrink: 0, width: "fit-content", alignItems: "center" }}
>
<GatheringResponsesRingProgress progress={ringProgress} />
{hideTrashIcon ? (
<></>
) : (
<Button
onClick={onClickSettings}
onClick={onClickTrash}
size="xs"
variant="light"
color="blue"
compact
color="red"
style={{
padding: "0px",
width: "28px",
minWidth: "28px",
height: "28px",
}}
>
<IconSettings size={"110%"} />
<IconTrash size={16} />
</Button>
</Group>
</div>
)}
<Button
onClick={onClickSettings}
size="xs"
variant="light"
color="blue"
compact
style={{ width: "28px", minWidth: "28px", height: "28px" }}
>
<IconSettings size={16} />
</Button>
</Group>
);
}
6 changes: 3 additions & 3 deletions chainforge/react-server/src/LLMListComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ import ModelSettingsModal, {
ModelSettingsModalRef,
} from "./ModelSettingsModal";
import { getDefaultModelSettings } from "./ModelSettingSchemas";
import { NativeLLM } from "./backend/models";
import useStore, { initLLMProviders, initLLMProviderMenu } from "./store";
import { Dict, JSONCompatible, LLMGroup, LLMSpec } from "./backend/typing";
import { ContextMenuItemOptions } from "mantine-contextmenu/dist/types";
import { deepcopy, ensureUniqueName } from "./backend/utils";
import NestedMenu, { NestedMenuItemProps } from "./NestedMenu";

// The LLM(s) to include by default on a PromptNode whenever one is created.
// Defaults to a cheap non-reasoning OpenAI model.
// Defaults to an in-browser Qwen 2.5 model.
const DEFAULT_INIT_LLMS = [
initLLMProviders.find((m) => m.model === "gpt-4o-mini")!,
initLLMProviders.find((m) => m.model === NativeLLM.WebLLM_Qwen2_5_0_5B)!,
];

// Helper funcs
Expand Down Expand Up @@ -499,7 +500,6 @@ export const LLMListContainer = forwardRef<
items={menuItems}
button={(closeMenu) => (
<button
style={_bgStyle}
onClick={() => {
closeMenu();
}}
Expand Down
Loading
Loading