chore(version): 0.4.6

This commit is contained in:
kangfenmao 2024-08-01 15:36:07 +08:00
parent 23687f119d
commit 681c93f5eb
4 changed files with 96 additions and 82 deletions

View File

@ -60,7 +60,7 @@ jobs:
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
draft: false draft: true
files: | files: |
dist/*.exe dist/*.exe
dist/*.zip dist/*.zip

View File

@ -1,6 +1,6 @@
{ {
"name": "cherry-studio", "name": "cherry-studio",
"version": "0.4.5", "version": "0.4.6",
"description": "A powerful AI assistant for producer.", "description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "kangfenmao@qq.com", "author": "kangfenmao@qq.com",

View File

@ -17,8 +17,8 @@ import { Message } from '@renderer/types'
import { firstLetter, removeLeadingEmoji } from '@renderer/utils' import { firstLetter, removeLeadingEmoji } from '@renderer/utils'
import { Avatar, Dropdown, Tooltip } from 'antd' import { Avatar, Dropdown, Tooltip } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { isEmpty, upperFirst } from 'lodash' import { upperFirst } from 'lodash'
import { FC, useCallback, useState } from 'react' import { FC, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import Markdown from './markdown/Markdown' import Markdown from './markdown/Markdown'
@ -43,14 +43,14 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
const isUserMessage = message.role === 'user' const isUserMessage = message.role === 'user'
const canRegenerate = isLastMessage && message.role === 'assistant' const canRegenerate = isLastMessage && message.role === 'assistant'
const onCopy = () => { const onCopy = useCallback(() => {
navigator.clipboard.writeText(message.content) navigator.clipboard.writeText(message.content)
window.message.success({ content: t('message.copied'), key: 'copy-message' }) window.message.success({ content: t('message.copied'), key: 'copy-message' })
setCopied(true) setCopied(true)
setTimeout(() => setCopied(false), 2000) setTimeout(() => setCopied(false), 2000)
} }, [message.content, t])
const onDelete = async () => { const onDelete = useCallback(async () => {
const confirmed = await window.modal.confirm({ const confirmed = await window.modal.confirm({
icon: null, icon: null,
title: t('message.message.delete.title'), title: t('message.message.delete.title'),
@ -59,23 +59,14 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
okType: 'danger' okType: 'danger'
}) })
confirmed && onDeleteMessage?.(message) confirmed && onDeleteMessage?.(message)
} }, [message, onDeleteMessage, t])
const onEdit = () => { const onEdit = useCallback(() => EventEmitter.emit(EVENT_NAMES.EDIT_MESSAGE, message), [message])
EventEmitter.emit(EVENT_NAMES.EDIT_MESSAGE, message)
}
const onRegenerate = () => { const onRegenerate = useCallback(() => {
onDeleteMessage?.(message) onDeleteMessage?.(message)
setTimeout(() => EventEmitter.emit(EVENT_NAMES.REGENERATE_MESSAGE), 100) setTimeout(() => EventEmitter.emit(EVENT_NAMES.REGENERATE_MESSAGE), 100)
} }, [message, onDeleteMessage])
const getMessageContent = (message: Message) => {
if (isEmpty(message.content) && message.status === 'paused') {
return t('message.chat.completion.paused')
}
return message.content
}
const getUserName = useCallback(() => { const getUserName = useCallback(() => {
if (message.id === 'assistant') { if (message.id === 'assistant') {
@ -111,73 +102,95 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
const messageBorder = showMessageDivider ? undefined : 'none' const messageBorder = showMessageDivider ? undefined : 'none'
return ( return useMemo(
<MessageContainer key={message.id} className="message" style={{ border: messageBorder }}> () => (
<MessageHeader> <MessageContainer key={message.id} className="message" style={{ border: messageBorder }}>
<AvatarWrapper> <MessageHeader>
{message.role === 'assistant' ? ( <AvatarWrapper>
<Avatar src={message.modelId ? getModelLogo(message.modelId) : undefined} size={35}> {message.role === 'assistant' ? (
{firstLetter(assistant?.name).toUpperCase()} <Avatar src={message.modelId ? getModelLogo(message.modelId) : undefined} size={35}>
</Avatar> {firstLetter(assistant?.name).toUpperCase()}
) : ( </Avatar>
<Avatar src={avatar} size={35} /> ) : (
<Avatar src={avatar} size={35} />
)}
<UserWrap>
<UserName>{removeLeadingEmoji(getUserName())}</UserName>
<MessageTime>{dayjs(message.createdAt).format('MM/DD HH:mm')}</MessageTime>
</UserWrap>
</AvatarWrapper>
</MessageHeader>
<MessageContent style={{ fontFamily }}>
{message.status === 'sending' && (
<MessageContentLoading>
<SyncOutlined spin size={24} />
</MessageContentLoading>
)} )}
<UserWrap> {message.status !== 'sending' && <Markdown message={message} />}
<UserName>{removeLeadingEmoji(getUserName())}</UserName> {message.usage && !generating && (
<MessageTime>{dayjs(message.createdAt).format('MM/DD HH:mm')}</MessageTime> <MessageMetadata>
</UserWrap> Tokens: {message.usage.total_tokens} | {message.usage.prompt_tokens}{message.usage.completion_tokens}
</AvatarWrapper> </MessageMetadata>
</MessageHeader> )}
<MessageContent style={{ fontFamily }}> {showMenu && (
{message.status === 'sending' && ( <MenusBar className={`menubar ${isLastMessage && 'show'} ${(!isLastMessage || isUserMessage) && 'user'}`}>
<MessageContentLoading> {message.role === 'user' && (
<SyncOutlined spin size={24} /> <Tooltip title="Edit" mouseEnterDelay={0.8}>
</MessageContentLoading> <ActionButton onClick={onEdit}>
)} <EditOutlined />
{message.status !== 'sending' && <Markdown message={message} />} </ActionButton>
{message.usage && !generating && ( </Tooltip>
<MessageMetadata> )}
Tokens: {message.usage.total_tokens} | {message.usage.prompt_tokens}{message.usage.completion_tokens} <Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
</MessageMetadata> <ActionButton onClick={onCopy}>
)} {!copied && <CopyOutlined />}
{showMenu && ( {copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
<MenusBar className={`menubar ${isLastMessage && 'show'} ${(!isLastMessage || isUserMessage) && 'user'}`}>
{message.role === 'user' && (
<Tooltip title="Edit" mouseEnterDelay={0.8}>
<ActionButton onClick={onEdit}>
<EditOutlined />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} <Tooltip title={t('common.delete')} mouseEnterDelay={0.8}>
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}> <ActionButton onClick={onDelete}>
<ActionButton onClick={onCopy}> <DeleteOutlined />
{!copied && <CopyOutlined />}
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
</ActionButton>
</Tooltip>
<Tooltip title={t('common.delete')} mouseEnterDelay={0.8}>
<ActionButton onClick={onDelete}>
<DeleteOutlined />
</ActionButton>
</Tooltip>
{canRegenerate && (
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<ActionButton onClick={onRegenerate}>
<SyncOutlined />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} {canRegenerate && (
{!isUserMessage && ( <Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<Dropdown menu={{ items: getDropdownMenus(message) }} trigger={['click']} placement="topRight" arrow> <ActionButton onClick={onRegenerate}>
<ActionButton> <SyncOutlined />
<MenuOutlined /> </ActionButton>
</ActionButton> </Tooltip>
</Dropdown> )}
)} {!isUserMessage && (
</MenusBar> <Dropdown menu={{ items: getDropdownMenus(message) }} trigger={['click']} placement="topRight" arrow>
)} <ActionButton>
</MessageContent> <MenuOutlined />
</MessageContainer> </ActionButton>
</Dropdown>
)}
</MenusBar>
)}
</MessageContent>
</MessageContainer>
),
[
assistant?.name,
avatar,
canRegenerate,
copied,
fontFamily,
generating,
getDropdownMenus,
getUserName,
isLastMessage,
isUserMessage,
message,
messageBorder,
onCopy,
onDelete,
onEdit,
onRegenerate,
showMenu,
t
]
) )
} }

View File

@ -134,6 +134,7 @@ const TopicListItem = styled.div`
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-family: Poppins;
&:hover { &:hover {
background-color: var(--color-background-soft); background-color: var(--color-background-soft);
} }