From 2074511067201f0addb9d274cc90d1e782f2bc1d Mon Sep 17 00:00:00 2001 From: NamH Date: Tue, 6 Aug 2024 15:03:08 +0700 Subject: [PATCH] feat: enable copy over instructions (#3266) --- web/containers/Providers/KeyListener.tsx | 24 ++++++++++- web/hooks/useThreads.ts | 5 ++- web/package.json | 2 - .../components/CopyOverInstruction.tsx | 41 +++++++++++++++++++ .../components/DataMigration.tsx | 0 web/screens/Settings/Advanced/index.tsx | 11 ++--- web/screens/Thread/ThreadLeftPanel/index.tsx | 35 ++++++++++------ 7 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 web/screens/Settings/Advanced/components/CopyOverInstruction.tsx rename web/screens/Settings/Advanced/{FactoryReset => }/components/DataMigration.tsx (100%) diff --git a/web/containers/Providers/KeyListener.tsx b/web/containers/Providers/KeyListener.tsx index 30b2ab46b7..12ce826aa3 100644 --- a/web/containers/Providers/KeyListener.tsx +++ b/web/containers/Providers/KeyListener.tsx @@ -7,6 +7,8 @@ import { useAtomValue, useSetAtom } from 'jotai' import useAssistantQuery from '@/hooks/useAssistantQuery' import useThreads from '@/hooks/useThreads' +import { copyOverInstructionEnabledAtom } from '@/screens/Settings/Advanced/components/CopyOverInstruction' + import { toaster } from '../Toast' import { @@ -17,12 +19,18 @@ import { } from '@/helpers/atoms/App.atom' import { getSelectedModelAtom } from '@/helpers/atoms/Model.atom' +import { activeThreadAtom } from '@/helpers/atoms/Thread.atom' + const KeyListener: React.FC = () => { const setShowLeftPanel = useSetAtom(showLeftPanelAtom) const setShowRightPanel = useSetAtom(showRightPanelAtom) const setMainViewState = useSetAtom(mainViewStateAtom) const { createThread } = useThreads() + const activeThread = useAtomValue(activeThreadAtom) + const copyOverInstructionEnabled = useAtomValue( + copyOverInstructionEnabledAtom + ) const { data: assistants } = useAssistantQuery() const selectedModel = useAtomValue(getSelectedModelAtom) @@ -46,9 +54,21 @@ const KeyListener: React.FC = () => { return } - createThread(selectedModel.model, assistants[0]) + if (!selectedModel) return + let instructions: string | undefined = undefined + if (copyOverInstructionEnabled) { + instructions = activeThread?.assistants[0]?.instructions ?? undefined + } + createThread(selectedModel.model, assistants[0], instructions) setMainViewState(MainViewState.Thread) - }, [selectedModel, createThread, assistants, setMainViewState]) + }, [ + createThread, + setMainViewState, + selectedModel, + assistants, + activeThread, + copyOverInstructionEnabled, + ]) useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { diff --git a/web/hooks/useThreads.ts b/web/hooks/useThreads.ts index d177ab6dbf..39dd6df1a3 100644 --- a/web/hooks/useThreads.ts +++ b/web/hooks/useThreads.ts @@ -49,8 +49,11 @@ const useThreads = () => { ) const createNewThread = useCallback( - async (modelId: string, assistant: Assistant) => { + async (modelId: string, assistant: Assistant, instructions?: string) => { assistant.model = modelId + if (instructions) { + assistant.instructions = instructions + } const thread = await createThread(assistant) log.info('Create new thread result', thread) setThreads((threads) => [thread, ...threads]) diff --git a/web/package.json b/web/package.json index 632cb8f7f5..d22a60e2b1 100644 --- a/web/package.json +++ b/web/package.json @@ -40,7 +40,6 @@ "react-dom": "18.2.0", "react-dropzone": "^14.2.3", "react-hot-toast": "^2.4.1", - "react-scroll-to-bottom": "^4.2.0", "sass": "^1.69.4", "tailwind-merge": "^2.0.0", "tailwindcss": "3.3.5", @@ -51,7 +50,6 @@ "@types/node": "20.8.10", "@types/react": "18.2.34", "@types/react-dom": "18.2.14", - "@types/react-scroll-to-bottom": "^4.2.4", "@types/uuid": "^9.0.6", "@typescript-eslint/eslint-plugin": "^6.8.0", "@typescript-eslint/parser": "^6.8.0", diff --git a/web/screens/Settings/Advanced/components/CopyOverInstruction.tsx b/web/screens/Settings/Advanced/components/CopyOverInstruction.tsx new file mode 100644 index 0000000000..b4102994a4 --- /dev/null +++ b/web/screens/Settings/Advanced/components/CopyOverInstruction.tsx @@ -0,0 +1,41 @@ +import { ChangeEvent, useCallback } from 'react' + +import { Switch } from '@janhq/joi' +import { useAtom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' + +const COPY_OVER_INSTRUCTION_ENABLED = 'copy_over_instruction_enabled' +export const copyOverInstructionEnabledAtom = atomWithStorage( + COPY_OVER_INSTRUCTION_ENABLED, + false +) + +const CopyOverInstructionItem: React.FC = () => { + const [copyOverInstructionEnabled, setCopyOverInstructionEnabled] = useAtom( + copyOverInstructionEnabledAtom + ) + + const onSwitchToggled = useCallback( + (e: ChangeEvent) => { + setCopyOverInstructionEnabled(e.target.checked) + }, + [setCopyOverInstructionEnabled] + ) + + return ( +
+
+
+
Copy Over Instruction
+
+

+ Enable instruction to be copied to new thread +

+
+ {/**/} + +
+ ) +} + +export default CopyOverInstructionItem diff --git a/web/screens/Settings/Advanced/FactoryReset/components/DataMigration.tsx b/web/screens/Settings/Advanced/components/DataMigration.tsx similarity index 100% rename from web/screens/Settings/Advanced/FactoryReset/components/DataMigration.tsx rename to web/screens/Settings/Advanced/components/DataMigration.tsx diff --git a/web/screens/Settings/Advanced/index.tsx b/web/screens/Settings/Advanced/index.tsx index 9ac2ef0c33..e89669a2c8 100644 --- a/web/screens/Settings/Advanced/index.tsx +++ b/web/screens/Settings/Advanced/index.tsx @@ -13,7 +13,9 @@ import { toaster } from '@/containers/Toast' import useModelStop from '@/hooks/useModelStop' import { useSettings } from '@/hooks/useSettings' -import DataMigration from './FactoryReset/components/DataMigration' +import CopyOverInstructionItem from './components/CopyOverInstruction' + +import DataMigration from './components/DataMigration' import { experimentalFeatureEnabledAtom, @@ -26,12 +28,6 @@ import { import { activeModelsAtom } from '@/helpers/atoms/Model.atom' -// type GPU = { -// id: string -// vram: number | null -// name: string -// } - const Advanced = () => { const [experimentalEnabled, setExperimentalEnabled] = useAtom( experimentalFeatureEnabledAtom @@ -462,6 +458,7 @@ const Advanced = () => { {/* Factory Reset */} {/* */} + {experimentalEnabled && } {experimentalEnabled && } diff --git a/web/screens/Thread/ThreadLeftPanel/index.tsx b/web/screens/Thread/ThreadLeftPanel/index.tsx index 2fc7b0e4f8..0af866d4fc 100644 --- a/web/screens/Thread/ThreadLeftPanel/index.tsx +++ b/web/screens/Thread/ThreadLeftPanel/index.tsx @@ -15,6 +15,8 @@ import useAssistantQuery from '@/hooks/useAssistantQuery' import useThreads from '@/hooks/useThreads' +import { copyOverInstructionEnabledAtom } from '@/screens/Settings/Advanced/components/CopyOverInstruction' + import ThreadItem from './ThreadItem' import { @@ -22,7 +24,7 @@ import { getSelectedModelAtom, } from '@/helpers/atoms/Model.atom' import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom' -import { getActiveThreadIdAtom, threadsAtom } from '@/helpers/atoms/Thread.atom' +import { activeThreadAtom, threadsAtom } from '@/helpers/atoms/Thread.atom' const ThreadLeftPanel: React.FC = () => { const { createThread, setActiveThread } = useThreads() @@ -30,11 +32,13 @@ const ThreadLeftPanel: React.FC = () => { const downloadedModels = useAtomValue(downloadedModelsAtom) const selectedModel = useAtomValue(getSelectedModelAtom) const threads = useAtomValue(threadsAtom) - const activeThreadId = useAtomValue(getActiveThreadIdAtom) + const activeThread = useAtomValue(activeThreadAtom) const { data: assistants } = useAssistantQuery() - const isCreatingThread = useRef(false) + const copyOverInstructionEnabled = useAtomValue( + copyOverInstructionEnabledAtom + ) useEffect(() => { // if user does not have any threads, we should create one @@ -52,13 +56,10 @@ const ThreadLeftPanel: React.FC = () => { }, [threads, assistants, downloadedModels, createThread]) useEffect(() => { - const setActiveThreadIfNone = () => { - if (activeThreadId) return - if (threads.length === 0) return - setActiveThread(threads[0].id) - } - setActiveThreadIfNone() - }, [activeThreadId, setActiveThread, threads]) + if (activeThread?.id) return + if (threads.length === 0) return + setActiveThread(threads[0].id) + }, [activeThread?.id, setActiveThread, threads]) const onCreateThreadClicked = useCallback(async () => { if (!assistants || assistants.length === 0) { @@ -70,8 +71,18 @@ const ThreadLeftPanel: React.FC = () => { return } if (!selectedModel) return - createThread(selectedModel.model, assistants[0]) - }, [createThread, selectedModel, assistants]) + let instructions: string | undefined = undefined + if (copyOverInstructionEnabled) { + instructions = activeThread?.assistants[0]?.instructions ?? undefined + } + createThread(selectedModel.model, assistants[0], instructions) + }, [ + createThread, + selectedModel, + assistants, + activeThread, + copyOverInstructionEnabled, + ]) return (