feat: add username and message divider line settings

This commit is contained in:
kangfenmao 2024-07-23 15:16:34 +08:00
parent 8535edbdd1
commit c43be11d20
7 changed files with 63 additions and 10 deletions

View File

@ -105,6 +105,9 @@ const resources = {
assistant: 'Default Assistant', assistant: 'Default Assistant',
about: 'About & Feedback', about: 'About & Feedback',
'general.title': 'General Settings', 'general.title': 'General Settings',
'general.message.divider': 'Show divider between messages',
'general.user_name': 'User Name',
'general.user_name.placeholder': 'Enter your name',
'provider.api_key': 'API Key', 'provider.api_key': 'API Key',
'provider.check': 'Check', 'provider.check': 'Check',
'provider.get_api_key': 'Get API Key', 'provider.get_api_key': 'Get API Key',
@ -252,6 +255,9 @@ const resources = {
assistant: '默认助手', assistant: '默认助手',
about: '关于我们', about: '关于我们',
'general.title': '常规设置', 'general.title': '常规设置',
'general.user_name': '用户名',
'general.user_name.placeholder': '请输入用户名',
'general.message.divider': '消息分割线',
'provider.api_key': 'API 密钥', 'provider.api_key': 'API 密钥',
'provider.check': '检查', 'provider.check': '检查',
'provider.get_api_key': '点击这里获取密钥', 'provider.get_api_key': '点击这里获取密钥',

View File

@ -16,6 +16,7 @@ import { isEmpty, upperFirst } from 'lodash'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useAppSelector } from '@renderer/store' import { useAppSelector } from '@renderer/store'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
interface Props { interface Props {
message: Message message: Message
@ -30,6 +31,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
const { t } = useTranslation() const { t } = useTranslation()
const generating = useAppSelector((state) => state.runtime.generating) const generating = useAppSelector((state) => state.runtime.generating)
const { assistant } = useAssistant(message.assistantId) const { assistant } = useAssistant(message.assistantId)
const { userName, showMessageDivider } = useSettings()
const isLastMessage = index === 0 const isLastMessage = index === 0
const isUserMessage = message.role === 'user' const isUserMessage = message.role === 'user'
@ -76,10 +78,10 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
return upperFirst(message.modelId) return upperFirst(message.modelId)
} }
return t('common.you') return userName || t('common.you')
} }
const borderBottom = (isLastMessage && !isUserMessage) || generating ? 'none' : undefined const borderBottom = (isLastMessage && !isUserMessage) || generating || !showMessageDivider ? 'none' : undefined
return ( return (
<MessageContainer key={message.id} style={{ borderBottom }}> <MessageContainer key={message.id} style={{ borderBottom }}>
@ -99,7 +101,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
</AvatarWrapper> </AvatarWrapper>
{message.usage && ( {message.usage && (
<MessageMetadata> <MessageMetadata>
Tokens: {message.usage.total_tokens} | {message.usage.prompt_tokens}{message.usage.completion_tokens} Tokens: {message.usage.total_tokens} | {message.usage.prompt_tokens}{message.usage.completion_tokens}
</MessageMetadata> </MessageMetadata>
)} )}
</MessageHeader> </MessageHeader>

View File

@ -1,6 +1,6 @@
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components' import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
import { Avatar, Input, Select, Upload } from 'antd' import { Avatar, Input, Select, Switch, Upload } from 'antd'
import styled from 'styled-components' import styled from 'styled-components'
import LocalStorage from '@renderer/services/storage' import LocalStorage from '@renderer/services/storage'
import { compressImage, isValidProxyUrl } from '@renderer/utils' import { compressImage, isValidProxyUrl } from '@renderer/utils'
@ -8,14 +8,14 @@ import useAvatar from '@renderer/hooks/useAvatar'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { setAvatar } from '@renderer/store/runtime' import { setAvatar } from '@renderer/store/runtime'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { setLanguage } from '@renderer/store/settings' import { setLanguage, setShowMessageDivider, setUserName } from '@renderer/store/settings'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings' import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import i18n from '@renderer/i18n' import i18n from '@renderer/i18n'
const GeneralSettings: FC = () => { const GeneralSettings: FC = () => {
const avatar = useAvatar() const avatar = useAvatar()
const { language, proxyUrl: storeProxyUrl } = useSettings() const { language, proxyUrl: storeProxyUrl, userName, showMessageDivider } = useSettings()
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl) const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { t } = useTranslation() const { t } = useTranslation()
@ -74,6 +74,17 @@ const GeneralSettings: FC = () => {
</Upload> </Upload>
</SettingRow> </SettingRow>
<SettingDivider /> <SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.user_name')}</SettingRowTitle>
<Input
placeholder={t('settings.general.user_name.placeholder')}
value={userName}
onChange={(e) => dispatch(setUserName(e.target.value))}
style={{ width: 150 }}
maxLength={30}
/>
</SettingRow>
<SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle> <SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle>
<Input <Input
@ -86,6 +97,11 @@ const GeneralSettings: FC = () => {
/> />
</SettingRow> </SettingRow>
<SettingDivider /> <SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.message.divider')}</SettingRowTitle>
<Switch checked={showMessageDivider} onChange={(checked) => dispatch(setShowMessageDivider(checked))} />
</SettingRow>
<SettingDivider />
</SettingContainer> </SettingContainer>
) )
} }

View File

@ -39,6 +39,7 @@ export const SettingRow = styled.div`
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
min-height: 40px;
` `
export const SettingRowTitle = styled.div` export const SettingRowTitle = styled.div`

View File

@ -19,7 +19,7 @@ const persistedReducer = persistReducer(
{ {
key: 'cherry-studio', key: 'cherry-studio',
storage, storage,
version: 14, version: 15,
blacklist: ['runtime'], blacklist: ['runtime'],
migrate migrate
}, },

View File

@ -254,6 +254,17 @@ const migrate = createMigrate({
proxyUrl: undefined proxyUrl: undefined
} }
} }
},
// @ts-ignore store type is unknown
'15': (state: RootState) => {
return {
...state,
settings: {
...state.settings,
userName: '',
showMessageDivider: true
}
}
} }
}) })

View File

@ -8,6 +8,8 @@ export interface SettingsState {
sendMessageShortcut: SendMessageShortcut sendMessageShortcut: SendMessageShortcut
language: string language: string
proxyUrl?: string proxyUrl?: string
userName: string
showMessageDivider: boolean
} }
const initialState: SettingsState = { const initialState: SettingsState = {
@ -15,7 +17,9 @@ const initialState: SettingsState = {
showAssistants: true, showAssistants: true,
sendMessageShortcut: 'Enter', sendMessageShortcut: 'Enter',
language: navigator.language, language: navigator.language,
proxyUrl: undefined proxyUrl: undefined,
userName: '',
showMessageDivider: true
} }
const settingsSlice = createSlice({ const settingsSlice = createSlice({
@ -36,11 +40,24 @@ const settingsSlice = createSlice({
}, },
setProxyUrl: (state, action: PayloadAction<string | undefined>) => { setProxyUrl: (state, action: PayloadAction<string | undefined>) => {
state.proxyUrl = action.payload state.proxyUrl = action.payload
},
setUserName: (state, action: PayloadAction<string>) => {
state.userName = action.payload
},
setShowMessageDivider: (state, action: PayloadAction<boolean>) => {
state.showMessageDivider = action.payload
} }
} }
}) })
export const { toggleRightSidebar, toggleShowAssistants, setSendMessageShortcut, setLanguage, setProxyUrl } = export const {
settingsSlice.actions toggleRightSidebar,
toggleShowAssistants,
setSendMessageShortcut,
setLanguage,
setProxyUrl,
setUserName,
setShowMessageDivider
} = settingsSlice.actions
export default settingsSlice.reducer export default settingsSlice.reducer