From ae4542ce68d122f4e5b1f7f4d459fd924d02d03f Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Sat, 21 Sep 2024 00:04:53 +0800 Subject: [PATCH] feat: improved input bar functionality and added text insertion feature - Improved functionality for handling text input and file uploads in the input bar. - Added functionality to insert text at cursor position in a text area. --- .../src/pages/home/Inputbar/Inputbar.tsx | 22 ++++++------- src/renderer/src/utils/input.ts | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 src/renderer/src/utils/input.ts diff --git a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx index af948f08..31ff578f 100644 --- a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx +++ b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx @@ -21,6 +21,7 @@ import store, { useAppDispatch, useAppSelector } from '@renderer/store' import { setGenerating, setSearching } from '@renderer/store/runtime' import { Assistant, FileType, Message, Topic } from '@renderer/types' import { delay, getFileExtension, uuid } from '@renderer/utils' +import { insertTextAtCursor } from '@renderer/utils/input' import { Button, Popconfirm, Tooltip } from 'antd' import TextArea, { TextAreaRef } from 'antd/es/input/TextArea' import dayjs from 'dayjs' @@ -40,6 +41,7 @@ interface Props { } let _text = '' +let _files: FileType[] = [] const Inputbar: FC = ({ assistant, setActiveTopic }) => { const [text, setText] = useState(_text) @@ -60,8 +62,10 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { const isVision = useMemo(() => isVisionModel(model), [model]) const supportExts = useMemo(() => [...textExts, ...(isVision ? imageExts : [])], [isVision]) + const inputTokenCount = useMemo(() => estimateTextTokens(text), [text]) _text = text + _files = files const sendMessage = useCallback(async () => { if (generating) { @@ -96,8 +100,6 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { setExpend(false) }, [assistant.id, assistant.topics, generating, files, text]) - const inputTokenCount = useMemo(() => estimateTextTokens(text), [text]) - const handleKeyDown = (event: React.KeyboardEvent) => { const isEnterPressed = event.keyCode == 13 @@ -142,10 +144,7 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { } const onNewContext = () => { - if (generating) { - onPause() - return - } + if (generating) return onPause() EventEmitter.emit(EVENT_NAMES.NEW_CONTEXT) } @@ -204,22 +203,21 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { const item = event.clipboardData?.items[0] if (item && item.kind === 'string' && item.type === 'text/plain') { event.preventDefault() - item.getAsString(async (text) => { - if (text.length > 1500) { - console.debug(item.getAsFile()) + item.getAsString(async (pasteText) => { + if (pasteText.length > 1500) { const tempFilePath = await window.api.file.create('pasted_text.txt') - await window.api.file.write(tempFilePath, text) + await window.api.file.write(tempFilePath, pasteText) const selectedFile = await window.api.file.get(tempFilePath) selectedFile && setFiles((prevFiles) => [...prevFiles, selectedFile]) } else { - setText((prevText) => prevText + text) + insertTextAtCursor({ text, pasteText, textareaRef, setText }) setTimeout(() => resizeTextArea(), 0) } }) } } }, - [supportExts, pasteLongTextAsFile] + [pasteLongTextAsFile, supportExts, text] ) // Command or Ctrl + N create new topic diff --git a/src/renderer/src/utils/input.ts b/src/renderer/src/utils/input.ts new file mode 100644 index 00000000..9c0d1286 --- /dev/null +++ b/src/renderer/src/utils/input.ts @@ -0,0 +1,31 @@ +import { TextAreaRef } from 'antd/es/input/TextArea' +import { RefObject } from 'react' + +export const insertTextAtCursor = ({ + text, + pasteText, + textareaRef, + setText +}: { + text: string + pasteText: string + textareaRef: RefObject + setText: (text: string) => void +}) => { + const textarea = textareaRef.current?.resizableTextArea?.textArea + + if (!textarea) { + return + } + + const start = textarea.selectionStart + const end = textarea.selectionEnd + const newValue = text.substring(0, start) + pasteText + text.substring(end) + + setText(newValue) + + setTimeout(() => { + textarea.setSelectionRange(start + pasteText.length, start + pasteText.length) + textarea.focus() + }, 0) +}