diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx index 24ffa373..e683c98a 100644 --- a/src/renderer/src/components/app/Sidebar.tsx +++ b/src/renderer/src/components/app/Sidebar.tsx @@ -1,6 +1,5 @@ import { TranslationOutlined } from '@ant-design/icons' import Logo from '@renderer/assets/images/logo.png' -import { isWindows } from '@renderer/config/constant' import useAvatar from '@renderer/hooks/useAvatar' import { FC } from 'react' import { Link, useLocation } from 'react-router-dom' @@ -13,7 +12,7 @@ const Sidebar: FC = () => { const isRoute = (path: string): string => (pathname === path ? 'active' : '') return ( - + diff --git a/src/renderer/src/pages/home/components/Message.tsx b/src/renderer/src/pages/home/components/Message.tsx index 0bf0c77a..44fcb4e6 100644 --- a/src/renderer/src/pages/home/components/Message.tsx +++ b/src/renderer/src/pages/home/components/Message.tsx @@ -14,7 +14,7 @@ import useAvatar from '@renderer/hooks/useAvatar' import { useSettings } from '@renderer/hooks/useSettings' import { useRuntime } from '@renderer/hooks/useStore' import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' -import { Message } from '@renderer/types' +import { Message, Model } from '@renderer/types' import { firstLetter, removeLeadingEmoji } from '@renderer/utils' import { Avatar, Dropdown, Popconfirm, Tooltip } from 'antd' import dayjs from 'dayjs' @@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next' import styled from 'styled-components' import Markdown from './markdown/Markdown' +import SelectModelDropdown from './SelectModelDropdown' interface Props { message: Message @@ -36,7 +37,7 @@ interface Props { const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) => { const avatar = useAvatar() const { t } = useTranslation() - const { assistant } = useAssistant(message.assistantId) + const { assistant, model, setModel } = useAssistant(message.assistantId) const { userName, showMessageDivider, messageFont } = useSettings() const { generating } = useRuntime() const [copied, setCopied] = useState(false) @@ -55,10 +56,14 @@ const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) = const onEdit = useCallback(() => EventEmitter.emit(EVENT_NAMES.EDIT_MESSAGE, message), [message]) - const onRegenerate = useCallback(() => { - onDeleteMessage?.(message) - setTimeout(() => EventEmitter.emit(EVENT_NAMES.REGENERATE_MESSAGE), 100) - }, [message, onDeleteMessage]) + const onRegenerate = useCallback( + (model: Model) => { + setModel(model) + onDeleteMessage?.(message) + setTimeout(() => EventEmitter.emit(EVENT_NAMES.REGENERATE_MESSAGE), 100) + }, + [message, onDeleteMessage, setModel] + ) const getUserName = useCallback(() => { if (message.id === 'assistant') return assistant?.name @@ -144,11 +149,13 @@ const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) = {canRegenerate && ( - - - - - + + + + + + + )} {!isUserMessage && ( diff --git a/src/renderer/src/pages/home/components/NavigationCenter.tsx b/src/renderer/src/pages/home/components/NavigationCenter.tsx index f6a1d6b1..6c9c0216 100644 --- a/src/renderer/src/pages/home/components/NavigationCenter.tsx +++ b/src/renderer/src/pages/home/components/NavigationCenter.tsx @@ -1,19 +1,18 @@ import { CodeSandboxOutlined } from '@ant-design/icons' import { NavbarCenter } from '@renderer/components/app/Navbar' import { isMac } from '@renderer/config/constant' -import { getModelLogo } from '@renderer/config/provider' import { useAssistant } from '@renderer/hooks/useAssistant' -import { useProviders } from '@renderer/hooks/useProvider' import { useShowAssistants } from '@renderer/hooks/useStore' import { Assistant } from '@renderer/types' import { removeLeadingEmoji } from '@renderer/utils' -import { Avatar, Button, Dropdown, MenuProps } from 'antd' -import { first, upperFirst } from 'lodash' +import { Button } from 'antd' +import { upperFirst } from 'lodash' import { FC } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' import { NewButton } from '../HomePage' +import SelectModelDropdown from './SelectModelDropdown' interface Props { activeAssistant: Assistant @@ -22,29 +21,9 @@ interface Props { const NavigationCenter: FC = ({ activeAssistant }) => { const { assistant } = useAssistant(activeAssistant.id) const { model, setModel } = useAssistant(activeAssistant.id) - const { providers } = useProviders() const { t } = useTranslation() const { showAssistants, toggleShowAssistants } = useShowAssistants() - const items: MenuProps['items'] = providers - .filter((p) => p.models.length > 0) - .map((p) => ({ - key: p.id, - label: p.isSystem ? t(`provider.${p.id}`) : p.name, - type: 'group', - children: p.models.map((m) => ({ - key: m?.id, - label: upperFirst(m?.name), - style: m?.id === model?.id ? { color: 'var(--color-primary)' } : undefined, - icon: ( - - {first(m?.name)} - - ), - onClick: () => m && setModel(m) - })) - })) - return ( {!showAssistants && ( @@ -53,27 +32,20 @@ const NavigationCenter: FC = ({ activeAssistant }) => { )} {removeLeadingEmoji(assistant?.name) || t('assistant.default.name')} - + {model ? upperFirst(model.name) : t('button.select_model')} - + ) } -const DropdownMenu = styled(Dropdown)` - -webkit-app-region: none; - margin-left: 10px; -` - const AssistantName = styled.span` font-weight: bold; margin-left: 5px; + margin-right: 10px; ` const DropdownButton = styled(Button)` diff --git a/src/renderer/src/pages/home/components/SelectModelDropdown.tsx b/src/renderer/src/pages/home/components/SelectModelDropdown.tsx new file mode 100644 index 00000000..00043ec6 --- /dev/null +++ b/src/renderer/src/pages/home/components/SelectModelDropdown.tsx @@ -0,0 +1,55 @@ +import { getModelLogo } from '@renderer/config/provider' +import { useProviders } from '@renderer/hooks/useProvider' +import { Model } from '@renderer/types' +import { Avatar, Dropdown, DropdownProps, MenuProps } from 'antd' +import { first, upperFirst } from 'lodash' +import { FC, PropsWithChildren } from 'react' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' + +interface Props extends DropdownProps { + model: Model + onSelect: (model: Model) => void +} + +const SelectModelDropdown: FC = ({ children, model, onSelect, ...props }) => { + const { t } = useTranslation() + const { providers } = useProviders() + + const items: MenuProps['items'] = providers + .filter((p) => p.models.length > 0) + .map((p) => ({ + key: p.id, + label: p.isSystem ? t(`provider.${p.id}`) : p.name, + type: 'group', + children: p.models.map((m) => ({ + key: m?.id, + label: upperFirst(m?.name), + style: m?.id === model?.id ? { color: 'var(--color-primary)' } : undefined, + icon: ( + + {first(m?.name)} + + ), + onClick: () => m && onSelect(m) + })) + })) + + return ( + + {children} + + ) +} + +const DropdownMenu = styled(Dropdown)` + -webkit-app-region: none; +` + +export default SelectModelDropdown