mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 18:10:26 +08:00
refactor: update message handling and state management
- Simplified message editing logic by removing unnecessary success/error logging. - Added `updatedAt` timestamp to message updates for better tracking. - Refactored `editMessageBlocks` to accept message ID and updates directly. - Removed unused `getTopicLimit` function from `TopicManager`. - Updated message rendering to use `updatedAt` when available. - Enhanced type definitions to include `updatedAt` in message structure.
This commit is contained in:
parent
5b95d20294
commit
6da1d08c9a
@ -79,7 +79,7 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑消息。(目前仅更新 Redux state)。 / Edits a message. (Currently only updates Redux state).
|
* 编辑消息。 / Edits a message.
|
||||||
* 使用 newMessagesActions.updateMessage.
|
* 使用 newMessagesActions.updateMessage.
|
||||||
*/
|
*/
|
||||||
const editMessage = useCallback(
|
const editMessage = useCallback(
|
||||||
@ -92,17 +92,12 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
|
|
||||||
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
id: messageId,
|
id: messageId,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
...updates
|
...updates
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the thunk with topic.id and only message updates
|
// Call the thunk with topic.id and only message updates
|
||||||
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, []))
|
await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, []))
|
||||||
|
|
||||||
if (success) {
|
|
||||||
console.log(`[useMessageOperations] Successfully edited message ${messageId} properties.`)
|
|
||||||
} else {
|
|
||||||
console.error(`[useMessageOperations] Failed to edit message ${messageId} properties.`)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
)
|
)
|
||||||
@ -133,9 +128,16 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
const files = findFileBlocks(message).map((block) => block.file)
|
const files = findFileBlocks(message).map((block) => block.file)
|
||||||
|
|
||||||
const usage = await estimateUserPromptUsage({ content: editedContent, files })
|
const usage = await estimateUserPromptUsage({ content: editedContent, files })
|
||||||
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
|
id: message.id,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
|
||||||
await dispatch(updateMessageAndBlocksThunk(topic.id, { id: message.id, usage }, []))
|
await dispatch(
|
||||||
|
newMessagesActions.updateMessage({ topicId: topic.id, messageId: message.id, updates: messageUpdates })
|
||||||
|
)
|
||||||
|
// 对于message的修改会在下面的thunk中保存
|
||||||
await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant))
|
await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant))
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
@ -313,29 +315,23 @@ export function useMessageOperations(topic: Topic) {
|
|||||||
* Uses the generalized thunk for persistence.
|
* Uses the generalized thunk for persistence.
|
||||||
*/
|
*/
|
||||||
const editMessageBlocks = useCallback(
|
const editMessageBlocks = useCallback(
|
||||||
// messageId?: string
|
async (messageId: string, updates: Partial<MessageBlock>) => {
|
||||||
async (blockUpdatesListRaw: Partial<MessageBlock>[]) => {
|
|
||||||
if (!topic?.id) {
|
if (!topic?.id) {
|
||||||
console.error('[editMessageBlocks] Topic prop is not valid.')
|
console.error('[editMessageBlocks] Topic prop is not valid.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!blockUpdatesListRaw || blockUpdatesListRaw.length === 0) {
|
|
||||||
console.warn('[editMessageBlocks] Received empty block updates list.')
|
const blockUpdatesListProcessed = {
|
||||||
return
|
updatedAt: new Date().toISOString(),
|
||||||
|
...updates
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockUpdatesListProcessed = blockUpdatesListRaw.map((update) => ({
|
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
|
||||||
...update,
|
id: messageId,
|
||||||
updatedAt: new Date().toISOString()
|
updatedAt: new Date().toISOString()
|
||||||
}))
|
|
||||||
|
|
||||||
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, null, blockUpdatesListProcessed))
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
// console.log(`[useMessageOperations] Successfully processed block updates for message ${messageId}.`)
|
|
||||||
} else {
|
|
||||||
// console.error(`[useMessageOperations] Failed to process block updates for message ${messageId}.`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, [blockUpdatesListProcessed]))
|
||||||
},
|
},
|
||||||
[dispatch, topic.id]
|
[dispatch, topic.id]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -107,14 +107,6 @@ export const autoRenameTopic = async (assistant: Assistant, topicId: string) =>
|
|||||||
// Convert class to object with functions since class only has static methods
|
// Convert class to object with functions since class only has static methods
|
||||||
// 只有静态方法,没必要用class,可以export {}
|
// 只有静态方法,没必要用class,可以export {}
|
||||||
export const TopicManager = {
|
export const TopicManager = {
|
||||||
async getTopicLimit(limit: number) {
|
|
||||||
return await db.topics
|
|
||||||
.orderBy('updatedAt') // 按 updatedAt 排序(默认升序)
|
|
||||||
.reverse() // 逆序(变成降序)
|
|
||||||
.limit(limit) // 取前 10 条
|
|
||||||
.toArray()
|
|
||||||
},
|
|
||||||
|
|
||||||
async getTopic(id: string) {
|
async getTopic(id: string) {
|
||||||
return await db.topics.get(id)
|
return await db.topics.get(id)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -102,7 +102,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
|
|||||||
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
||||||
{username}
|
{username}
|
||||||
</UserName>
|
</UserName>
|
||||||
<MessageTime>{dayjs(message.createdAt).format('MM/DD HH:mm')}</MessageTime>
|
<MessageTime>{dayjs(message?.updatedAt ?? message.createdAt).format('MM/DD HH:mm')}</MessageTime>
|
||||||
</UserWrap>
|
</UserWrap>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@ -164,7 +164,7 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
if (resendMessage) {
|
if (resendMessage) {
|
||||||
resendUserMessageWithEdit(message, editedText, assistant)
|
resendUserMessageWithEdit(message, editedText, assistant)
|
||||||
} else {
|
} else {
|
||||||
editMessageBlocks([{ ...findMainTextBlocks(message)[0], content: editedText }])
|
editMessageBlocks(message.id, { id: findMainTextBlocks(message)[0].id, content: editedText })
|
||||||
}
|
}
|
||||||
// // 更新消息内容,保留图片信息
|
// // 更新消息内容,保留图片信息
|
||||||
// await editMessage(message.id, {
|
// await editMessage(message.id, {
|
||||||
|
|||||||
@ -867,6 +867,7 @@ export const resendMessageThunk =
|
|||||||
const blockIdsToDelete = [...(originalMsg.blocks || [])]
|
const blockIdsToDelete = [...(originalMsg.blocks || [])]
|
||||||
const resetMsg = resetAssistantMessage(originalMsg, {
|
const resetMsg = resetAssistantMessage(originalMsg, {
|
||||||
status: AssistantMessageStatus.PENDING,
|
status: AssistantMessageStatus.PENDING,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {})
|
...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -969,7 +970,8 @@ export const regenerateAssistantResponseThunk =
|
|||||||
|
|
||||||
// 5. Reset the message entity in Redux
|
// 5. Reset the message entity in Redux
|
||||||
const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, {
|
const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, {
|
||||||
status: AssistantMessageStatus.PENDING
|
status: AssistantMessageStatus.PENDING,
|
||||||
|
updatedAt: new Date().toISOString()
|
||||||
})
|
})
|
||||||
dispatch(
|
dispatch(
|
||||||
newMessagesActions.updateMessage({
|
newMessagesActions.updateMessage({
|
||||||
|
|||||||
@ -161,7 +161,7 @@ export type Message = {
|
|||||||
assistantId: string
|
assistantId: string
|
||||||
topicId: string
|
topicId: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
// updatedAt?: string
|
updatedAt?: string
|
||||||
status: UserMessageStatus | AssistantMessageStatus
|
status: UserMessageStatus | AssistantMessageStatus
|
||||||
|
|
||||||
// 消息元数据
|
// 消息元数据
|
||||||
|
|||||||
@ -384,7 +384,7 @@ export function resetMessage(
|
|||||||
*/
|
*/
|
||||||
export const resetAssistantMessage = (
|
export const resetAssistantMessage = (
|
||||||
originalMessage: Message,
|
originalMessage: Message,
|
||||||
updates?: Partial<Pick<Message, 'status'>> // Primarily allow updating status
|
updates?: Partial<Pick<Message, 'status' | 'updatedAt'>> // Primarily allow updating status
|
||||||
): Message => {
|
): Message => {
|
||||||
// Ensure we are only resetting assistant messages
|
// Ensure we are only resetting assistant messages
|
||||||
if (originalMessage.role !== 'assistant') {
|
if (originalMessage.role !== 'assistant') {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user