diff --git a/src/renderer/src/hooks/useAssistant.ts b/src/renderer/src/hooks/useAssistant.ts
index dd2d47b89f..23b538b56a 100644
--- a/src/renderer/src/hooks/useAssistant.ts
+++ b/src/renderer/src/hooks/useAssistant.ts
@@ -15,7 +15,7 @@ import {
updateTopic,
updateTopics
} from '@renderer/store/assistants'
-import { setDefaultModel, setQuickAssistantModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
+import { setDefaultModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
import { Assistant, AssistantSettings, Model, Topic } from '@renderer/types'
import { useCallback, useMemo } from 'react'
@@ -103,17 +103,15 @@ export function useDefaultAssistant() {
}
export function useDefaultModel() {
- const { defaultModel, topicNamingModel, translateModel, quickAssistantModel } = useAppSelector((state) => state.llm)
+ const { defaultModel, topicNamingModel, translateModel } = useAppSelector((state) => state.llm)
const dispatch = useAppDispatch()
return {
defaultModel,
topicNamingModel,
translateModel,
- quickAssistantModel,
setDefaultModel: (model: Model) => dispatch(setDefaultModel({ model })),
setTopicNamingModel: (model: Model) => dispatch(setTopicNamingModel({ model })),
- setTranslateModel: (model: Model) => dispatch(setTranslateModel({ model })),
- setQuickAssistantModel: (model: Model) => dispatch(setQuickAssistantModel({ model }))
+ setTranslateModel: (model: Model) => dispatch(setTranslateModel({ model }))
}
}
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index 46c32545c0..d533dac446 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -1592,6 +1592,10 @@
"models.translate_model_prompt_title": "Translate Model Prompt",
"models.quick_assistant_model": "Quick Assistant Model",
"models.quick_assistant_model_description": "Default model used by Quick Assistant",
+ "models.quick_assistant_selection": "Select Assistant",
+ "models.quick_assistant_default_tag": "Default",
+ "models.use_model": "Default Model",
+ "models.use_assistant": "Use Assistant",
"moresetting": "More Settings",
"moresetting.check.confirm": "Confirm Selection",
"moresetting.check.warn": "Please be cautious when selecting this option. Incorrect selection may cause the model to malfunction!",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index d155eea480..a59b2ed984 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -1586,6 +1586,10 @@
"models.translate_model_prompt_title": "翻訳モデルのプロンプト",
"models.quick_assistant_model": "クイックアシスタントモデル",
"models.quick_assistant_model_description": "クイックアシスタントで使用されるデフォルトモデル",
+ "models.quick_assistant_selection": "アシスタントを選択します",
+ "models.quick_assistant_default_tag": "デフォルト",
+ "models.use_model": "デフォルトモデル",
+ "models.use_assistant": "アシスタントの活用",
"moresetting": "詳細設定",
"moresetting.check.confirm": "選択を確認",
"moresetting.check.warn": "このオプションを選択する際は慎重に行ってください。誤った選択はモデルの誤動作を引き起こす可能性があります!",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index 444440f604..4b1264e30e 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -1586,6 +1586,10 @@
"models.translate_model_prompt_title": "Модель перевода",
"models.quick_assistant_model": "Модель быстрого помощника",
"models.quick_assistant_model_description": "Модель по умолчанию, используемая быстрым помощником",
+ "models.quick_assistant_selection": "Выберите помощника",
+ "models.quick_assistant_default_tag": "умолчанию",
+ "models.use_model": "модель по умолчанию",
+ "models.use_assistant": "Использование ассистентов",
"moresetting": "Дополнительные настройки",
"moresetting.check.confirm": "Подтвердить выбор",
"moresetting.check.warn": "Пожалуйста, будьте осторожны при выборе этой опции. Неправильный выбор может привести к сбою в работе модели!",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index 09ba5b4bdb..ca1d1da3d2 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -1592,6 +1592,10 @@
"models.translate_model_prompt_title": "翻译模型提示词",
"models.quick_assistant_model": "快捷助手模型",
"models.quick_assistant_model_description": "快捷助手使用的默认模型",
+ "models.quick_assistant_selection": "选择助手",
+ "models.quick_assistant_default_tag": "默认",
+ "models.use_model": "默认模型",
+ "models.use_assistant": "使用助手",
"moresetting": "更多设置",
"moresetting.check.confirm": "确认勾选",
"moresetting.check.warn": "请慎重勾选此选项,勾选错误会导致模型无法正常使用!!!",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index bae3c5331c..ca88470f2a 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -1589,6 +1589,10 @@
"models.translate_model_prompt_title": "翻譯模型提示詞",
"models.quick_assistant_model": "快捷助手模型",
"models.quick_assistant_model_description": "快捷助手使用的預設模型",
+ "models.quick_assistant_selection": "選擇助手",
+ "models.quick_assistant_default_tag": "預設",
+ "models.use_model": "預設模型",
+ "models.use_assistant": "使用助手",
"moresetting": "更多設定",
"moresetting.check.confirm": "確認勾選",
"moresetting.check.warn": "請謹慎勾選此選項,勾選錯誤會導致模型無法正常使用!!!",
@@ -1957,7 +1961,7 @@
},
"opacity": {
"title": "透明度",
- "description": "設置視窗的默認透明度,100%為完全不透明"
+ "description": "設置視窗的預設透明度,100%為完全不透明"
}
},
"actions": {
diff --git a/src/renderer/src/pages/settings/ModelSettings/ModelSettings.tsx b/src/renderer/src/pages/settings/ModelSettings/ModelSettings.tsx
index 1003c011d0..d61767b3af 100644
--- a/src/renderer/src/pages/settings/ModelSettings/ModelSettings.tsx
+++ b/src/renderer/src/pages/settings/ModelSettings/ModelSettings.tsx
@@ -1,37 +1,35 @@
import { RedoOutlined } from '@ant-design/icons'
+import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
import { HStack } from '@renderer/components/Layout'
import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { isEmbeddingModel } from '@renderer/config/models'
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
import { useTheme } from '@renderer/context/ThemeProvider'
-import { useDefaultModel } from '@renderer/hooks/useAssistant'
+import { useAssistants, useDefaultAssistant, useDefaultModel } from '@renderer/hooks/useAssistant'
import { useProviders } from '@renderer/hooks/useProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { getModelUniqId, hasModel } from '@renderer/services/ModelService'
+import { useAppSelector } from '@renderer/store'
import { useAppDispatch } from '@renderer/store'
+import { setQuickAssistantId } from '@renderer/store/llm'
import { setTranslateModelPrompt } from '@renderer/store/settings'
import { Model } from '@renderer/types'
import { Button, Select, Tooltip } from 'antd'
import { find, sortBy } from 'lodash'
-import { FolderPen, Languages, MessageSquareMore, Rocket, Settings2 } from 'lucide-react'
+import { CircleHelp, FolderPen, Languages, MessageSquareMore, Rocket, Settings2 } from 'lucide-react'
import { FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
+import styled from 'styled-components'
import { SettingContainer, SettingDescription, SettingGroup, SettingTitle } from '..'
import DefaultAssistantSettings from './DefaultAssistantSettings'
import TopicNamingModalPopup from './TopicNamingModalPopup'
const ModelSettings: FC = () => {
- const {
- defaultModel,
- topicNamingModel,
- translateModel,
- quickAssistantModel,
- setDefaultModel,
- setTopicNamingModel,
- setTranslateModel,
- setQuickAssistantModel
- } = useDefaultModel()
+ const { defaultModel, topicNamingModel, translateModel, setDefaultModel, setTopicNamingModel, setTranslateModel } =
+ useDefaultModel()
+ const { defaultAssistant } = useDefaultAssistant()
+ const { assistants } = useAssistants()
const { providers } = useProviders()
const allModels = providers.map((p) => p.models).flat()
const { theme } = useTheme()
@@ -39,6 +37,7 @@ const ModelSettings: FC = () => {
const { translateModelPrompt } = useSettings()
const dispatch = useAppDispatch()
+ const { quickAssistantId } = useAppSelector((state) => state.llm)
const selectOptions = providers
.filter((p) => p.models.length > 0)
@@ -68,11 +67,6 @@ const ModelSettings: FC = () => {
[translateModel]
)
- const defaultQuickAssistantModel = useMemo(
- () => (hasModel(quickAssistantModel) ? getModelUniqId(quickAssistantModel) : undefined),
- [quickAssistantModel]
- )
-
const onUpdateTranslateModel = async () => {
const prompt = await PromptPopup.show({
title: t('settings.models.translate_model_prompt_title'),
@@ -163,27 +157,118 @@ const ModelSettings: FC = () => {
{t('settings.models.translate_model_description')}
-
-
-
- {t('settings.models.quick_assistant_model')}
-
-
-
-
)
}
+const QuestionIcon = styled(CircleHelp)`
+ cursor: pointer;
+ color: var(--color-text-3);
+`
+
+const StyledButton = styled(Button)<{ selected: boolean }>`
+ border-radius: ${(props) => (props.selected ? '6px' : '6px')};
+ z-index: ${(props) => (props.selected ? 1 : 0)};
+ min-width: 80px;
+
+ &:first-child {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-right-width: 0px; // No right border for the first button when not selected
+ }
+
+ &:last-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left-width: 1px; // Ensure left border for the last button
+ }
+
+ // Override Ant Design's default hover and focus styles for a cleaner look
+ &:hover,
+ &:focus {
+ z-index: 1;
+ border-color: ${(props) => (props.selected ? 'var(--ant-primary-color)' : 'var(--ant-primary-color-hover)')};
+ box-shadow: ${(props) =>
+ props.selected ? '0 0 0 2px var(--ant-primary-color-outline)' : '0 0 0 2px var(--ant-primary-color-outline)'};
+ }
+`
+
+const AssistantItem = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ height: 28px;
+`
+
+const AssistantName = styled.span`
+ max-width: calc(100% - 60px);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+`
+
+const Spacer = styled.div`
+ flex: 1;
+`
+
+const DefaultTag = styled.span<{ isCurrent: boolean }>`
+ color: ${(props) => (props.isCurrent ? 'var(--color-primary)' : 'var(--color-text-3)')};
+ font-size: 12px;
+ padding: 2px 4px;
+ border-radius: 4px;
+`
+
export default ModelSettings
diff --git a/src/renderer/src/store/llm.ts b/src/renderer/src/store/llm.ts
index 8b3e5ed053..26611a6d2f 100644
--- a/src/renderer/src/store/llm.ts
+++ b/src/renderer/src/store/llm.ts
@@ -21,7 +21,7 @@ export interface LlmState {
defaultModel: Model
topicNamingModel: Model
translateModel: Model
- quickAssistantModel: Model
+ quickAssistantId: string | null
settings: LlmSettings
}
@@ -514,7 +514,7 @@ const initialState: LlmState = {
defaultModel: SYSTEM_MODELS.defaultModel[0],
topicNamingModel: SYSTEM_MODELS.defaultModel[1],
translateModel: SYSTEM_MODELS.defaultModel[2],
- quickAssistantModel: SYSTEM_MODELS.defaultModel[3],
+ quickAssistantId: null,
providers: INITIAL_PROVIDERS,
settings: {
ollama: {
@@ -621,8 +621,9 @@ const llmSlice = createSlice({
setTranslateModel: (state, action: PayloadAction<{ model: Model }>) => {
state.translateModel = action.payload.model
},
- setQuickAssistantModel: (state, action: PayloadAction<{ model: Model }>) => {
- state.quickAssistantModel = action.payload.model
+
+ setQuickAssistantId: (state, action: PayloadAction) => {
+ state.quickAssistantId = action.payload
},
setOllamaKeepAliveTime: (state, action: PayloadAction) => {
state.settings.ollama.keepAliveTime = action.payload
@@ -661,7 +662,7 @@ export const {
setDefaultModel,
setTopicNamingModel,
setTranslateModel,
- setQuickAssistantModel,
+ setQuickAssistantId,
setOllamaKeepAliveTime,
setLMStudioKeepAliveTime,
setGPUStackKeepAliveTime,
diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts
index 3cc36c7d99..f64bd30c5e 100644
--- a/src/renderer/src/store/migrate.ts
+++ b/src/renderer/src/store/migrate.ts
@@ -1462,8 +1462,6 @@ const migrateConfig = {
searchMessageShortcut.shortcut = [isMac ? 'Command' : 'Ctrl', 'Shift', 'F']
}
}
- // Quick assistant model
- state.llm.quickAssistantModel = state.llm.defaultModel || SYSTEM_MODELS.silicon[1]
return state
} catch (error) {
return state
diff --git a/src/renderer/src/windows/mini/chat/ChatWindow.tsx b/src/renderer/src/windows/mini/chat/ChatWindow.tsx
index 2156d405b5..d59169ba6f 100644
--- a/src/renderer/src/windows/mini/chat/ChatWindow.tsx
+++ b/src/renderer/src/windows/mini/chat/ChatWindow.tsx
@@ -1,5 +1,4 @@
import Scrollbar from '@renderer/components/Scrollbar'
-import { getDefaultModel } from '@renderer/services/AssistantService'
import { Assistant } from '@renderer/types'
import { FC } from 'react'
import styled from 'styled-components'
@@ -11,11 +10,9 @@ interface Props {
}
const ChatWindow: FC = ({ route, assistant }) => {
- // const { defaultAssistant } = useDefaultAssistant()
-
return (
-
+
)
}
diff --git a/src/renderer/src/windows/mini/home/HomeWindow.tsx b/src/renderer/src/windows/mini/home/HomeWindow.tsx
index 1b1b7b6db1..7ea0fd6959 100644
--- a/src/renderer/src/windows/mini/home/HomeWindow.tsx
+++ b/src/renderer/src/windows/mini/home/HomeWindow.tsx
@@ -4,13 +4,13 @@ import { useDefaultAssistant, useDefaultModel } from '@renderer/hooks/useAssista
import { useSettings } from '@renderer/hooks/useSettings'
import i18n from '@renderer/i18n'
import { fetchChatCompletion } from '@renderer/services/ApiService'
-import { getDefaultAssistant, getDefaultModel } from '@renderer/services/AssistantService'
+import { getAssistantById } from '@renderer/services/AssistantService'
import { getAssistantMessage, getUserMessage } from '@renderer/services/MessagesService'
-import store from '@renderer/store'
+import store, { useAppSelector } from '@renderer/store'
import { upsertManyBlocks } from '@renderer/store/messageBlock'
import { updateOneBlock, upsertOneBlock } from '@renderer/store/messageBlock'
import { newMessagesActions } from '@renderer/store/newMessage'
-import { ThemeMode } from '@renderer/types'
+import { Assistant, ThemeMode } from '@renderer/types'
import { Chunk, ChunkType } from '@renderer/types/chunk'
import { AssistantMessageStatus } from '@renderer/types/newMessage'
import { MessageBlockStatus } from '@renderer/types/newMessage'
@@ -37,14 +37,14 @@ const HomeWindow: FC = () => {
const [isFirstMessage, setIsFirstMessage] = useState(true)
const [clipboardText, setClipboardText] = useState('')
const [selectedText, setSelectedText] = useState('')
+ const [currentAssistant, setCurrentAssistant] = useState({} as Assistant)
const [text, setText] = useState('')
const [lastClipboardText, setLastClipboardText] = useState(null)
const textChange = useState(() => {})[1]
const { defaultAssistant } = useDefaultAssistant()
const topic = defaultAssistant.topics[0]
- const { defaultModel, quickAssistantModel } = useDefaultModel()
- // 如果 quickAssistantModel 未設定,則使用 defaultModel
- const model = quickAssistantModel || defaultModel
+ const { defaultModel } = useDefaultModel()
+ const model = currentAssistant.model || defaultModel
const { language, readClipboardAtStartup, windowStyle } = useSettings()
const { theme } = useTheme()
const { t } = useTranslation()
@@ -54,6 +54,8 @@ const HomeWindow: FC = () => {
const content = isFirstMessage ? (referenceText === text ? text : `${referenceText}\n\n${text}`).trim() : text.trim()
+ const { quickAssistantId } = useAppSelector((state) => state.llm)
+
const readClipboard = useCallback(async () => {
if (!readClipboardAtStartup) return
@@ -158,16 +160,36 @@ const HomeWindow: FC = () => {
setText(e.target.value)
}
+ useEffect(() => {
+ const defaultCurrentAssistant = {
+ ...defaultAssistant,
+ model: defaultModel
+ }
+
+ if (quickAssistantId) {
+ // 獲取指定助手,如果不存在則使用默認助手
+ const assistantFromId = getAssistantById(quickAssistantId)
+ const currentAssistant = assistantFromId || defaultCurrentAssistant
+ // 如果助手本身沒有設定模型,則使用預設模型
+ if (!currentAssistant.model) {
+ currentAssistant.model = defaultModel
+ }
+ setCurrentAssistant(currentAssistant)
+ } else {
+ setCurrentAssistant(defaultCurrentAssistant)
+ }
+ }, [quickAssistantId, defaultAssistant, defaultModel])
+
const onSendMessage = useCallback(
async (prompt?: string) => {
if (isEmpty(content)) {
return
}
-
+ const topic = currentAssistant.topics[0]
const messageParams = {
role: 'user',
- content: prompt ? `${prompt}\n\n${content}` : content,
- assistant: defaultAssistant,
+ content: [prompt, content].filter(Boolean).join('\n\n'),
+ assistant: currentAssistant,
topic,
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),
status: 'success'
@@ -178,7 +200,7 @@ const HomeWindow: FC = () => {
store.dispatch(newMessagesActions.addMessage({ topicId, message: userMessage }))
store.dispatch(upsertManyBlocks(blocks))
- const assistant = getDefaultAssistant()
+ const assistant = currentAssistant
let blockId: string | null = null
let blockContent: string = ''
@@ -187,7 +209,7 @@ const HomeWindow: FC = () => {
fetchChatCompletion({
messages: [userMessage],
- assistant: { ...assistant, model: quickAssistantModel || getDefaultModel(), settings: { streamOutput: true } },
+ assistant: { ...assistant, settings: { streamOutput: true } },
onChunkReceived: (chunk: Chunk) => {
if (chunk.type === ChunkType.TEXT_DELTA) {
blockContent += chunk.text
@@ -224,7 +246,7 @@ const HomeWindow: FC = () => {
setIsFirstMessage(false)
setText('') // ✅ 清除输入框内容
},
- [content, defaultAssistant, topic, quickAssistantModel]
+ [content, currentAssistant, topic]
)
const clearClipboard = () => {
@@ -277,7 +299,11 @@ const HomeWindow: FC = () => {
text={text}
model={model}
referenceText={referenceText}
- placeholder={t('miniwindow.input.placeholder.empty', { model: model.name })}
+ placeholder={
+ quickAssistantId
+ ? t('miniwindow.input.placeholder.empty', { model: currentAssistant.name })
+ : t('miniwindow.input.placeholder.empty', { model: model.name })
+ }
handleKeyDown={handleKeyDown}
handleChange={handleChange}
ref={inputBarRef}
@@ -290,7 +316,7 @@ const HomeWindow: FC = () => {
)}
-
+