From 73973ecb7f22bce2a8e5889f48c90118a8bf3d6d Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Tue, 3 Dec 2024 19:58:27 +0800 Subject: [PATCH] feat: change re-generage message logic --- .../src/assets/fonts/icon-fonts/iconfont.css | 20 +++---- .../assets/fonts/icon-fonts/iconfont.woff2 | Bin 3644 -> 3860 bytes .../src/components/Popups/TextEditPopup.tsx | 10 +++- src/renderer/src/i18n/locales/en-us.json | 3 +- src/renderer/src/i18n/locales/ru-ru.json | 3 +- src/renderer/src/i18n/locales/zh-cn.json | 3 +- src/renderer/src/i18n/locales/zh-tw.json | 3 +- src/renderer/src/pages/agents/AgentsPage.tsx | 4 +- .../src/pages/home/Messages/Message.tsx | 55 ++++++++++-------- .../src/pages/home/Messages/MessageHeader.tsx | 21 ++++--- .../pages/home/Messages/MessageMenubar.tsx | 44 ++++++++++++-- src/renderer/src/store/settings.ts | 2 +- 12 files changed, 110 insertions(+), 58 deletions(-) diff --git a/src/renderer/src/assets/fonts/icon-fonts/iconfont.css b/src/renderer/src/assets/fonts/icon-fonts/iconfont.css index eddc69d7..0f00ab67 100644 --- a/src/renderer/src/assets/fonts/icon-fonts/iconfont.css +++ b/src/renderer/src/assets/fonts/icon-fonts/iconfont.css @@ -1,6 +1,6 @@ @font-face { - font-family: 'iconfont'; /* Project id 4563475 */ - src: url('iconfont.woff2?t=1725606177995') format('woff2'); + font-family: 'iconfont'; /* Project id 4753420 */ + src: url('iconfont.woff2?t=1733224456443') format('woff2'); } .iconfont { @@ -11,6 +11,14 @@ -moz-osx-font-smoothing: grayscale; } +.icon-at1:before { + content: '\e7df'; +} + +.icon-at:before { + content: '\e630'; +} + .icon-a-darkmode:before { content: '\e6cd'; } @@ -27,10 +35,6 @@ content: '\e942'; } -.icon-grid-row-2copy:before { - content: '\e681'; -} - .icon-inbox:before { content: '\e869'; } @@ -71,10 +75,6 @@ content: '\e944'; } -.icon-a-addchat:before { - content: '\e658'; -} - .icon-appstore:before { content: '\e792'; } diff --git a/src/renderer/src/assets/fonts/icon-fonts/iconfont.woff2 b/src/renderer/src/assets/fonts/icon-fonts/iconfont.woff2 index 067b1a9d9613adb1bd7fc55591dba9253c80587d..9a6c9a7bac7db7b534f6a8df786270985e2ca379 100644 GIT binary patch literal 3860 zcmV+v59{!EPew8T0RR9101p%Z3jhEB02`P901n3h0RR9100000000000000000000 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 W#%*109rFBjr&tySs1}eYvYG)qjb}*! literal 3644 zcmV-C4#V+xPew8T0RR9101i9=3jhEB02;^u01fT{0RR9100000000000000000000 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 = ({ text, textareaProps, modalProps, reso setTimeout(resizeTextArea, 0) }, []) + TextEditPopup.hide = onCancel + return ( = ({ text, textareaProps, modalProps, reso ) } +const TopViewKey = 'TextEditPopup' + export default class TextEditPopup { static topviewId = 0 static hide() { - TopView.hide('TextEditPopup') + TopView.hide(TopViewKey) } static show(props: ShowParams) { return new Promise((resolve) => { @@ -87,10 +91,10 @@ export default class TextEditPopup { {...props} resolve={(v) => { resolve(v) - this.hide() + TopView.hide(TopViewKey) }} />, - 'TextEditPopup' + TopViewKey ) }) } diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 4307c3d8..2a07206a 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -240,7 +240,8 @@ "topic.added": "New topic added", "upgrade.success.button": "Restart", "upgrade.success.content": "Please restart the application to complete the upgrade", - "upgrade.success.title": "Upgrade successfully" + "upgrade.success.title": "Upgrade successfully", + "regenerate.confirm": "Regenerating will replace current message" }, "minapp": { "title": "MinApp" diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 1806d0cc..3e7015ac 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -240,7 +240,8 @@ "topic.added": "Новый топик добавлен", "upgrade.success.button": "Перезапустить", "upgrade.success.content": "Пожалуйста, перезапустите приложение для завершения обновления", - "upgrade.success.title": "Обновление успешно" + "upgrade.success.title": "Обновление успешно", + "regenerate.confirm": "Перегенерация заменит текущее сообщение" }, "minapp": { "title": "Встроенные приложения" diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index ddf6a3e3..9a688b6f 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -240,7 +240,8 @@ "topic.added": "话题添加成功", "upgrade.success.button": "重启", "upgrade.success.content": "重启用以完成升级", - "upgrade.success.title": "升级成功" + "upgrade.success.title": "升级成功", + "regenerate.confirm": "重新生成会覆盖当前消息" }, "minapp": { "title": "小程序" diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index f4b8cc81..c6d49172 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -240,7 +240,8 @@ "topic.added": "新話題已添加", "upgrade.success.button": "重新啟動", "upgrade.success.content": "請重新啟動應用以完成升級", - "upgrade.success.title": "升級成功" + "upgrade.success.title": "升級成功", + "regenerate.confirm": "重新生成會覆蓋當前訊息" }, "minapp": { "title": "小程序" diff --git a/src/renderer/src/pages/agents/AgentsPage.tsx b/src/renderer/src/pages/agents/AgentsPage.tsx index f1712e18..77669de4 100644 --- a/src/renderer/src/pages/agents/AgentsPage.tsx +++ b/src/renderer/src/pages/agents/AgentsPage.tsx @@ -272,8 +272,8 @@ const Tabs = styled(TabsAntd)<{ $language: string }>` padding-right: 0 !important; } .ant-tabs-nav { - min-width: ${({ $language }) => ($language.startsWith('zh') ? '100px' : '140px')}; - max-width: ${({ $language }) => ($language.startsWith('zh') ? '100px' : '140px')}; + min-width: ${({ $language }) => ($language.startsWith('zh') ? '110px' : '140px')}; + max-width: ${({ $language }) => ($language.startsWith('zh') ? '110px' : '140px')}; } .ant-tabs-nav-list { padding: 10px 8px; diff --git a/src/renderer/src/pages/home/Messages/Message.tsx b/src/renderer/src/pages/home/Messages/Message.tsx index dbc4dc98..4fafb142 100644 --- a/src/renderer/src/pages/home/Messages/Message.tsx +++ b/src/renderer/src/pages/home/Messages/Message.tsx @@ -30,6 +30,9 @@ interface Props { onDeleteMessage?: (message: Message) => void } +const getMessageBackground = (isBubbleStyle: boolean, isAssistantMessage: boolean) => + isBubbleStyle ? (isAssistantMessage ? 'var(--chat-background-assistant)' : 'var(--chat-background-user)') : undefined + const MessageItem: FC = ({ message: _message, topic, @@ -57,37 +60,33 @@ const MessageItem: FC = ({ }, [messageFont]) const messageBorder = showMessageDivider ? undefined : 'none' - const messageBackground = isBubbleStyle - ? isAssistantMessage - ? 'var(--chat-background-assistant)' - : 'var(--chat-background-user)' - : undefined + const messageBackground = getMessageBackground(isBubbleStyle, isAssistantMessage) const onEditMessage = useCallback( (msg: Message) => { setMessage(msg) - const messages = onGetMessages?.().map((m) => (m.id === message.id ? msg : m)) + const messages = onGetMessages?.()?.map((m) => (m.id === message.id ? msg : m)) messages && onSetMessages?.(messages) topic && db.topics.update(topic.id, { messages }) }, - [message, onGetMessages, onSetMessages, topic] + [message.id, onGetMessages, onSetMessages, topic] ) + const messageHighlightHandler = (highlight: boolean = true) => { + if (messageContainerRef.current) { + messageContainerRef.current.scrollIntoView({ behavior: 'smooth' }) + if (highlight) { + setTimeout(() => { + const classList = messageContainerRef.current?.classList + classList?.add('message-highlight') + setTimeout(() => classList?.remove('message-highlight'), 2500) + }, 500) + } + } + } + useEffect(() => { - const unsubscribes = [ - EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, (highlight: boolean = true) => { - if (messageContainerRef.current) { - messageContainerRef.current.scrollIntoView({ behavior: 'smooth' }) - if (highlight) { - setTimeout(() => { - const classList = messageContainerRef.current?.classList - classList?.add('message-highlight') - setTimeout(() => classList?.remove('message-highlight'), 2500) - }, 500) - } - } - }) - ] + const unsubscribes = [EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, messageHighlightHandler)] return () => unsubscribes.forEach((unsub) => unsub()) }, [message]) @@ -105,11 +104,16 @@ const MessageItem: FC = ({ useEffect(() => { if (topic && onGetMessages && onSetMessages) { - if (message.status === 'sending' && index === 0) { + if (message.status === 'sending') { const messages = onGetMessages() fetchChatCompletion({ message, - messages: messages.filter((m) => !m.status.includes('ing')), + messages: messages + .filter((m) => !m.status.includes('ing')) + .slice( + 0, + messages.findIndex((m) => m.id === message.id) + ), assistant, topic, onResponse: (msg) => { @@ -124,7 +128,7 @@ const MessageItem: FC = ({ } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [message.status]) if (hidePresetMessages && message.isPreset) { return null @@ -148,7 +152,7 @@ const MessageItem: FC = ({ })} ref={messageContainerRef} style={isBubbleStyle ? { alignItems: isAssistantMessage ? 'start' : 'end' } : undefined}> - + @@ -164,6 +168,7 @@ const MessageItem: FC = ({ = ({ assistant, model, message }) => { +const getAvatarSource = (isLocalAi: boolean, modelId: string | undefined) => { + if (isLocalAi) return AppLogo + return modelId ? getModelLogo(modelId) : undefined +} + +const MessageHeader: FC = memo(({ assistant, model, message }) => { const avatar = useAvatar() const { theme } = useTheme() const { userName } = useSettings() const { t } = useTranslation() const { isBubbleStyle } = useMessageStyle() - const avatarSource = useMemo(() => { - if (isLocalAi) return AppLogo - return message.modelId ? getModelLogo(message.modelId) : undefined - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [message.modelId, theme]) + const avatarSource = useMemo(() => getAvatarSource(isLocalAi, message.modelId), [message.modelId]) const getUserName = useCallback(() => { if (isLocalAi && message.role !== 'user') return APP_NAME @@ -43,7 +44,7 @@ const MessageHeader: FC = ({ assistant, model, message }) => { const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name]) const username = useMemo(() => removeLeadingEmoji(getUserName()), [getUserName]) - const showMiniApp = () => model?.provider && startMinAppById(model?.provider) + const showMiniApp = useCallback(() => model?.provider && startMinAppById(model.provider), [model?.provider]) const avatarStyle: CSSProperties | undefined = isBubbleStyle ? { @@ -83,7 +84,9 @@ const MessageHeader: FC = ({ assistant, model, message }) => { ) -} +}) + +MessageHeader.displayName = 'MessageHeader' const Container = styled.div` display: flex; diff --git a/src/renderer/src/pages/home/Messages/MessageMenubar.tsx b/src/renderer/src/pages/home/Messages/MessageMenubar.tsx index 755e1659..480bfeb2 100644 --- a/src/renderer/src/pages/home/Messages/MessageMenubar.tsx +++ b/src/renderer/src/pages/home/Messages/MessageMenubar.tsx @@ -23,6 +23,7 @@ import styled from 'styled-components' interface Props { message: Message + assistantModel?: Model model?: Model index?: number isLastMessage: boolean @@ -33,7 +34,17 @@ interface Props { } const MessageMenubar: FC = (props) => { - const { message, index, model, isLastMessage, isAssistantMessage, setModel, onEditMessage, onDeleteMessage } = props + const { + message, + index, + model, + isLastMessage, + isAssistantMessage, + assistantModel, + setModel, + onEditMessage, + onDeleteMessage + } = props const { t } = useTranslation() const [copied, setCopied] = useState(false) const [isTranslating, setIsTranslating] = useState(false) @@ -157,11 +168,21 @@ const MessageMenubar: FC = (props) => { [handleTranslate, isTranslating, message, onEdit, onEditMessage, t] ) - const onSelectModel = async () => { + const onAtModelRegenerate = async () => { const selectedModel = await SelectModelPopup.show({ model }) selectedModel && onRegenerate(selectedModel) } + const onDeleteAndRegenerate = () => { + onEditMessage?.({ + ...message, + content: '', + status: 'sending', + modelId: assistantModel?.id || model?.id, + translatedContent: undefined + }) + } + return ( {message.role === 'user' && ( @@ -177,10 +198,22 @@ const MessageMenubar: FC = (props) => { {copied && } + {isAssistantMessage && ( + } + onConfirm={onDeleteAndRegenerate}> + + + + + )} {canRegenerate && ( - - + + )} @@ -247,6 +280,9 @@ const ActionButton = styled.div` &:hover { color: var(--color-text-1); } + .icon-at1 { + font-size: 16px; + } ` export default MessageMenubar diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index 6e6db498..fa324c7b 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -55,7 +55,7 @@ const initialState: SettingsState = { theme: ThemeMode.auto, windowStyle: 'transparent', fontSize: 14, - topicPosition: 'right', + topicPosition: 'left', showTopicTime: false, pasteLongTextAsFile: false, clickAssistantToShowTopic: false,