feat: quick regenerate with new model
This commit is contained in:
parent
cbd9f60cfc
commit
de41199f7e
@ -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 (
|
||||
<Container style={isWindows ? { paddingTop: 0 } : {}}>
|
||||
<Container>
|
||||
<StyledLink to="/">
|
||||
<AvatarImg src={avatar || Logo} draggable={false} />
|
||||
</StyledLink>
|
||||
|
||||
@ -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<Props> = ({ 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<Props> = ({ 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<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
{canRegenerate && (
|
||||
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
|
||||
<ActionButton onClick={onRegenerate}>
|
||||
<SyncOutlined />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
<SelectModelDropdown model={model} onSelect={onRegenerate} placement="topRight">
|
||||
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
|
||||
<ActionButton>
|
||||
<SyncOutlined />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
</SelectModelDropdown>
|
||||
)}
|
||||
{!isUserMessage && (
|
||||
<Dropdown menu={{ items: dropdownItems }} trigger={['click']} placement="topRight" arrow>
|
||||
|
||||
@ -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<Props> = ({ 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: (
|
||||
<Avatar src={getModelLogo(m?.id || '')} size={24}>
|
||||
{first(m?.name)}
|
||||
</Avatar>
|
||||
),
|
||||
onClick: () => m && setModel(m)
|
||||
}))
|
||||
}))
|
||||
|
||||
return (
|
||||
<NavbarCenter style={{ paddingLeft: isMac ? 16 : 8 }}>
|
||||
{!showAssistants && (
|
||||
@ -53,27 +32,20 @@ const NavigationCenter: FC<Props> = ({ activeAssistant }) => {
|
||||
</NewButton>
|
||||
)}
|
||||
<AssistantName>{removeLeadingEmoji(assistant?.name) || t('assistant.default.name')}</AssistantName>
|
||||
<DropdownMenu
|
||||
menu={{ items, style: { maxHeight: '80vh', overflow: 'auto' } }}
|
||||
trigger={['click']}
|
||||
overlayClassName="chat-nav-dropdown">
|
||||
<SelectModelDropdown model={model} onSelect={setModel}>
|
||||
<DropdownButton size="small" type="primary" ghost>
|
||||
<CodeSandboxOutlined />
|
||||
<ModelName>{model ? upperFirst(model.name) : t('button.select_model')}</ModelName>
|
||||
</DropdownButton>
|
||||
</DropdownMenu>
|
||||
</SelectModelDropdown>
|
||||
</NavbarCenter>
|
||||
)
|
||||
}
|
||||
|
||||
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)`
|
||||
|
||||
@ -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<Props & PropsWithChildren> = ({ 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: (
|
||||
<Avatar src={getModelLogo(m?.id || '')} size={24}>
|
||||
{first(m?.name)}
|
||||
</Avatar>
|
||||
),
|
||||
onClick: () => m && onSelect(m)
|
||||
}))
|
||||
}))
|
||||
|
||||
return (
|
||||
<DropdownMenu
|
||||
menu={{ items, style: { maxHeight: '80vh', overflow: 'auto' } }}
|
||||
trigger={['click']}
|
||||
arrow
|
||||
placement="bottomCenter"
|
||||
overlayClassName="chat-nav-dropdown"
|
||||
{...props}>
|
||||
{children}
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
const DropdownMenu = styled(Dropdown)`
|
||||
-webkit-app-region: none;
|
||||
`
|
||||
|
||||
export default SelectModelDropdown
|
||||
Loading…
x
Reference in New Issue
Block a user