mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-22 08:40:08 +08:00
fix: assistant and agent emoji
This commit is contained in:
parent
a047048f69
commit
f448d8a8db
@ -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?",
|
||||
|
||||
@ -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": "可視化"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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": "Хотите очистить все сообщения текущего топика?",
|
||||
|
||||
@ -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": "确定要清除当前会话所有消息吗?",
|
||||
|
||||
@ -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": "您想要清除當前話題的所有訊息嗎?",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -32,7 +32,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 72,
|
||||
version: 73,
|
||||
blacklist: ['runtime'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user