refactor(Inputbar, Messages): simplify clear topic functionality and improve message display logic
- Removed unused QuestionCircleOutlined icon and Popconfirm from Inputbar, replacing it with a direct button click for clearing topics. - Refactored message display logic in Messages component to enhance clarity and maintainability, while preserving existing functionality.
This commit is contained in:
parent
d4bf8da225
commit
0e7c4e4bdd
@ -9,7 +9,6 @@ import {
|
|||||||
HolderOutlined,
|
HolderOutlined,
|
||||||
PaperClipOutlined,
|
PaperClipOutlined,
|
||||||
PauseCircleOutlined,
|
PauseCircleOutlined,
|
||||||
QuestionCircleOutlined,
|
|
||||||
ThunderboltOutlined,
|
ThunderboltOutlined,
|
||||||
TranslationOutlined
|
TranslationOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
@ -40,7 +39,7 @@ import { Assistant, FileType, KnowledgeBase, KnowledgeItem, MCPServer, Message,
|
|||||||
import { classNames, delay, formatFileSize, getFileExtension } from '@renderer/utils'
|
import { classNames, delay, formatFileSize, getFileExtension } from '@renderer/utils'
|
||||||
import { getFilesFromDropEvent } from '@renderer/utils/input'
|
import { getFilesFromDropEvent } from '@renderer/utils/input'
|
||||||
import { documentExts, imageExts, textExts } from '@shared/config/constant'
|
import { documentExts, imageExts, textExts } from '@shared/config/constant'
|
||||||
import { Button, Popconfirm, Tooltip } from 'antd'
|
import { Button, Tooltip } from 'antd'
|
||||||
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
|
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import Logger from 'electron-log/renderer'
|
import Logger from 'electron-log/renderer'
|
||||||
@ -695,9 +694,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
textareaRef.current?.focus()
|
textareaRef.current?.focus()
|
||||||
})
|
})
|
||||||
|
|
||||||
useShortcut('clear_topic', () => {
|
useShortcut('clear_topic', clearTopic)
|
||||||
clearTopic()
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const _setEstimateTokenCount = debounce(setEstimateTokenCount, 100, { leading: false, trailing: true })
|
const _setEstimateTokenCount = debounce(setEstimateTokenCount, 100, { leading: false, trailing: true })
|
||||||
@ -991,17 +988,9 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
ToolbarButton={ToolbarButton}
|
ToolbarButton={ToolbarButton}
|
||||||
/>
|
/>
|
||||||
<Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow>
|
<Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow>
|
||||||
<Popconfirm
|
<ToolbarButton type="text" onClick={clearTopic}>
|
||||||
title={t('chat.input.clear.content')}
|
<ClearOutlined style={{ fontSize: 17 }} />
|
||||||
placement="top"
|
</ToolbarButton>
|
||||||
onConfirm={clearTopic}
|
|
||||||
okButtonProps={{ danger: true }}
|
|
||||||
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
|
|
||||||
okText={t('chat.input.clear.title')}>
|
|
||||||
<ToolbarButton type="text">
|
|
||||||
<ClearOutlined style={{ fontSize: 17 }} />
|
|
||||||
</ToolbarButton>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
|
<Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
|
||||||
<ToolbarButton type="text" onClick={onToggleExpended}>
|
<ToolbarButton type="text" onClick={onToggleExpended}>
|
||||||
|
|||||||
@ -38,42 +38,6 @@ interface MessagesProps {
|
|||||||
setActiveTopic: (topic: Topic) => void
|
setActiveTopic: (topic: Topic) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const computeDisplayMessages = (messages: Message[], startIndex: number, displayCount: number) => {
|
|
||||||
const reversedMessages = [...messages].reverse()
|
|
||||||
|
|
||||||
// 如果剩余消息数量小于 displayCount,直接返回所有剩余消息
|
|
||||||
if (reversedMessages.length - startIndex <= displayCount) {
|
|
||||||
return reversedMessages.slice(startIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
const userIdSet = new Set() // 用户消息 id 集合
|
|
||||||
const assistantIdSet = new Set() // 助手消息 askId 集合
|
|
||||||
const displayMessages: Message[] = []
|
|
||||||
|
|
||||||
// 处理单条消息的函数
|
|
||||||
const processMessage = (message: Message) => {
|
|
||||||
if (!message) return
|
|
||||||
|
|
||||||
const idSet = message.role === 'user' ? userIdSet : assistantIdSet
|
|
||||||
const messageId = message.role === 'user' ? message.id : message.askId
|
|
||||||
|
|
||||||
if (!idSet.has(messageId)) {
|
|
||||||
idSet.add(messageId)
|
|
||||||
displayMessages.push(message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 如果是相同 askId 的助手消息,也要显示
|
|
||||||
displayMessages.push(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历消息直到满足显示数量要求
|
|
||||||
for (let i = startIndex; i < reversedMessages.length && userIdSet.size + assistantIdSet.size < displayCount; i++) {
|
|
||||||
processMessage(reversedMessages[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return displayMessages
|
|
||||||
}
|
|
||||||
|
|
||||||
const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic }) => {
|
const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { showTopics, topicPosition, showAssistants, messageNavigation } = useSettings()
|
const { showTopics, topicPosition, showAssistants, messageNavigation } = useSettings()
|
||||||
@ -118,24 +82,36 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const clearTopic = useCallback(
|
||||||
|
async (data: Topic) => {
|
||||||
|
const defaultTopic = getDefaultTopic(assistant.id)
|
||||||
|
|
||||||
|
if (data && data.id !== topic.id) {
|
||||||
|
await clearTopicMessages(data.id)
|
||||||
|
updateTopic({ ...data, name: defaultTopic.name } as Topic)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await clearTopicMessages()
|
||||||
|
|
||||||
|
setDisplayMessages([])
|
||||||
|
|
||||||
|
const _topic = getTopic(assistant, topic.id)
|
||||||
|
_topic && updateTopic({ ..._topic, name: defaultTopic.name } as Topic)
|
||||||
|
},
|
||||||
|
[assistant, clearTopicMessages, topic.id, updateTopic]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribes = [
|
const unsubscribes = [
|
||||||
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, scrollToBottom),
|
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, scrollToBottom),
|
||||||
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => {
|
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => {
|
||||||
const defaultTopic = getDefaultTopic(assistant.id)
|
window.modal.confirm({
|
||||||
|
title: t('chat.input.clear.title'),
|
||||||
if (data && data.id !== topic.id) {
|
content: t('chat.input.clear.content'),
|
||||||
await clearTopicMessages(data.id)
|
centered: true,
|
||||||
updateTopic({ ...data, name: defaultTopic.name } as Topic)
|
onOk: () => clearTopic(data)
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
await clearTopicMessages()
|
|
||||||
setDisplayMessages([])
|
|
||||||
const _topic = getTopic(assistant, topic.id)
|
|
||||||
if (_topic) {
|
|
||||||
updateTopic({ ..._topic, name: defaultTopic.name } as Topic)
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
EventEmitter.on(EVENT_NAMES.COPY_TOPIC_IMAGE, async () => {
|
EventEmitter.on(EVENT_NAMES.COPY_TOPIC_IMAGE, async () => {
|
||||||
await captureScrollableDivAsBlob(containerRef, async (blob) => {
|
await captureScrollableDivAsBlob(containerRef, async (blob) => {
|
||||||
@ -280,11 +256,43 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoaderProps {
|
const computeDisplayMessages = (messages: Message[], startIndex: number, displayCount: number) => {
|
||||||
$loading: boolean
|
const reversedMessages = [...messages].reverse()
|
||||||
|
|
||||||
|
// 如果剩余消息数量小于 displayCount,直接返回所有剩余消息
|
||||||
|
if (reversedMessages.length - startIndex <= displayCount) {
|
||||||
|
return reversedMessages.slice(startIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
const userIdSet = new Set() // 用户消息 id 集合
|
||||||
|
const assistantIdSet = new Set() // 助手消息 askId 集合
|
||||||
|
const displayMessages: Message[] = []
|
||||||
|
|
||||||
|
// 处理单条消息的函数
|
||||||
|
const processMessage = (message: Message) => {
|
||||||
|
if (!message) return
|
||||||
|
|
||||||
|
const idSet = message.role === 'user' ? userIdSet : assistantIdSet
|
||||||
|
const messageId = message.role === 'user' ? message.id : message.askId
|
||||||
|
|
||||||
|
if (!idSet.has(messageId)) {
|
||||||
|
idSet.add(messageId)
|
||||||
|
displayMessages.push(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 如果是相同 askId 的助手消息,也要显示
|
||||||
|
displayMessages.push(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历消息直到满足显示数量要求
|
||||||
|
for (let i = startIndex; i < reversedMessages.length && userIdSet.size + assistantIdSet.size < displayCount; i++) {
|
||||||
|
processMessage(reversedMessages[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoaderContainer = styled.div<LoaderProps>`
|
const LoaderContainer = styled.div<{ $loading: boolean }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user