fix: assistant and agent emoji

This commit is contained in:
kangfenmao 2025-02-25 19:53:04 +08:00
parent a047048f69
commit f448d8a8db
12 changed files with 133 additions and 60 deletions

View File

@ -79,7 +79,7 @@
"assistant.search.placeholder": "Search",
"deeply_thought": "Deeply thought ({{secounds}} seconds)",
"default.description": "Hello, I'm Default Assistant. You can start chatting with me right away",
"default.name": "⭐️ Default Assistant",
"default.name": "Default Assistant",
"default.topic.name": "Default Topic",
"input.clear": "Clear {{Command}}",
"input.clear.content": "Do you want to clear all messages of the current topic?",

View File

@ -79,7 +79,7 @@
"assistant.search.placeholder": "検索",
"deeply_thought": "深く考えています({{secounds}} 秒)",
"default.description": "こんにちは、私はデフォルトのアシスタントです。すぐにチャットを始められます。",
"default.name": "⭐️ デフォルトアシスタント",
"default.name": "デフォルトアシスタント",
"default.topic.name": "デフォルトトピック",
"input.clear": "クリア {{Command}}",
"input.clear.content": "現在のトピックのすべてのメッセージをクリアしますか?",
@ -866,4 +866,4 @@
"visualization": "可視化"
}
}
}
}

View File

@ -79,7 +79,7 @@
"assistant.search.placeholder": "Поиск",
"deeply_thought": "Мыслим ({{secounds}} секунд)",
"default.description": "Привет, я Ассистент по умолчанию. Вы можете начать общаться со мной прямо сейчас",
"default.name": "⭐️ Ассистент по умолчанию",
"default.name": "Ассистент по умолчанию",
"default.topic.name": "Топик по умолчанию",
"input.clear": "Очистить {{Command}}",
"input.clear.content": "Хотите очистить все сообщения текущего топика?",

View File

@ -79,7 +79,7 @@
"assistant.search.placeholder": "搜索",
"deeply_thought": "已深度思考(用时 {{secounds}} 秒)",
"default.description": "你好,我是默认助手。你可以立刻开始跟我聊天。",
"default.name": "⭐️ 默认助手",
"default.name": "默认助手",
"default.topic.name": "默认话题",
"input.clear": "清空消息 {{Command}}",
"input.clear.content": "确定要清除当前会话所有消息吗?",

View File

@ -79,7 +79,7 @@
"assistant.search.placeholder": "搜尋",
"deeply_thought": "已深度思考(用時 {{secounds}} 秒)",
"default.description": "你好,我是預設助手。你可以立即開始與我聊天。",
"default.name": "⭐️ 預設助手",
"default.name": "預設助手",
"default.topic.name": "預設話題",
"input.clear": "清除 {{Command}}",
"input.clear.content": "您想要清除當前話題的所有訊息嗎?",

View File

