feat: Add copy functionality to message reasoning content
This commit is contained in:
parent
ae71a7be9e
commit
bf51a0b5c6
@ -1,6 +1,7 @@
|
|||||||
|
import { CheckOutlined } from '@ant-design/icons'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { Message } from '@renderer/types'
|
import { Message } from '@renderer/types'
|
||||||
import { Collapse } from 'antd'
|
import { Collapse, message as antdMessage, Tooltip } from 'antd'
|
||||||
import { FC, useEffect, useMemo, useState } from 'react'
|
import { FC, useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import BarLoader from 'react-spinners/BarLoader'
|
import BarLoader from 'react-spinners/BarLoader'
|
||||||
@ -14,6 +15,7 @@ interface Props {
|
|||||||
|
|
||||||
const MessageThought: FC<Props> = ({ message }) => {
|
const MessageThought: FC<Props> = ({ message }) => {
|
||||||
const [activeKey, setActiveKey] = useState<'thought' | ''>('thought')
|
const [activeKey, setActiveKey] = useState<'thought' | ''>('thought')
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
const isThinking = !message.content
|
const isThinking = !message.content
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { messageFont, fontSize } = useSettings()
|
const { messageFont, fontSize } = useSettings()
|
||||||
@ -31,6 +33,15 @@ const MessageThought: FC<Props> = ({ message }) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyThought = () => {
|
||||||
|
if (message.reasoning_content) {
|
||||||
|
navigator.clipboard.writeText(message.reasoning_content)
|
||||||
|
antdMessage.success({ content: t('message.copied'), key: 'copy-message' })
|
||||||
|
setCopied(true)
|
||||||
|
setTimeout(() => setCopied(false), 2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const thinkingTime = message.metrics?.time_thinking_millsec || 0
|
const thinkingTime = message.metrics?.time_thinking_millsec || 0
|
||||||
const thinkingTimeSeconds = (thinkingTime / 1000).toFixed(1)
|
const thinkingTimeSeconds = (thinkingTime / 1000).toFixed(1)
|
||||||
const isPaused = message.status === 'paused'
|
const isPaused = message.status === 'paused'
|
||||||
@ -50,6 +61,20 @@ const MessageThought: FC<Props> = ({ message }) => {
|
|||||||
{isThinking ? t('chat.thinking') : t('chat.deeply_thought', { secounds: thinkingTimeSeconds })}
|
{isThinking ? t('chat.thinking') : t('chat.deeply_thought', { secounds: thinkingTimeSeconds })}
|
||||||
</TinkingText>
|
</TinkingText>
|
||||||
{isThinking && !isPaused && <BarLoader color="#9254de" />}
|
{isThinking && !isPaused && <BarLoader color="#9254de" />}
|
||||||
|
{(!isThinking || isPaused) && (
|
||||||
|
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
|
||||||
|
<ActionButton
|
||||||
|
className="message-action-button"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
copyThought()
|
||||||
|
}}
|
||||||
|
aria-label={t('common.copy')}>
|
||||||
|
{!copied && <i className="iconfont icon-copy"></i>}
|
||||||
|
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
|
||||||
|
</ActionButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</MessageTitleLabel>
|
</MessageTitleLabel>
|
||||||
),
|
),
|
||||||
children: (
|
children: (
|
||||||
@ -79,4 +104,32 @@ const TinkingText = styled.span`
|
|||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const ActionButton = styled.button`
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: auto;
|
||||||
|
opacity: 0.6;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--color-primary);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default MessageThought
|
export default MessageThought
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user