mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 23:59:45 +08:00
feat(assistants): place copied assistant after the original one (#8557)
* feat(assistants): 复制助手功能插入到原助手后 添加 insertAssistant 方法用于在指定位置插入助手 实现 copyAssistant 功能用于复制助手并插入到原助手后面 更新相关组件以使用新的复制功能 * fix(useAssistant): 修复助手索引检查逻辑错误 原条件判断错误导致未找到索引时仍执行更新操作,现修正为仅在索引存在时更新 * fix(useAssistant): 添加错误处理及国际化支持 捕获插入助手时的异常并显示错误提示 添加react-i18next的翻译功能用于错误消息
This commit is contained in:
parent
dfceed8751
commit
46d98c2b22
@ -1,9 +1,11 @@
|
|||||||
import { db } from '@renderer/databases'
|
import { db } from '@renderer/databases'
|
||||||
import { getDefaultTopic } from '@renderer/services/AssistantService'
|
import { getDefaultTopic } from '@renderer/services/AssistantService'
|
||||||
|
import { loggerService } from '@renderer/services/LoggerService'
|
||||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||||
import {
|
import {
|
||||||
addAssistant,
|
addAssistant,
|
||||||
addTopic,
|
addTopic,
|
||||||
|
insertAssistant,
|
||||||
removeAllTopics,
|
removeAllTopics,
|
||||||
removeAssistant,
|
removeAssistant,
|
||||||
removeTopic,
|
removeTopic,
|
||||||
@ -17,18 +19,44 @@ import {
|
|||||||
} from '@renderer/store/assistants'
|
} from '@renderer/store/assistants'
|
||||||
import { setDefaultModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
|
import { setDefaultModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
|
||||||
import { Assistant, AssistantSettings, Model, Topic } from '@renderer/types'
|
import { Assistant, AssistantSettings, Model, Topic } from '@renderer/types'
|
||||||
|
import { uuid } from '@renderer/utils'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { TopicManager } from './useTopic'
|
import { TopicManager } from './useTopic'
|
||||||
|
|
||||||
export function useAssistants() {
|
export function useAssistants() {
|
||||||
|
const { t } = useTranslation()
|
||||||
const { assistants } = useAppSelector((state) => state.assistants)
|
const { assistants } = useAppSelector((state) => state.assistants)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const logger = loggerService.withContext('useAssistants')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
assistants,
|
assistants,
|
||||||
updateAssistants: (assistants: Assistant[]) => dispatch(updateAssistants(assistants)),
|
updateAssistants: (assistants: Assistant[]) => dispatch(updateAssistants(assistants)),
|
||||||
addAssistant: (assistant: Assistant) => dispatch(addAssistant(assistant)),
|
addAssistant: (assistant: Assistant) => dispatch(addAssistant(assistant)),
|
||||||
|
insertAssistant: (index: number, assistant: Assistant) => dispatch(insertAssistant({ index, assistant })),
|
||||||
|
copyAssistant: (assistant: Assistant): Assistant | undefined => {
|
||||||
|
if (!assistant) {
|
||||||
|
logger.error("assistant doesn't exists.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const index = assistants.findIndex((_assistant) => _assistant.id === assistant.id)
|
||||||
|
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic(assistant.id)] }
|
||||||
|
if (index === -1) {
|
||||||
|
logger.warn("Origin assistant's id not found. Fallback to addAssistant.")
|
||||||
|
dispatch(addAssistant(_assistant))
|
||||||
|
} else {
|
||||||
|
// 插入到后面
|
||||||
|
try {
|
||||||
|
dispatch(insertAssistant({ index: index + 1, assistant: _assistant }))
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Failed to insert assistant', e as Error)
|
||||||
|
window.message.error(t('message.error.copy'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _assistant
|
||||||
|
},
|
||||||
removeAssistant: (id: string) => {
|
removeAssistant: (id: string) => {
|
||||||
dispatch(removeAssistant({ id }))
|
dispatch(removeAssistant({ id }))
|
||||||
const assistant = assistants.find((a) => a.id === id)
|
const assistant = assistants.find((a) => a.id === id)
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const Assistants: FC<AssistantsTabProps> = ({
|
|||||||
onCreateAssistant,
|
onCreateAssistant,
|
||||||
onCreateDefaultAssistant
|
onCreateDefaultAssistant
|
||||||
}) => {
|
}) => {
|
||||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
const { assistants, removeAssistant, copyAssistant, updateAssistants } = useAssistants()
|
||||||
const [dragging, setDragging] = useState(false)
|
const [dragging, setDragging] = useState(false)
|
||||||
const { addAgent } = useAgents()
|
const { addAgent } = useAgents()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -106,7 +106,7 @@ const Assistants: FC<AssistantsTabProps> = ({
|
|||||||
onSwitch={setActiveAssistant}
|
onSwitch={setActiveAssistant}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
addAgent={addAgent}
|
addAgent={addAgent}
|
||||||
addAssistant={addAssistant}
|
copyAssistant={copyAssistant}
|
||||||
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
||||||
handleSortByChange={handleSortByChange}
|
handleSortByChange={handleSortByChange}
|
||||||
/>
|
/>
|
||||||
@ -143,7 +143,7 @@ const Assistants: FC<AssistantsTabProps> = ({
|
|||||||
onSwitch={setActiveAssistant}
|
onSwitch={setActiveAssistant}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
addAgent={addAgent}
|
addAgent={addAgent}
|
||||||
addAssistant={addAssistant}
|
copyAssistant={copyAssistant}
|
||||||
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
||||||
handleSortByChange={handleSortByChange}
|
handleSortByChange={handleSortByChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
|
|||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useTags } from '@renderer/hooks/useTags'
|
import { useTags } from '@renderer/hooks/useTags'
|
||||||
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
||||||
import { getDefaultModel, getDefaultTopic } from '@renderer/services/AssistantService'
|
import { getDefaultModel } from '@renderer/services/AssistantService'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
import { Assistant, AssistantsSortType } from '@renderer/types'
|
import { Assistant, AssistantsSortType } from '@renderer/types'
|
||||||
import { getLeadingEmoji, uuid } from '@renderer/utils'
|
import { getLeadingEmoji, uuid } from '@renderer/utils'
|
||||||
@ -40,7 +40,7 @@ interface AssistantItemProps {
|
|||||||
onDelete: (assistant: Assistant) => void
|
onDelete: (assistant: Assistant) => void
|
||||||
onCreateDefaultAssistant: () => void
|
onCreateDefaultAssistant: () => void
|
||||||
addAgent: (agent: any) => void
|
addAgent: (agent: any) => void
|
||||||
addAssistant: (assistant: Assistant) => void
|
copyAssistant: (assistant: Assistant) => void
|
||||||
onTagClick?: (tag: string) => void
|
onTagClick?: (tag: string) => void
|
||||||
handleSortByChange?: (sortType: AssistantsSortType) => void
|
handleSortByChange?: (sortType: AssistantsSortType) => void
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ const AssistantItem: FC<AssistantItemProps> = ({
|
|||||||
onSwitch,
|
onSwitch,
|
||||||
onDelete,
|
onDelete,
|
||||||
addAgent,
|
addAgent,
|
||||||
addAssistant,
|
copyAssistant,
|
||||||
handleSortByChange
|
handleSortByChange
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -91,7 +91,7 @@ const AssistantItem: FC<AssistantItemProps> = ({
|
|||||||
assistants,
|
assistants,
|
||||||
updateAssistants,
|
updateAssistants,
|
||||||
addAgent,
|
addAgent,
|
||||||
addAssistant,
|
copyAssistant,
|
||||||
onSwitch,
|
onSwitch,
|
||||||
onDelete,
|
onDelete,
|
||||||
removeAllTopics,
|
removeAllTopics,
|
||||||
@ -108,7 +108,7 @@ const AssistantItem: FC<AssistantItemProps> = ({
|
|||||||
assistants,
|
assistants,
|
||||||
updateAssistants,
|
updateAssistants,
|
||||||
addAgent,
|
addAgent,
|
||||||
addAssistant,
|
copyAssistant,
|
||||||
onSwitch,
|
onSwitch,
|
||||||
onDelete,
|
onDelete,
|
||||||
removeAllTopics,
|
removeAllTopics,
|
||||||
@ -246,7 +246,7 @@ function getMenuItems({
|
|||||||
assistants,
|
assistants,
|
||||||
updateAssistants,
|
updateAssistants,
|
||||||
addAgent,
|
addAgent,
|
||||||
addAssistant,
|
copyAssistant,
|
||||||
onSwitch,
|
onSwitch,
|
||||||
onDelete,
|
onDelete,
|
||||||
removeAllTopics,
|
removeAllTopics,
|
||||||
@ -268,9 +268,10 @@ function getMenuItems({
|
|||||||
key: 'duplicate',
|
key: 'duplicate',
|
||||||
icon: <CopyIcon />,
|
icon: <CopyIcon />,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic(assistant.id)] }
|
const _assistant = copyAssistant(assistant)
|
||||||
addAssistant(_assistant)
|
if (_assistant) {
|
||||||
onSwitch(_assistant)
|
onSwitch(_assistant)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -32,6 +32,15 @@ const assistantsSlice = createSlice({
|
|||||||
addAssistant: (state, action: PayloadAction<Assistant>) => {
|
addAssistant: (state, action: PayloadAction<Assistant>) => {
|
||||||
state.assistants.push(action.payload)
|
state.assistants.push(action.payload)
|
||||||
},
|
},
|
||||||
|
insertAssistant: (state, action: PayloadAction<{ index: number; assistant: Assistant }>) => {
|
||||||
|
const { index, assistant } = action.payload
|
||||||
|
|
||||||
|
if (index < 0 || index > state.assistants.length) {
|
||||||
|
throw new Error(`InsertAssistant: index ${index} is out of bounds [0, ${state.assistants.length}]`)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.assistants.splice(index, 0, assistant)
|
||||||
|
},
|
||||||
removeAssistant: (state, action: PayloadAction<{ id: string }>) => {
|
removeAssistant: (state, action: PayloadAction<{ id: string }>) => {
|
||||||
state.assistants = state.assistants.filter((c) => c.id !== action.payload.id)
|
state.assistants = state.assistants.filter((c) => c.id !== action.payload.id)
|
||||||
},
|
},
|
||||||
@ -170,6 +179,7 @@ export const {
|
|||||||
updateDefaultAssistant,
|
updateDefaultAssistant,
|
||||||
updateAssistants,
|
updateAssistants,
|
||||||
addAssistant,
|
addAssistant,
|
||||||
|
insertAssistant,
|
||||||
removeAssistant,
|
removeAssistant,
|
||||||
updateAssistant,
|
updateAssistant,
|
||||||
addTopic,
|
addTopic,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user