feat: 增加保持并发送的功能 #527
This commit is contained in:
parent
96124cf58e
commit
47c455b125
@ -4,6 +4,7 @@ import { TextAreaProps } from 'antd/lib/input'
|
|||||||
import { TextAreaRef } from 'antd/lib/input/TextArea'
|
import { TextAreaRef } from 'antd/lib/input/TextArea'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { TopView } from '../TopView'
|
import { TopView } from '../TopView'
|
||||||
|
|
||||||
@ -11,13 +12,14 @@ interface ShowParams {
|
|||||||
text: string
|
text: string
|
||||||
textareaProps?: TextAreaProps
|
textareaProps?: TextAreaProps
|
||||||
modalProps?: ModalProps
|
modalProps?: ModalProps
|
||||||
|
children?: (props: { onOk?: () => void; onCancel?: () => void }) => React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends ShowParams {
|
interface Props extends ShowParams {
|
||||||
resolve: (data: any) => void
|
resolve: (data: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, resolve }) => {
|
const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, resolve, children }) => {
|
||||||
const [open, setOpen] = useState(true)
|
const [open, setOpen] = useState(true)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [textValue, setTextValue] = useState(text)
|
const [textValue, setTextValue] = useState(text)
|
||||||
@ -73,12 +75,17 @@ const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, reso
|
|||||||
onInput={resizeTextArea}
|
onInput={resizeTextArea}
|
||||||
onChange={(e) => setTextValue(e.target.value)}
|
onChange={(e) => setTextValue(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
<ChildrenContainer>{children && children({ onOk, onCancel })}</ChildrenContainer>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const TopViewKey = 'TextEditPopup'
|
const TopViewKey = 'TextEditPopup'
|
||||||
|
|
||||||
|
const ChildrenContainer = styled.div`
|
||||||
|
position: relative;
|
||||||
|
`
|
||||||
|
|
||||||
export default class TextEditPopup {
|
export default class TextEditPopup {
|
||||||
static topviewId = 0
|
static topviewId = 0
|
||||||
static hide() {
|
static hide() {
|
||||||
|
|||||||
@ -112,7 +112,8 @@
|
|||||||
"topics.list": "Topic List",
|
"topics.list": "Topic List",
|
||||||
"topics.move_to": "Move to",
|
"topics.move_to": "Move to",
|
||||||
"topics.title": "Topics",
|
"topics.title": "Topics",
|
||||||
"translate": "Translate"
|
"translate": "Translate",
|
||||||
|
"resend": "Resend"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"and": "and",
|
"and": "and",
|
||||||
|
|||||||
@ -112,7 +112,8 @@
|
|||||||
"topics.list": "トピックリスト",
|
"topics.list": "トピックリスト",
|
||||||
"topics.move_to": "移動先",
|
"topics.move_to": "移動先",
|
||||||
"topics.title": "トピック",
|
"topics.title": "トピック",
|
||||||
"translate": "翻訳"
|
"translate": "翻訳",
|
||||||
|
"resend": "再送信"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"and": "と",
|
"and": "と",
|
||||||
|
|||||||
@ -112,7 +112,8 @@
|
|||||||
"topics.list": "Список топиков",
|
"topics.list": "Список топиков",
|
||||||
"topics.move_to": "Переместить в",
|
"topics.move_to": "Переместить в",
|
||||||
"topics.title": "Топики",
|
"topics.title": "Топики",
|
||||||
"translate": "Перевести"
|
"translate": "Перевести",
|
||||||
|
"resend": "Переотправить"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"and": "и",
|
"and": "и",
|
||||||
|
|||||||
@ -112,7 +112,8 @@
|
|||||||
"topics.list": "话题列表",
|
"topics.list": "话题列表",
|
||||||
"topics.move_to": "移动到",
|
"topics.move_to": "移动到",
|
||||||
"topics.title": "话题",
|
"topics.title": "话题",
|
||||||
"translate": "翻译"
|
"translate": "翻译",
|
||||||
|
"resend": "重新发送"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"and": "和",
|
"and": "和",
|
||||||
|
|||||||
@ -112,7 +112,8 @@
|
|||||||
"topics.list": "話題列表",
|
"topics.list": "話題列表",
|
||||||
"topics.move_to": "移動到",
|
"topics.move_to": "移動到",
|
||||||
"topics.title": "話題",
|
"topics.title": "話題",
|
||||||
"translate": "翻譯"
|
"translate": "翻譯",
|
||||||
|
"resend": "重新發送"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"and": "與",
|
"and": "與",
|
||||||
|
|||||||
@ -86,9 +86,12 @@ const MessageItem: FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribes = [EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, messageHighlightHandler)]
|
const unsubscribes = [
|
||||||
|
EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, messageHighlightHandler),
|
||||||
|
EventEmitter.on(EVENT_NAMES.RESEND_MESSAGE + ':' + message.id, onEditMessage)
|
||||||
|
]
|
||||||
return () => unsubscribes.forEach((unsub) => unsub())
|
return () => unsubscribes.forEach((unsub) => unsub())
|
||||||
}, [message])
|
}, [message, onEditMessage])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (message.role === 'user' && !message.usage) {
|
if (message.role === 'user' && !message.usage) {
|
||||||
@ -178,6 +181,7 @@ const MessageItem: FC<Props> = ({
|
|||||||
setModel={setModel}
|
setModel={setModel}
|
||||||
onEditMessage={onEditMessage}
|
onEditMessage={onEditMessage}
|
||||||
onDeleteMessage={onDeleteMessage}
|
onDeleteMessage={onDeleteMessage}
|
||||||
|
onGetMessages={onGetMessages}
|
||||||
/>
|
/>
|
||||||
</MessageFooter>
|
</MessageFooter>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
|||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import { Message, Model } from '@renderer/types'
|
import { Message, Model } from '@renderer/types'
|
||||||
import { removeTrailingDoubleSpaces } from '@renderer/utils'
|
import { removeTrailingDoubleSpaces } from '@renderer/utils'
|
||||||
import { Dropdown, Popconfirm, Tooltip } from 'antd'
|
import { Button, Dropdown, Popconfirm, Tooltip } from 'antd'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { FC, useCallback, useMemo, useState } from 'react'
|
import { FC, useCallback, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -31,6 +31,7 @@ interface Props {
|
|||||||
setModel: (model: Model) => void
|
setModel: (model: Model) => void
|
||||||
onEditMessage?: (message: Message) => void
|
onEditMessage?: (message: Message) => void
|
||||||
onDeleteMessage?: (message: Message) => void
|
onDeleteMessage?: (message: Message) => void
|
||||||
|
onGetMessages?: () => Message[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const MessageMenubar: FC<Props> = (props) => {
|
const MessageMenubar: FC<Props> = (props) => {
|
||||||
@ -43,7 +44,8 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
assistantModel,
|
assistantModel,
|
||||||
setModel,
|
setModel,
|
||||||
onEditMessage,
|
onEditMessage,
|
||||||
onDeleteMessage
|
onDeleteMessage,
|
||||||
|
onGetMessages
|
||||||
} = props
|
} = props
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [copied, setCopied] = useState(false)
|
const [copied, setCopied] = useState(false)
|
||||||
@ -75,10 +77,43 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
})
|
})
|
||||||
}, [index, t])
|
}, [index, t])
|
||||||
|
|
||||||
|
const onResend = useCallback(() => {
|
||||||
|
const _messages = onGetMessages?.() || []
|
||||||
|
const index = _messages.findIndex((m) => m.id === message.id)
|
||||||
|
const nextIndex = index + 1
|
||||||
|
const nextMessage = _messages[nextIndex]
|
||||||
|
|
||||||
|
if (nextMessage && nextMessage.role === 'assistant') {
|
||||||
|
EventEmitter.emit(EVENT_NAMES.RESEND_MESSAGE + ':' + nextMessage.id, {
|
||||||
|
...nextMessage,
|
||||||
|
content: '',
|
||||||
|
status: 'sending',
|
||||||
|
modelId: assistantModel?.id || model?.id,
|
||||||
|
translatedContent: undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [assistantModel?.id, message.id, model?.id, onGetMessages])
|
||||||
|
|
||||||
const onEdit = useCallback(async () => {
|
const onEdit = useCallback(async () => {
|
||||||
const editedText = await TextEditPopup.show({ text: message.content })
|
let resendMessage = false
|
||||||
|
|
||||||
|
const editedText = await TextEditPopup.show({
|
||||||
|
text: message.content,
|
||||||
|
children: (props) => (
|
||||||
|
<ReSendButton
|
||||||
|
icon={<i className="iconfont icon-ic_send" style={{ color: 'var(--color-primary)' }} />}
|
||||||
|
onClick={() => {
|
||||||
|
props.onOk?.()
|
||||||
|
resendMessage = true
|
||||||
|
}}>
|
||||||
|
{t('chat.resend')}
|
||||||
|
</ReSendButton>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
editedText && onEditMessage?.({ ...message, content: editedText })
|
editedText && onEditMessage?.({ ...message, content: editedText })
|
||||||
}, [message, onEditMessage])
|
resendMessage && onResend()
|
||||||
|
}, [message, onEditMessage, onResend, t])
|
||||||
|
|
||||||
const handleTranslate = useCallback(
|
const handleTranslate = useCallback(
|
||||||
async (language: string) => {
|
async (language: string) => {
|
||||||
@ -287,4 +322,10 @@ const ActionButton = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const ReSendButton = styled(Button)`
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
`
|
||||||
|
|
||||||
export default MessageMenubar
|
export default MessageMenubar
|
||||||
|
|||||||
@ -20,5 +20,6 @@ export const EVENT_NAMES = {
|
|||||||
NEW_BRANCH: 'NEW_BRANCH',
|
NEW_BRANCH: 'NEW_BRANCH',
|
||||||
EXPORT_TOPIC_IMAGE: 'EXPORT_TOPIC_IMAGE',
|
EXPORT_TOPIC_IMAGE: 'EXPORT_TOPIC_IMAGE',
|
||||||
LOCATE_MESSAGE: 'LOCATE_MESSAGE',
|
LOCATE_MESSAGE: 'LOCATE_MESSAGE',
|
||||||
ADD_NEW_TOPIC: 'ADD_NEW_TOPIC'
|
ADD_NEW_TOPIC: 'ADD_NEW_TOPIC',
|
||||||
|
RESEND_MESSAGE: 'RESEND_MESSAGE'
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user