@ -66,14 +66,10 @@ const AgentsPage: FC = () => {
return { 搜索结果: Array.from(uniqueAgents.values()) }
}, [agentGroups, search])
const getAgentName = (agent: Agent) => {
return agent.emoji ? agent.emoji + ' ' + agent.name : agent.name
}
const onAddAgentConfirm = useCallback(
(agent: Agent) => {
window.modal.confirm({
title: getAgentName(agent),
title: agent.name,
content: (
<AgentPrompt>
<ReactMarkdown className="markdown">{agent.description || agent.prompt}</ReactMarkdown>

View File

@ -107,10 +107,14 @@ const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch,
onSwitch(assistant)
}, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition])
const assistantName = assistant.name || t('chat.default.name')
return (
<Dropdown menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}>
<Container onClick={handleSwitch} className={isActive ? 'active' : ''}>
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
<AssistantName className="name">
{assistant.emoji ? `${assistant.emoji} ${assistantName}` : assistantName}
</AssistantName>
{isActive && (
<MenuButton onClick={() => EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)}>
<TopicCount className="topics-count">{assistant.topics.length}</TopicCount>

View File

@ -25,13 +25,13 @@ const AssistantPromptSettings: React.FC<Props> = ({ assistant, updateAssistant,
const { t } = useTranslation()
const onUpdate = () => {
const _assistant = { ...assistant, name: `${emoji} ${name}`.trim(), prompt }
const _assistant = { ...assistant, name: name.trim(), emoji, prompt }
updateAssistant(_assistant)
}
const handleEmojiSelect = (selectedEmoji: string) => {
setEmoji(selectedEmoji)
const _assistant = { ...assistant, name: `${selectedEmoji} ${name}`.trim(), prompt }
const _assistant = { ...assistant, name: name.trim(), emoji: selectedEmoji, prompt }
updateAssistant(_assistant)
}

View File

@ -1,11 +1,13 @@
import { QuestionCircleOutlined } from '@ant-design/icons'
import { CloseCircleFilled, QuestionCircleOutlined } from '@ant-design/icons'
import EmojiPicker from '@renderer/components/EmojiPicker'
import { HStack } from '@renderer/components/Layout'
import { TopView } from '@renderer/components/TopView'
import { DEFAULT_CONTEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { AssistantSettings as AssistantSettingsType } from '@renderer/types'
import { Button, Col, Input, InputNumber, Modal, Row, Slider, Switch, Tooltip } from 'antd'
import { getLeadingEmoji, modalConfirm } from '@renderer/utils'
import { Button, Col, Input, InputNumber, Modal, Popover, Row, Slider, Switch, Tooltip } from 'antd'
import TextArea from 'antd/es/input/TextArea'
import { Dispatch, FC, SetStateAction, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -20,6 +22,10 @@ const AssistantSettings: FC = () => {
const [enableMaxTokens, setEnableMaxTokens] = useState(defaultAssistant?.settings?.enableMaxTokens ?? false)
const [maxTokens, setMaxTokens] = useState(defaultAssistant?.settings?.maxTokens ?? 0)
const [topP, setTopP] = useState(defaultAssistant.settings?.topP ?? 1)
const [emoji, setEmoji] = useState(defaultAssistant.emoji || getLeadingEmoji(defaultAssistant.name) || '')
const [name, setName] = useState(
defaultAssistant.name.replace(getLeadingEmoji(defaultAssistant.name) || '', '').trim()
)
const { theme } = useTheme()
const { t } = useTranslation()
@ -73,15 +79,56 @@ const AssistantSettings: FC = () => {
})
}
const handleEmojiSelect = (selectedEmoji: string) => {
setEmoji(selectedEmoji)
updateDefaultAssistant({ ...defaultAssistant, emoji: selectedEmoji, name })
}
const handleEmojiDelete = () => {
setEmoji('')
updateDefaultAssistant({ ...defaultAssistant, emoji: '', name })
}
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newName = e.target.value
setName(newName)
updateDefaultAssistant({ ...defaultAssistant, name: newName })
}
return (
<SettingContainer style={{ height: 'auto', background: 'transparent', padding: 0 }} theme={theme}>
<SettingSubtitle style={{ marginTop: 0 }}>{t('common.name')}</SettingSubtitle>
<Input
placeholder={t('common.assistant') + t('common.name')}
value={defaultAssistant.name}
onChange={(e) => updateDefaultAssistant({ ...defaultAssistant, name: e.target.value })}
style={{ margin: '10px 0' }}
/>
<HStack gap={8} alignItems="center" style={{ margin: '10px 0' }}>
<Popover content={<EmojiPicker onEmojiClick={handleEmojiSelect} />} arrow>
<EmojiButtonWrapper>
<Button style={{ fontSize: 20, padding: '4px', minWidth: '32px', height: '32px' }}>{emoji}</Button>
{emoji && (
<CloseCircleFilled
className="delete-icon"
onClick={(e) => {
e.stopPropagation()
handleEmojiDelete()
}}
style={{
display: 'none',
position: 'absolute',
top: '-8px',
right: '-8px',
fontSize: '16px',
color: '#ff4d4f',
cursor: 'pointer'
}}
/>
)}
</EmojiButtonWrapper>
</Popover>
<Input
placeholder={t('common.assistant') + t('common.name')}
value={name}
onChange={handleNameChange}
style={{ flex: 1 }}
/>
</HStack>
<SettingSubtitle>{t('common.prompt')}</SettingSubtitle>
<TextArea
rows={4}
@ -182,7 +229,7 @@ const AssistantSettings: FC = () => {
/>
</Col>
</Row>
<Row align="middle">
<Row align="middle" style={{ marginBottom: 10 }}>
<HStack alignItems="center">
<Label>{t('chat.settings.max_tokens')}</Label>
<Tooltip title={t('chat.settings.max_tokens.tip')}>
@ -192,41 +239,39 @@ const AssistantSettings: FC = () => {
<Switch
style={{ marginLeft: 10 }}
checked={enableMaxTokens}
onChange={(enabled) => {
onChange={async (enabled) => {
if (enabled) {
const confirmed = await modalConfirm({
title: t('chat.settings.max_tokens.confirm'),
content: t('chat.settings.max_tokens.confirm_content'),
okButtonProps: {
danger: true
}
})
if (!confirmed) return
}
setEnableMaxTokens(enabled)
onUpdateAssistantSettings({ enableMaxTokens: enabled })
}}
/>
</Row>
<Row align="middle" gutter={20}>
<Col span={21}>
<Slider
disabled={!enableMaxTokens}
min={0}
max={32000}
onChange={setMaxTokens}
onChangeComplete={onMaxTokensChange}
value={typeof maxTokens === 'number' ? maxTokens : 0}
step={100}
marks={{
0: '0',
32000: t('chat.settings.max')
}}
/>
</Col>
<Col span={3}>
<InputNumber
disabled={!enableMaxTokens}
min={0}
max={32000}
step={100}
value={maxTokens}
onChange={onMaxTokensChange}
controls={true}
style={{ width: '100%' }}
/>
</Col>
</Row>
{enableMaxTokens && (
<Row align="middle" gutter={20}>
<Col span={24}>
<InputNumber
disabled={!enableMaxTokens}
min={0}
max={10000000}
step={100}
value={maxTokens}
changeOnBlur
onChange={onMaxTokensChange}
style={{ width: '100%' }}
/>
</Col>
</Row>
)}
</SettingContainer>
)
}
@ -290,6 +335,15 @@ export default class DefaultAssistantSettingsPopup {
}
}
const EmojiButtonWrapper = styled.div`
position: relative;
display: inline-block;
&:hover .delete-icon {
display: block !important;
}
`
const Label = styled.p`
margin: 0;
font-size: 14px;

View File

@ -12,6 +12,7 @@ export function getDefaultAssistant(): Assistant {
return {
id: 'default',
name: i18n.t('chat.default.name'),
emoji: '⭐️',
prompt: '',
topics: [getDefaultTopic('default')],
messages: [],
@ -110,10 +111,6 @@ export const getAssistantSettings = (assistant: Assistant): AssistantSettings =>
}
}
export function getAssistantNameWithAgent(agent: Agent) {
return agent.emoji ? agent.emoji + ' ' + agent.name : agent.name
}
export function getAssistantById(id: string) {
const assistants = store.getState().assistants.assistants
return assistants.find((a) => a.id === id)
@ -152,7 +149,8 @@ export async function createAssistantFromAgent(agent: Agent) {
const assistant: Assistant = {
...agent,
id: assistantId,
name: agent.emoji ? agent.emoji + ' ' + agent.name : agent.name,
name: agent.name,
emoji: agent.emoji,
topics: [topic],
model: agent.defaultModel,
type: 'assistant'

View File

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

View File

@ -5,7 +5,7 @@ import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
import db from '@renderer/databases'
import i18n from '@renderer/i18n'
import { Assistant } from '@renderer/types'
import { getDefaultGroupName, runAsyncFunction, uuid } from '@renderer/utils'
import { getDefaultGroupName, getLeadingEmoji, runAsyncFunction, uuid } from '@renderer/utils'
import { isEmpty } from 'lodash'
import { createMigrate } from 'redux-persist'
@ -1137,6 +1137,27 @@ const migrateConfig = {
enabled: false
})
}
state.assistants.assistants.forEach((assistant) => {
const leadingEmoji = getLeadingEmoji(assistant.name)
if (leadingEmoji) {
assistant.emoji = leadingEmoji
assistant.name = assistant.name.replace(leadingEmoji, '').trim()
}
})
state.agents.agents.forEach((agent) => {
const leadingEmoji = getLeadingEmoji(agent.name)
if (leadingEmoji) {
agent.emoji = leadingEmoji
agent.name = agent.name.replace(leadingEmoji, '').trim()
}
})
const defaultAssistantEmoji = getLeadingEmoji(state.assistants.defaultAssistant.name)
if (defaultAssistantEmoji) {
state.assistants.defaultAssistant.emoji = defaultAssistantEmoji
state.assistants.defaultAssistant.name = state.assistants.defaultAssistant.name
.replace(defaultAssistantEmoji, '')
.trim()
}
return state
}
}