From 4a7986f041b74bb4780b6e4fed47f8e24809557a Mon Sep 17 00:00:00 2001 From: who is Date: Wed, 10 Dec 2025 00:44:38 +0000 Subject: [PATCH] feat: support clipboard images in mini assistant --- .../src/windows/mini/home/HomeWindow.tsx | 34 +++++++++++++++++-- .../windows/mini/home/components/InputBar.tsx | 5 ++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/windows/mini/home/HomeWindow.tsx b/src/renderer/src/windows/mini/home/HomeWindow.tsx index 23787066e8..77aa0b9abe 100644 --- a/src/renderer/src/windows/mini/home/HomeWindow.tsx +++ b/src/renderer/src/windows/mini/home/HomeWindow.tsx @@ -7,12 +7,14 @@ import i18n from '@renderer/i18n' import { fetchChatCompletion } from '@renderer/services/ApiService' import { getDefaultTopic } from '@renderer/services/AssistantService' import { ConversationService } from '@renderer/services/ConversationService' +import FileManager from '@renderer/services/FileManager' import { getAssistantMessage, getUserMessage } from '@renderer/services/MessagesService' +import PasteService from '@renderer/services/PasteService' import store, { useAppSelector } from '@renderer/store' import { updateOneBlock, upsertManyBlocks, upsertOneBlock } from '@renderer/store/messageBlock' import { newMessagesActions, selectMessagesForTopic } from '@renderer/store/newMessage' import { cancelThrottledBlockUpdate, throttledBlockUpdate } from '@renderer/store/thunk/messageThunk' -import type { Topic } from '@renderer/types' +import type { FileMetadata, Topic } from '@renderer/types' import { ThemeMode } from '@renderer/types' import type { Chunk } from '@renderer/types/chunk' import { ChunkType } from '@renderer/types/chunk' @@ -51,6 +53,7 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { const [isFirstMessage, setIsFirstMessage] = useState(true) const [userInputText, setUserInputText] = useState('') + const [files, setFiles] = useState([]) const [clipboardText, setClipboardText] = useState('') const lastClipboardTextRef = useRef(null) @@ -73,6 +76,8 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { const inputBarRef = useRef(null) const featureMenusRef = useRef(null) + const supportedImageExts = useMemo(() => ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'], []) + const referenceText = useMemo(() => clipboardText || userInputText, [clipboardText, userInputText]) const userContent = useMemo(() => { @@ -213,6 +218,23 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { setUserInputText(e.target.value) } + const handlePaste = useCallback( + async (event: React.ClipboardEvent) => { + await PasteService.handlePaste( + event.nativeEvent, + supportedImageExts, + setFiles, + setUserInputText, + false, + undefined, + userInputText, + undefined, + t + ) + }, + [supportedImageExts, t, userInputText] + ) + const handleError = (error: Error) => { setIsLoading(false) setError(error.message) @@ -227,10 +249,13 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { try { const topicId = currentTopic.current.id + const uploadedFiles = files.length ? await FileManager.uploadFiles(files) : [] + const { message: userMessage, blocks } = getUserMessage({ content: [prompt, userContent].filter(Boolean).join('\n\n'), assistant: currentAssistant, - topic: currentTopic.current + topic: currentTopic.current, + files: uploadedFiles }) store.dispatch(newMessagesActions.addMessage({ topicId, message: userMessage })) @@ -272,6 +297,7 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { setIsFirstMessage(false) setUserInputText('') + setFiles([]) const newAssistant = cloneDeep(currentAssistant) if (!newAssistant.settings) { @@ -452,7 +478,7 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { currentAskId.current = '' } }, - [userContent, currentAssistant] + [files, userContent, currentAssistant] ) const handlePause = useCallback(() => { @@ -546,6 +572,7 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { loading={isLoading} handleKeyDown={handleKeyDown} handleChange={handleChange} + handlePaste={handlePaste} ref={inputBarRef} /> @@ -590,6 +617,7 @@ const HomeWindow: FC<{ draggable?: boolean }> = ({ draggable = true }) => { loading={isLoading} handleKeyDown={handleKeyDown} handleChange={handleChange} + handlePaste={handlePaste} ref={inputBarRef} /> diff --git a/src/renderer/src/windows/mini/home/components/InputBar.tsx b/src/renderer/src/windows/mini/home/components/InputBar.tsx index 648b72080e..3b3597f084 100644 --- a/src/renderer/src/windows/mini/home/components/InputBar.tsx +++ b/src/renderer/src/windows/mini/home/components/InputBar.tsx @@ -14,6 +14,7 @@ interface InputBarProps { loading: boolean handleKeyDown: (e: React.KeyboardEvent) => void handleChange: (e: React.ChangeEvent) => void + handlePaste: (e: React.ClipboardEvent) => void } const InputBar = ({ @@ -23,7 +24,8 @@ const InputBar = ({ placeholder, loading, handleKeyDown, - handleChange + handleChange, + handlePaste }: InputBarProps & { ref?: React.RefObject }) => { const inputRef = useRef(null) const { setTimeoutTimer } = useTimer() @@ -40,6 +42,7 @@ const InputBar = ({ autoFocus onKeyDown={handleKeyDown} onChange={handleChange} + onPaste={handlePaste} ref={inputRef} />