From 622509188f42cbe0d7a07ccb515531784da333e1 Mon Sep 17 00:00:00 2001 From: Ian Arawjo Date: Mon, 27 Nov 2023 20:14:34 -0500 Subject: [PATCH] Update cache for join and split nodes. Use StorageCache in App.js as safe interface to localStorage. --- chainforge/react-server/src/App.js | 8 ++++---- chainforge/react-server/src/JoinNode.js | 8 +++++++- chainforge/react-server/src/SplitNode.js | 8 +++++++- chainforge/react-server/src/backend/cache.ts | 18 ++++++++++-------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/chainforge/react-server/src/App.js b/chainforge/react-server/src/App.js index f6fff8b..ae9ebbf 100644 --- a/chainforge/react-server/src/App.js +++ b/chainforge/react-server/src/App.js @@ -300,7 +300,7 @@ const App = () => { // NOTE: This currently only saves the front-end state. Cache files // are not pulled or overwritten upon loading from localStorage. const flow = rf.toObject(); - localStorage.setItem('chainforge-flow', JSON.stringify(flow)); + StorageCache.saveToLocalStorage('chainforge-flow', flow); // Attempt to save the current state of the back-end state, // the StorageCache. (This does LZ compression to save space.) @@ -342,7 +342,7 @@ const App = () => { setEdges(flow.edges || []); // Save flow that user loaded to autosave cache, in case they refresh the browser - localStorage.setItem('chainforge-flow', JSON.stringify(flow)); + StorageCache.saveToLocalStorage('chainforge-flow', flow); StorageCache.saveToLocalStorage('chainforge-state'); } }; @@ -350,10 +350,10 @@ const App = () => { return localStorage.getItem('chainforge-flow') !== null; }; const loadFlowFromAutosave = async (rf_inst) => { - const saved_flow = localStorage.getItem('chainforge-flow'); + const saved_flow = StorageCache.loadFromLocalStorage('chainforge-flow', false); if (saved_flow) { StorageCache.loadFromLocalStorage('chainforge-state'); - loadFlow(JSON.parse(saved_flow), rf_inst); + loadFlow(saved_flow, rf_inst); } }; diff --git a/chainforge/react-server/src/JoinNode.js b/chainforge/react-server/src/JoinNode.js index 1b009b3..adce3b0 100644 --- a/chainforge/react-server/src/JoinNode.js +++ b/chainforge/react-server/src/JoinNode.js @@ -8,7 +8,8 @@ import { IconArrowMerge, IconList } from '@tabler/icons-react'; import { Divider, NativeSelect, Text, Popover, Tooltip, Center, Modal, Box } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { escapeBraces } from './backend/template'; -import { countNumLLMs } from './backend/utils'; +import { countNumLLMs, toStandardResponseFormat } from './backend/utils'; +import StorageCache from './backend/cache'; const formattingOptions = [ {value: "\n\n", label:"double newline \\n\\n"}, @@ -321,6 +322,11 @@ const JoinNode = ({ data, id }) => { handleOnConnect(); }, [groupByVar, groupByLLM, formatting]) + // Store the outputs to the cache whenever they change + useEffect(() => { + StorageCache.store(`${id}.json`, joinedTexts.map(toStandardResponseFormat)); + }, [joinedTexts]); + useEffect(() => { if (data.refresh && data.refresh === true) { // Recreate the visualization: diff --git a/chainforge/react-server/src/SplitNode.js b/chainforge/react-server/src/SplitNode.js index 636b124..63934b7 100644 --- a/chainforge/react-server/src/SplitNode.js +++ b/chainforge/react-server/src/SplitNode.js @@ -8,9 +8,10 @@ import { IconArrowMerge, IconArrowsSplit, IconList } from '@tabler/icons-react'; import { Divider, NativeSelect, Text, Popover, Tooltip, Center, Modal, Box } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { escapeBraces } from './backend/template'; -import { processCSV, deepcopy, deepcopy_and_modify, dict_excluding_key } from "./backend/utils"; +import { processCSV, deepcopy, deepcopy_and_modify, dict_excluding_key, toStandardResponseFormat } from "./backend/utils"; import { fromMarkdown } from "mdast-util-from-markdown"; +import StorageCache from './backend/cache'; const formattingOptions = [ {value: "list", label:"- list items"}, @@ -244,6 +245,11 @@ const SplitNode = ({ data, id }) => { handleOnConnect(); }, [splitOnFormat]) + // Store the outputs to the cache whenever they change + useEffect(() => { + StorageCache.store(`${id}.json`, splitTexts.map(toStandardResponseFormat)); + }, [splitTexts]); + useEffect(() => { if (data.refresh && data.refresh === true) { // Recreate the visualization: diff --git a/chainforge/react-server/src/backend/cache.ts b/chainforge/react-server/src/backend/cache.ts index 7bfaf04..df73c35 100644 --- a/chainforge/react-server/src/backend/cache.ts +++ b/chainforge/react-server/src/backend/cache.ts @@ -58,10 +58,11 @@ export default class StorageCache { * Use loadFromLocalStorage to unpack the localStorage data. * * @param localStorageKey The key that will be used in localStorage (default='chainforge') + * @param data Optional. JSON-compatible data to store. If undefined, will store the StorageCache's data. If defined, will only store the passed data. * @returns True if succeeded, false if failure (e.g., too big for localStorage). */ - public static saveToLocalStorage(localStorageKey: string='chainforge'): boolean { - const data = StorageCache.getInstance().data; + public static saveToLocalStorage(localStorageKey: string='chainforge', data?: Dict): boolean { + data = data ?? StorageCache.getInstance().data; const compressed = LZString.compressToUTF16(JSON.stringify(data)); try { localStorage.setItem(localStorageKey, compressed); @@ -83,22 +84,23 @@ export default class StorageCache { * Performs lz-string decompression from UTF16 encoding. * * @param localStorageKey The key that will be used in localStorage (default='chainforge') - * @returns True if succeeded, false if failure (e.g., key not found). + * @returns Loaded data if succeeded, undefined if failure (e.g., key not found). */ - public static loadFromLocalStorage(localStorageKey: string='chainforge'): boolean { + public static loadFromLocalStorage(localStorageKey: string='chainforge', setStorageCacheData: boolean=true): boolean { const compressed = localStorage.getItem(localStorageKey); if (!compressed) { console.error(`Could not find cache data in localStorage with key ${localStorageKey}.`); - return false; + return undefined; } try { let data = JSON.parse(LZString.decompressFromUTF16(compressed)); - StorageCache.getInstance().data = data; + if (setStorageCacheData) + StorageCache.getInstance().data = data; console.log('loaded', data); - return true; + return data; } catch (error) { console.error(error.message); - return false; + return undefined; } } } \ No newline at end of file