refactor: Update message handling and improve Inputbar functionality
- Modified Inputbar to include a new resizeTextArea function for better text area management. - Adjusted MessageGroup and MessageStream components to remove unnecessary props and streamline message handling. - Enhanced message dispatching logic in the messages store for improved state management. - Cleaned up unused imports and code in Message components to enhance readability and maintainability.
This commit is contained in:
parent
ca085a807e
commit
93ad07b44e
3
src/preload/index.d.ts
vendored
3
src/preload/index.d.ts
vendored
@ -1,6 +1,7 @@
|
||||
import { ElectronAPI } from '@electron-toolkit/preload'
|
||||
import type { FileMetadataResponse, ListFilesResponse, UploadFileResponse } from '@google/generative-ai/server'
|
||||
import { ExtractChunkData } from '@llm-tools/embedjs-interfaces'
|
||||
import type { MCPServer, MCPTool } from '@renderer/types'
|
||||
import { AppInfo, FileType, KnowledgeBaseParams, KnowledgeItem, LanguageVarious, WebDavConfig } from '@renderer/types'
|
||||
import type { LoaderReturn } from '@shared/config/types'
|
||||
import type { OpenDialogOptions } from 'electron'
|
||||
@ -129,7 +130,7 @@ declare global {
|
||||
deleteServer: (serverName: string) => Promise<void>
|
||||
setServerActive: (name: string, isActive: boolean) => Promise<void>
|
||||
// tools
|
||||
listTools: () => Promise<MCPTool>
|
||||
listTools: () => Promise<MCPTool[]>
|
||||
callTool: ({ client, name, args }: { client: string; name: string; args: any }) => Promise<any>
|
||||
// status
|
||||
cleanup: () => Promise<void>
|
||||
|
||||
@ -132,6 +132,18 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
_text = text
|
||||
_files = files
|
||||
|
||||
const resizeTextArea = useCallback(() => {
|
||||
const textArea = textareaRef.current?.resizableTextArea?.textArea
|
||||
if (textArea) {
|
||||
// 如果已经手动设置了高度,则不自动调整
|
||||
if (textareaHeight) {
|
||||
return
|
||||
}
|
||||
textArea.style.height = 'auto'
|
||||
textArea.style.height = textArea?.scrollHeight > 400 ? '400px' : `${textArea?.scrollHeight}px`
|
||||
}
|
||||
}, [textareaHeight])
|
||||
|
||||
const sendMessage = useCallback(async () => {
|
||||
if (inputEmpty || loading) {
|
||||
return
|
||||
@ -174,7 +186,19 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
} catch (error) {
|
||||
console.error('Failed to send message:', error)
|
||||
}
|
||||
}, [inputEmpty, files, dispatch, text, assistant, topic, selectedKnowledgeBases, mentionModels, enabledMCPs, loading])
|
||||
}, [
|
||||
assistant,
|
||||
dispatch,
|
||||
enabledMCPs,
|
||||
files,
|
||||
inputEmpty,
|
||||
loading,
|
||||
mentionModels,
|
||||
resizeTextArea,
|
||||
selectedKnowledgeBases,
|
||||
text,
|
||||
topic
|
||||
])
|
||||
|
||||
const translate = async () => {
|
||||
if (isTranslating) {
|
||||
@ -318,18 +342,6 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
EventEmitter.emit(EVENT_NAMES.NEW_CONTEXT)
|
||||
}
|
||||
|
||||
const resizeTextArea = () => {
|
||||
const textArea = textareaRef.current?.resizableTextArea?.textArea
|
||||
if (textArea) {
|
||||
// 如果已经手动设置了高度,则不自动调整
|
||||
if (textareaHeight) {
|
||||
return
|
||||
}
|
||||
textArea.style.height = 'auto'
|
||||
textArea.style.height = textArea?.scrollHeight > 400 ? '400px' : `${textArea?.scrollHeight}px`
|
||||
}
|
||||
}
|
||||
|
||||
const onToggleExpended = () => {
|
||||
const isExpended = !expended
|
||||
setExpend(isExpended)
|
||||
|
||||
@ -4,7 +4,6 @@ import { MultiModelMessageStyle } from '@renderer/store/settings'
|
||||
import type { Message, Topic } from '@renderer/types'
|
||||
import { classNames } from '@renderer/utils'
|
||||
import { Popover } from 'antd'
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import { memo, useCallback, useEffect, useState } from 'react'
|
||||
import styled, { css } from 'styled-components'
|
||||
|
||||
@ -15,12 +14,10 @@ interface Props {
|
||||
messages: (Message & { index: number })[]
|
||||
topic: Topic
|
||||
hidePresetMessages?: boolean
|
||||
onSetMessages: Dispatch<SetStateAction<Message[]>>
|
||||
}
|
||||
|
||||
const MessageGroup = ({ messages, topic, hidePresetMessages, onSetMessages }: Props) => {
|
||||
const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
|
||||
const { multiModelMessageStyle: multiModelMessageStyleSetting, gridColumns, gridPopoverTrigger } = useSettings()
|
||||
// const { t } = useTranslation()
|
||||
|
||||
const [multiModelMessageStyle, setMultiModelMessageStyle] =
|
||||
useState<MultiModelMessageStyle>(multiModelMessageStyleSetting)
|
||||
@ -32,10 +29,6 @@ const MessageGroup = ({ messages, topic, hidePresetMessages, onSetMessages }: Pr
|
||||
const isHorizontal = multiModelMessageStyle === 'horizontal'
|
||||
const isGrid = multiModelMessageStyle === 'grid'
|
||||
|
||||
// const handleDeleteGroup = useCallback(async () => {
|
||||
|
||||
// }, [messages, t, deleteGroupMessages])
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedIndex(messageLength - 1)
|
||||
}, [messageLength])
|
||||
@ -51,10 +44,7 @@ const MessageGroup = ({ messages, topic, hidePresetMessages, onSetMessages }: Pr
|
||||
hidePresetMessages,
|
||||
style: {
|
||||
paddingTop: isGrouped && ['horizontal', 'grid'].includes(multiModelMessageStyle) ? 0 : 15
|
||||
},
|
||||
onSetMessages
|
||||
// onDeleteMessage,
|
||||
// onGetMessages
|
||||
}
|
||||
}
|
||||
|
||||
const messageWrapper = (
|
||||
@ -99,8 +89,6 @@ const MessageGroup = ({ messages, topic, hidePresetMessages, onSetMessages }: Pr
|
||||
selectedIndex,
|
||||
topic,
|
||||
hidePresetMessages,
|
||||
onSetMessages,
|
||||
// onDeleteMessage,
|
||||
gridPopoverTrigger
|
||||
]
|
||||
)
|
||||
|
||||
@ -14,7 +14,6 @@ interface MessageStreamProps {
|
||||
hidePresetMessages?: boolean
|
||||
isGrouped?: boolean
|
||||
style?: React.CSSProperties
|
||||
onSetMessages?: React.Dispatch<React.SetStateAction<Message[]>>
|
||||
}
|
||||
|
||||
const MessageStreamContainer = styled.div`
|
||||
@ -30,8 +29,7 @@ const MessageStream: React.FC<MessageStreamProps> = ({
|
||||
index,
|
||||
hidePresetMessages,
|
||||
isGrouped,
|
||||
style,
|
||||
onSetMessages
|
||||
style
|
||||
}) => {
|
||||
// 获取流式消息
|
||||
const streamMessage = useAppSelector((state) => selectStreamMessage(state, _message.topicId, _message.id))
|
||||
@ -63,7 +61,6 @@ const MessageStream: React.FC<MessageStreamProps> = ({
|
||||
isGrouped={isGrouped}
|
||||
style={style}
|
||||
isStreaming={isStreaming}
|
||||
onSetMessages={onSetMessages}
|
||||
/>
|
||||
</MessageStreamContainer>
|
||||
)
|
||||
|
||||
@ -200,7 +200,6 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
||||
messages={groupMessages}
|
||||
topic={topic}
|
||||
hidePresetMessages={assistant.settings?.hideMessages}
|
||||
onSetMessages={setDisplayMessages}
|
||||
/>
|
||||
))}
|
||||
</ScrollContainer>
|
||||
|
||||
@ -243,6 +243,7 @@ export const sendMessage =
|
||||
|
||||
// Initialize topic messages if not exists
|
||||
const initialState = getState()
|
||||
|
||||
if (!initialState.messages.messagesByTopic[topic.id]) {
|
||||
dispatch(clearTopicMessages(topic.id))
|
||||
}
|
||||
@ -278,6 +279,7 @@ export const sendMessage =
|
||||
assistantMessage.status = 'sending'
|
||||
assistantMessages.push(assistantMessage)
|
||||
}
|
||||
|
||||
dispatch(
|
||||
addMessage({
|
||||
topicId: topic.id,
|
||||
@ -287,6 +289,7 @@ export const sendMessage =
|
||||
}
|
||||
|
||||
const queue = getTopicQueue(topic.id)
|
||||
|
||||
for (const assistantMessage of assistantMessages) {
|
||||
// Set as stream message instead of adding to messages
|
||||
dispatch(setStreamMessage({ topicId: topic.id, message: assistantMessage }))
|
||||
@ -298,6 +301,7 @@ export const sendMessage =
|
||||
if (currentTopicMessages) {
|
||||
await syncMessagesWithDB(topic.id, currentTopicMessages)
|
||||
}
|
||||
|
||||
// 保证请求有序,防止请求静态,限制并发数量
|
||||
await queue.add(async () => {
|
||||
try {
|
||||
|
||||
@ -3,12 +3,10 @@ import { useModel } from '@renderer/hooks/useModel'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import MessageContent from '@renderer/pages/home/Messages/MessageContent'
|
||||
import MessageErrorBoundary from '@renderer/pages/home/Messages/MessageErrorBoundary'
|
||||
import { fetchChatCompletion } from '@renderer/services/ApiService'
|
||||
import { getDefaultAssistant, getDefaultModel } from '@renderer/services/AssistantService'
|
||||
import { getMessageModelId } from '@renderer/services/MessagesService'
|
||||
import { Message } from '@renderer/types'
|
||||
import { isMiniWindow } from '@renderer/utils'
|
||||
import { Dispatch, FC, memo, SetStateAction, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Dispatch, FC, memo, SetStateAction, useMemo, useRef } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface Props {
|
||||
@ -23,8 +21,7 @@ interface Props {
|
||||
const getMessageBackground = (isBubbleStyle: boolean, isAssistantMessage: boolean) =>
|
||||
isBubbleStyle ? (isAssistantMessage ? 'transparent' : 'var(--chat-background-user)') : undefined
|
||||
|
||||
const MessageItem: FC<Props> = ({ message: _message, index, total, route, onSetMessages, onGetMessages }) => {
|
||||
const [message, setMessage] = useState(_message)
|
||||
const MessageItem: FC<Props> = ({ message, index, total, route }) => {
|
||||
const model = useModel(getMessageModelId(message))
|
||||
const isBubbleStyle = true
|
||||
const { messageFont, fontSize } = useSettings()
|
||||
@ -40,32 +37,6 @@ const MessageItem: FC<Props> = ({ message: _message, index, total, route, onSetM
|
||||
|
||||
const maxWidth = isMiniWindow() ? '480px' : '100%'
|
||||
|
||||
useEffect(() => {
|
||||
if (onGetMessages && onSetMessages) {
|
||||
if (message.status === 'sending') {
|
||||
const messages = onGetMessages()
|
||||
fetchChatCompletion({
|
||||
message,
|
||||
messages: messages
|
||||
.filter((m) => !m.status.includes('ing'))
|
||||
.slice(
|
||||
0,
|
||||
messages.findIndex((m) => m.id === message.id)
|
||||
),
|
||||
assistant: { ...getDefaultAssistant(), model: getDefaultModel() },
|
||||
onResponse: (msg) => {
|
||||
setMessage(msg)
|
||||
if (msg.status !== 'pending') {
|
||||
const _messages = messages.map((m) => (m.id === msg.id ? msg : m))
|
||||
onSetMessages(_messages)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [message.status])
|
||||
|
||||
if (['summary', 'explanation'].includes(route) && index === total - 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
@ -23,12 +23,9 @@ const Messages: FC<Props> = ({ assistant, route }) => {
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const messagesRef = useRef(messages)
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
messagesRef.current = messages
|
||||
|
||||
const onSendMessage = useCallback(
|
||||
async (message: Message) => {
|
||||
setMessages((prev) => {
|
||||
@ -40,10 +37,6 @@ const Messages: FC<Props> = ({ assistant, route }) => {
|
||||
[assistant]
|
||||
)
|
||||
|
||||
const onGetMessages = useCallback(() => {
|
||||
return messagesRef.current
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribes = [EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, onSendMessage)]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
@ -60,15 +53,7 @@ const Messages: FC<Props> = ({ assistant, route }) => {
|
||||
return (
|
||||
<Container id="messages" key={assistant.id} ref={containerRef}>
|
||||
{[...messages].reverse().map((message, index) => (
|
||||
<MessageItem
|
||||
key={message.id}
|
||||
message={message}
|
||||
index={index}
|
||||
total={messages.length}
|
||||
onSetMessages={setMessages}
|
||||
onGetMessages={onGetMessages}
|
||||
route={route}
|
||||
/>
|
||||
<MessageItem key={message.id} message={message} index={index} total={messages.length} route={route} />
|
||||
))}
|
||||
</Container>
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user