fix: performance issue when pasting long content into the chat input box (#4240)

This commit is contained in:
Faisal Amir 2024-12-06 16:48:01 +08:00 committed by GitHub
parent 3341a3be15
commit 21389070fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 61 additions and 15 deletions

View File

@ -1,15 +1,40 @@
import { PropsWithChildren } from 'react'
import { useMediaQuery } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
import { MainViewState } from '@/constants/screens'
import { LEFT_PANEL_WIDTH } from '../LeftPanelContainer'
import { RIGHT_PANEL_WIDTH } from '../RightPanelContainer'
import {
mainViewStateAtom,
showLeftPanelAtom,
showRightPanelAtom,
} from '@/helpers/atoms/App.atom'
import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
const CenterPanelContainer = ({ children }: PropsWithChildren) => {
const reduceTransparent = useAtomValue(reduceTransparentAtom)
const matches = useMediaQuery('(max-width: 880px)')
const showLeftPanel = useAtomValue(showLeftPanelAtom)
const showRightPanel = useAtomValue(showRightPanelAtom)
const mainViewState = useAtomValue(mainViewStateAtom)
return (
<div className={twMerge('flex h-full w-full')}>
<div
className={twMerge('flex h-full w-full')}
style={{
maxWidth: matches
? '100%'
: mainViewState === MainViewState.Thread
? `calc(100% - (${showRightPanel ? Number(localStorage.getItem(RIGHT_PANEL_WIDTH)) : 0}px + ${showLeftPanel ? Number(localStorage.getItem(LEFT_PANEL_WIDTH)) : 0}px))`
: '100%',
}}
>
<div
className={twMerge(
'h-full w-full overflow-hidden bg-[hsla(var(--center-panel-bg))]',

View File

@ -1,6 +1,6 @@
'use client'
import { useEffect, useMemo } from 'react'
import { useEffect } from 'react'
import { useAtomValue, useSetAtom } from 'jotai'

View File

@ -17,7 +17,7 @@ import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
type Props = PropsWithChildren
const DEFAULT_LEFT_PANEL_WIDTH = 200
const LEFT_PANEL_WIDTH = 'leftPanelWidth'
export const LEFT_PANEL_WIDTH = 'leftPanelWidth'
const LeftPanelContainer = ({ children }: Props) => {
const [leftPanelRef, setLeftPanelRef] = useState<HTMLDivElement | null>(null)

View File

@ -37,7 +37,7 @@ const MainViewContainer = () => {
}
return (
<div className={twMerge('relative flex w-full')}>
<div className={twMerge('relative flex w-[calc(100%-48px)]')}>
<div className="w-full">
<m.div
key={mainViewState}

View File

@ -16,13 +16,13 @@ import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
type Props = PropsWithChildren
const DEFAULT_RIGTH_PANEL_WIDTH = 280
const RIGHT_PANEL_WIDTH = 'rightPanelWidth'
const DEFAULT_RIGHT_PANEL_WIDTH = 280
export const RIGHT_PANEL_WIDTH = 'rightPanelWidth'
const RightPanelContainer = ({ children }: Props) => {
const [isResizing, setIsResizing] = useState(false)
const [threadRightPanelWidth, setRightPanelWidth] = useState(
Number(localStorage.getItem(RIGHT_PANEL_WIDTH)) || DEFAULT_RIGTH_PANEL_WIDTH
Number(localStorage.getItem(RIGHT_PANEL_WIDTH)) || DEFAULT_RIGHT_PANEL_WIDTH
)
const [rightPanelRef, setRightPanelRef] = useState<HTMLDivElement | null>(
null
@ -55,11 +55,11 @@ const RightPanelContainer = ({ children }: Props) => {
mouseMoveEvent.clientX <
200
) {
setRightPanelWidth(DEFAULT_RIGTH_PANEL_WIDTH)
setRightPanelWidth(DEFAULT_RIGHT_PANEL_WIDTH)
setIsResizing(false)
localStorage.setItem(
RIGHT_PANEL_WIDTH,
String(DEFAULT_RIGTH_PANEL_WIDTH)
String(DEFAULT_RIGHT_PANEL_WIDTH)
)
setShowRightPanel(false)
} else {
@ -77,8 +77,8 @@ const RightPanelContainer = ({ children }: Props) => {
useEffect(() => {
if (localStorage.getItem(RIGHT_PANEL_WIDTH) === null) {
setRightPanelWidth(DEFAULT_RIGTH_PANEL_WIDTH)
localStorage.setItem(RIGHT_PANEL_WIDTH, String(DEFAULT_RIGTH_PANEL_WIDTH))
setRightPanelWidth(DEFAULT_RIGHT_PANEL_WIDTH)
localStorage.setItem(RIGHT_PANEL_WIDTH, String(DEFAULT_RIGHT_PANEL_WIDTH))
}
window.addEventListener('mousemove', resize)
window.addEventListener('mouseup', stopResizing)

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback, useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useMemo, useRef, ClipboardEvent } from 'react'
import { MessageStatus } from '@janhq/core'
import hljs from 'highlight.js'
@ -67,7 +67,7 @@ const RichTextEditor = ({
placeholder,
spellCheck,
}: RichTextEditorProps) => {
const [editor] = useState(() => withHistory(withReact(createEditor())))
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
const currentLanguage = useRef<string>('plaintext')
const hasStartBackticks = useRef<boolean>(false)
const hasEndBackticks = useRef<boolean>(false)
@ -80,6 +80,8 @@ const RichTextEditor = ({
const { sendChatMessage } = useSendChatMessage()
const { stopInference } = useActiveModel()
const largeContentThreshold = 1000
// The decorate function identifies code blocks and marks the ranges
const decorate = useCallback(
(entry: [any, any]) => {
@ -324,6 +326,16 @@ const RichTextEditor = ({
[currentPrompt, editor, messages]
)
const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {
const clipboardData = event.clipboardData || (window as any).clipboardData
const pastedData = clipboardData.getData('text')
if (pastedData.length > largeContentThreshold) {
event.preventDefault() // Prevent the default paste behavior
Transforms.insertText(editor, pastedData) // Insert the content directly into the editor
}
}
return (
<Slate
editor={editor}
@ -362,9 +374,18 @@ const RichTextEditor = ({
>
<Editable
ref={textareaRef}
decorate={decorate} // Pass the decorate function
decorate={(entry) => {
// Skip decorate if content exceeds threshold
if (
currentPrompt.length > largeContentThreshold ||
!currentPrompt.length
)
return []
return decorate(entry)
}}
renderLeaf={renderLeaf} // Pass the renderLeaf function
onKeyDown={handleKeyDown}
onPaste={handlePaste} // Add the custom paste handler
className={twMerge(
className,
disabled &&

View File

@ -337,7 +337,7 @@ const ChatInput = () => {
{activeSettingInputBox && (
<div
className={twMerge(
'absolute bottom-[6px] left-[1px] flex w-[calc(100%-10px)] items-center justify-between rounded-b-lg bg-[hsla(var(--center-panel-bg))] p-3 pr-0',
'absolute bottom-[5px] left-[1px] flex w-[calc(100%-10px)] items-center justify-between rounded-b-lg bg-[hsla(var(--center-panel-bg))] p-3 pr-0',
!activeThread && 'bg-transparent',
stateModel.loading && 'bg-transparent'
)}