fix: keep bubble metrics visible

This commit is contained in:
scientia 2025-11-01 13:14:52 +08:00
parent f1a2e15dac
commit 36eaf5229d
3 changed files with 48 additions and 49 deletions

View File

@ -10,6 +10,7 @@ import type { ToolQuickPanelApi } from '@renderer/pages/home/Inputbar/types'
import FileManager from '@renderer/services/FileManager'
import PasteService from '@renderer/services/PasteService'
import { useAppSelector } from '@renderer/store'
import { messageBlocksSelectors } from '@renderer/store/messageBlock'
import { selectMessagesForTopic } from '@renderer/store/newMessage'
import type { FileMetadata } from '@renderer/types'
import { FileTypes } from '@renderer/types'
@ -43,7 +44,15 @@ interface Props {
const logger = loggerService.withContext('MessageBlockEditor')
const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onCancel }) => {
const allBlocks = findAllBlocks(message)
const blockEntities = useAppSelector(messageBlocksSelectors.selectEntities)
const allBlocks = useMemo(() => {
if (!message?.blocks || message.blocks.length === 0) {
return []
}
return message.blocks
.map((blockId) => blockEntities[blockId])
.filter((block): block is MessageBlock => Boolean(block))
}, [blockEntities, message?.blocks])
const [editedBlocks, setEditedBlocks] = useState<MessageBlock[]>(allBlocks)
const [files, setFiles] = useState<FileMetadata[]>([])
const [isProcessing, setIsProcessing] = useState(false)
@ -120,6 +129,12 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
return () => clearTimeout(timer)
}, [])
useEffect(() => {
if (editedBlocks.length === 0 && allBlocks.length > 0) {
setEditedBlocks(allBlocks)
}
}, [allBlocks, editedBlocks.length])
// 仅在打开时执行一次
useEffect(() => {
if (textareaRef.current) {
@ -202,7 +217,16 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
// 处理编辑区块并上传文件
const processEditedBlocks = async () => {
const updatedBlocks = [...editedBlocks]
let updatedBlocks = [...editedBlocks]
if (!updatedBlocks.some((block) => block.type === MessageBlockType.MAIN_TEXT)) {
const originalMainTextBlocks = findAllBlocks(message).filter(
(block): block is MessageBlock => block.type === MessageBlockType.MAIN_TEXT
)
if (originalMainTextBlocks.length > 0) {
updatedBlocks = [...originalMainTextBlocks, ...updatedBlocks]
}
}
if (files && files.length) {
const uploadedFiles = await FileManager.uploadFiles(files)
uploadedFiles.forEach((file) => {

View File

@ -524,7 +524,7 @@ const MessageMenubar: FC<Props> = (props) => {
const softHoverBg = isBubbleStyle && !isLastMessage
const isUserBubbleStyleMessage = isBubbleStyle && isUserMessage
const bubbleAlignment: 'flex-start' | 'flex-end' = isAssistantMessage ? 'flex-start' : 'flex-end'
const messageTokensAlignment: 'left' | 'right' = isBubbleStyle ? 'right' : 'left'
const messageTokensAlignment: 'left' | 'right' = isBubbleStyle || isAssistantMessage ? 'right' : 'left'
const tokensElement = <MessageTokens message={message} align={messageTokensAlignment} />
@ -563,7 +563,11 @@ const MessageMenubar: FC<Props> = (props) => {
if (isBubbleStyle) {
return (
<BubbleMenubarWrapper $align={bubbleAlignment}>
<div
className={classNames(
'flex w-full flex-row items-center gap-2',
bubbleAlignment === 'flex-start' ? 'justify-start' : 'justify-end'
)}>
<MenusBar
className={classNames({
menubar: true,
@ -583,8 +587,8 @@ const MessageMenubar: FC<Props> = (props) => {
return <Fragment key={buttonId}>{element}</Fragment>
})}
</MenusBar>
<BubbleTokens>{tokensElement}</BubbleTokens>
</BubbleMenubarWrapper>
<div className="ml-auto flex min-w-0 flex-none justify-end">{tokensElement}</div>
</div>
)
}
@ -610,23 +614,6 @@ const MessageMenubar: FC<Props> = (props) => {
)
}
const BubbleMenubarWrapper = styled.div<{ $align: 'flex-start' | 'flex-end' }>`
display: flex;
flex-direction: row;
align-items: center;
justify-content: ${(props) => props.$align};
gap: 8px;
width: 100%;
`
const BubbleTokens = styled.div`
margin-left: auto;
flex: 0 0 auto;
min-width: 0;
display: flex;
justify-content: flex-end;
`
const MenusBar = styled.div`
display: flex;
flex-direction: row;

View File

@ -1,9 +1,9 @@
// import { useRuntime } from '@renderer/hooks/useRuntime'
import { classNames } from '@renderer/utils'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import type { Message } from '@renderer/types/newMessage'
import { Popover } from 'antd'
import { t } from 'i18next'
import styled from 'styled-components'
interface MessageTokensProps {
message: Message
@ -54,11 +54,16 @@ const MessageTokens: React.FC<MessageTokensProps> = ({ message, align = 'left' }
return <div />
}
const metadataClassName = classNames(
'message-tokens flex min-w-0 cursor-pointer select-text text-[10px] text-[var(--color-text-3)]',
align === 'right' ? 'ml-auto justify-end' : 'mr-auto justify-start'
)
if (message.role === 'user') {
return (
<MessageMetadata className="message-tokens" onClick={locateMessage} $align={align}>
<div className={metadataClassName} onClick={locateMessage}>
{`Tokens: ${message?.usage?.total_tokens}`}
</MessageMetadata>
</div>
)
}
@ -78,15 +83,15 @@ const MessageTokens: React.FC<MessageTokensProps> = ({ message, align = 'left' }
const tokensInfo = (
<span className="tokens">
Tokens:
<span>{message?.usage?.total_tokens}</span>
<span>{message?.usage?.prompt_tokens}</span>
<span>{message?.usage?.completion_tokens}</span>
<span>{getPriceString()}</span>
<span className="px-0.5">{message?.usage?.total_tokens}</span>
<span className="px-0.5">{message?.usage?.prompt_tokens}</span>
<span className="px-0.5">{message?.usage?.completion_tokens}</span>
<span className="px-0.5">{getPriceString()}</span>
</span>
)
return (
<MessageMetadata className="message-tokens" onClick={locateMessage} $align={align}>
<div className={metadataClassName} onClick={locateMessage}>
{hasMetrics ? (
<Popover content={metrixs} placement="top" trigger="hover" styles={{ root: { fontSize: 11 } }}>
{tokensInfo}
@ -94,28 +99,11 @@ const MessageTokens: React.FC<MessageTokensProps> = ({ message, align = 'left' }
) : (
tokensInfo
)}
</MessageMetadata>
</div>
)
}
return null
}
const MessageMetadata = styled.div<{ $align: 'left' | 'right' }>`
font-size: 10px;
color: var(--color-text-3);
user-select: text;
cursor: pointer;
display: flex;
flex: 0 1 auto;
min-width: 0;
justify-content: ${(props) => (props.$align === 'right' ? 'flex-end' : 'flex-start')};
margin-left: ${(props) => (props.$align === 'right' ? 'auto' : '0')};
margin-right: ${(props) => (props.$align === 'left' ? 'auto' : '0')};
.tokens span {
padding: 0 2px;
}
`
export default MessageTokens