refactor: unify message model handling across components

- Replaced direct usage of modelId with model object in Message, MessageHeader, MessageMenubar, and TranslatePage components for consistency.
- Introduced getMessageModelId utility function to streamline model retrieval from messages.
- Updated event handling in Messages component to align with new model structure.
- Enhanced code readability and maintainability by reducing redundancy in model handling.
This commit is contained in:
kangfenmao 2025-01-22 13:29:21 +08:00
parent 4d201059ad
commit a566b0e91a
9 changed files with 20 additions and 16 deletions

View File

@ -5,6 +5,7 @@ import { useModel } from '@renderer/hooks/useModel'
import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings' import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
import { fetchChatCompletion } from '@renderer/services/ApiService' import { fetchChatCompletion } from '@renderer/services/ApiService'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { getMessageModelId } from '@renderer/services/MessagesService'
import { estimateMessageUsage } from '@renderer/services/TokenService' import { estimateMessageUsage } from '@renderer/services/TokenService'
import { Message, Topic } from '@renderer/types' import { Message, Topic } from '@renderer/types'
import { classNames, runAsyncFunction } from '@renderer/utils' import { classNames, runAsyncFunction } from '@renderer/utils'
@ -52,7 +53,7 @@ const MessageItem: FC<Props> = ({
const [message, setMessage] = useState(_message) const [message, setMessage] = useState(_message)
const { t } = useTranslation() const { t } = useTranslation()
const { assistant, setModel } = useAssistant(message.assistantId) const { assistant, setModel } = useAssistant(message.assistantId)
const model = useModel(message.modelId) const model = useModel(getMessageModelId(message))
const { isBubbleStyle } = useMessageStyle() const { isBubbleStyle } = useMessageStyle()
const { showMessageDivider, messageFont, fontSize } = useSettings() const { showMessageDivider, messageFont, fontSize } = useSettings()
const messageContainerRef = useRef<HTMLDivElement>(null) const messageContainerRef = useRef<HTMLDivElement>(null)
@ -165,7 +166,7 @@ const MessageItem: FC<Props> = ({
})} })}
ref={messageContainerRef} ref={messageContainerRef}
style={{ ...style, alignItems: isBubbleStyle ? (isAssistantMessage ? 'start' : 'end') : undefined }}> style={{ ...style, alignItems: isBubbleStyle ? (isAssistantMessage ? 'start' : 'end') : undefined }}>
<MessageHeader message={message} assistant={assistant} model={model} key={message.modelId} /> <MessageHeader message={message} assistant={assistant} model={model} key={getMessageModelId(message)} />
<MessageContentContainer <MessageContentContainer
className="message-content-container" className="message-content-container"
style={{ fontFamily, fontSize, background: messageBackground }}> style={{ fontFamily, fontSize, background: messageBackground }}>

View File

@ -5,6 +5,7 @@ import { getModelLogo } from '@renderer/config/models'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import useAvatar from '@renderer/hooks/useAvatar' import useAvatar from '@renderer/hooks/useAvatar'
import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings' import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
import { getMessageModelId } from '@renderer/services/MessagesService'
import { Assistant, Message, Model } from '@renderer/types' import { Assistant, Message, Model } from '@renderer/types'
import { firstLetter, removeLeadingEmoji } from '@renderer/utils' import { firstLetter, removeLeadingEmoji } from '@renderer/utils'
import { Avatar } from 'antd' import { Avatar } from 'antd'
@ -31,7 +32,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { isBubbleStyle } = useMessageStyle() const { isBubbleStyle } = useMessageStyle()
const avatarSource = useMemo(() => getAvatarSource(isLocalAi, message.modelId), [message.modelId]) const avatarSource = useMemo(() => getAvatarSource(isLocalAi, getMessageModelId(message)), [message])
const getUserName = useCallback(() => { const getUserName = useCallback(() => {
if (isLocalAi && message.role !== 'user') return APP_NAME if (isLocalAi && message.role !== 'user') return APP_NAME

View File

@ -84,7 +84,7 @@ const MessageMenubar: FC<Props> = (props) => {
...nextMessage, ...nextMessage,
content: '', content: '',
status: 'sending', status: 'sending',
modelId: assistantModel?.id || model?.id, model: assistantModel || model,
translatedContent: undefined translatedContent: undefined
}) })
} }
@ -93,7 +93,7 @@ const MessageMenubar: FC<Props> = (props) => {
EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE, { ...message, id: uuid() }) EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE, { ...message, id: uuid() })
onDeleteMessage?.(message) onDeleteMessage?.(message)
} }
}, [assistantModel?.id, message, model?.id, onDeleteMessage, onGetMessages]) }, [assistantModel, message, model, onDeleteMessage, onGetMessages])
const onEdit = useCallback(async () => { const onEdit = useCallback(async () => {
let resendMessage = false let resendMessage = false
@ -169,7 +169,7 @@ const MessageMenubar: FC<Props> = (props) => {
[message, onEdit, onNewBranch, t] [message, onEdit, onNewBranch, t]
) )
const onDeleteAndRegenerate = async () => { const onRegenerate = async () => {
await modelGenerating() await modelGenerating()
const selectedModel = await SelectModelPopup.show({ model }) const selectedModel = await SelectModelPopup.show({ model })
if (!selectedModel) return if (!selectedModel) return
@ -180,7 +180,6 @@ const MessageMenubar: FC<Props> = (props) => {
reasoning_content: undefined, reasoning_content: undefined,
metrics: undefined, metrics: undefined,
status: 'sending', status: 'sending',
modelId: selectedModel.id,
model: selectedModel, model: selectedModel,
translatedContent: undefined, translatedContent: undefined,
metadata: undefined metadata: undefined
@ -214,7 +213,7 @@ const MessageMenubar: FC<Props> = (props) => {
</Tooltip> </Tooltip>
{isAssistantMessage && ( {isAssistantMessage && (
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}> <Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onDeleteAndRegenerate}> <ActionButton className="message-action-button" onClick={onRegenerate}>
<SyncOutlined /> <SyncOutlined />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>

View File

@ -164,8 +164,7 @@ const Messages: FC<Props> = ({ assistant, topic, setActiveTopic }) => {
}), }),
EventEmitter.on(EVENT_NAMES.REGENERATE_MESSAGE, async (model: Model) => { EventEmitter.on(EVENT_NAMES.REGENERATE_MESSAGE, async (model: Model) => {
const lastUserMessage = last(filterMessages(messages).filter((m) => m.role === 'user')) const lastUserMessage = last(filterMessages(messages).filter((m) => m.role === 'user'))
lastUserMessage && lastUserMessage && onSendMessage({ ...lastUserMessage, id: uuid(), model: model, mentions: [model] })
onSendMessage({ ...lastUserMessage, id: uuid(), modelId: model.id, model: model, mentions: [model] })
}), }),
EventEmitter.on(EVENT_NAMES.AI_AUTO_RENAME, autoRenameTopic), EventEmitter.on(EVENT_NAMES.AI_AUTO_RENAME, autoRenameTopic),
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, () => { EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, () => {

View File

@ -55,7 +55,7 @@ const TranslatePage: FC = () => {
content: text, content: text,
assistantId: assistant.id, assistantId: assistant.id,
topicId: uuid(), topicId: uuid(),
modelId: translateModel.id, model: translateModel,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
type: 'text', type: 'text',
status: 'sending' status: 'sending'

View File

@ -133,7 +133,7 @@ export async function addAssistantMessagesToTopic({ assistant, topic }: { assist
topicId: topic.id, topicId: topic.id,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
status: 'success', status: 'success',
modelId: assistant.defaultModel?.id || defaultModel.id, model: assistant.defaultModel || defaultModel,
type: 'text', type: 'text',
isPreset: true isPreset: true
} }

View File

@ -86,7 +86,7 @@ export function getUserMessage({
content: content || '', content: content || '',
assistantId: assistant.id, assistantId: assistant.id,
topicId: topic.id, topicId: topic.id,
modelId: model.id, model,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
type, type,
status: 'success' status: 'success'
@ -104,7 +104,6 @@ export function getAssistantMessage({ assistant, topic }: { assistant: Assistant
assistantId: assistant.id, assistantId: assistant.id,
topicId: topic.id, topicId: topic.id,
model, model,
modelId: model.id,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
type: 'text', type: 'text',
status: 'sending' status: 'sending'
@ -150,3 +149,7 @@ export function getGroupedMessages(messages: Message[]): { [key: string]: (Messa
}) })
return groups return groups
} }
export function getMessageModelId(message: Message) {
return message?.model?.id || message.modelId
}

View File

@ -5,6 +5,7 @@ import MessageContent from '@renderer/pages/home/Messages/MessageContent'
import MessageErrorBoundary from '@renderer/pages/home/Messages/MessageErrorBoundary' import MessageErrorBoundary from '@renderer/pages/home/Messages/MessageErrorBoundary'
import { fetchChatCompletion } from '@renderer/services/ApiService' import { fetchChatCompletion } from '@renderer/services/ApiService'
import { getDefaultAssistant, getDefaultModel } from '@renderer/services/AssistantService' import { getDefaultAssistant, getDefaultModel } from '@renderer/services/AssistantService'
import { getMessageModelId } from '@renderer/services/MessagesService'
import { Message } from '@renderer/types' import { Message } from '@renderer/types'
import { isMiniWindow } from '@renderer/utils' import { isMiniWindow } from '@renderer/utils'
import { Dispatch, FC, memo, SetStateAction, useEffect, useMemo, useRef, useState } from 'react' import { Dispatch, FC, memo, SetStateAction, useEffect, useMemo, useRef, useState } from 'react'
@ -24,7 +25,7 @@ const getMessageBackground = (isBubbleStyle: boolean, isAssistantMessage: boolea
const MessageItem: FC<Props> = ({ message: _message, index, total, route, onSetMessages, onGetMessages }) => { const MessageItem: FC<Props> = ({ message: _message, index, total, route, onSetMessages, onGetMessages }) => {
const [message, setMessage] = useState(_message) const [message, setMessage] = useState(_message)
const model = useModel(message.modelId) const model = useModel(getMessageModelId(message))
const isBubbleStyle = true const isBubbleStyle = true
const { messageFont, fontSize } = useSettings() const { messageFont, fontSize } = useSettings()
const messageContainerRef = useRef<HTMLDivElement>(null) const messageContainerRef = useRef<HTMLDivElement>(null)

View File

@ -45,7 +45,7 @@ const Translate: FC<Props> = ({ text }) => {
content: text, content: text,
assistantId: assistant.id, assistantId: assistant.id,
topicId: uuid(), topicId: uuid(),
modelId: translateModel.id, model: translateModel,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
type: 'text', type: 'text',
status: 'sending' status: 'sending'