feat: merge assistant and topics
This commit is contained in:
parent
44e518ef03
commit
ace0cb7823
Binary file not shown.
|
Before Width: | Height: | Size: 9.1 KiB |
BIN
src/renderer/src/assets/images/models/chatglm.png
Normal file
BIN
src/renderer/src/assets/images/models/chatglm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@ -2,9 +2,10 @@ import { TranslationOutlined } from '@ant-design/icons'
|
||||
import { isMac } from '@renderer/config/constant'
|
||||
import { AppLogo, isLocalAi } from '@renderer/config/env'
|
||||
import useAvatar from '@renderer/hooks/useAvatar'
|
||||
import { useRuntime } from '@renderer/hooks/useStore'
|
||||
import { useRuntime, useShowAssistants } from '@renderer/hooks/useStore'
|
||||
import { Avatar } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import styled from 'styled-components'
|
||||
|
||||
@ -16,11 +17,26 @@ const Sidebar: FC = () => {
|
||||
const { pathname } = useLocation()
|
||||
const avatar = useAvatar()
|
||||
const { minappShow } = useRuntime()
|
||||
const { toggleShowAssistants } = useShowAssistants()
|
||||
const { generating } = useRuntime()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isRoute = (path: string): string => (pathname === path ? 'active' : '')
|
||||
|
||||
const onEditUser = () => {
|
||||
UserPopup.show()
|
||||
const onEditUser = () => UserPopup.show()
|
||||
|
||||
const to = (path: string) => {
|
||||
if (generating) {
|
||||
window.message.warning({ content: t('message.switch.disabled'), key: 'switch-assistant' })
|
||||
return '/'
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
const onToggleShowAssistants = () => {
|
||||
if (pathname === '/') {
|
||||
toggleShowAssistants()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -28,22 +44,22 @@ const Sidebar: FC = () => {
|
||||
<AvatarImg src={avatar || AppLogo} draggable={false} className="nodrag" onClick={onEditUser} />
|
||||
<MainMenus>
|
||||
<Menus>
|
||||
<StyledLink to="/">
|
||||
<StyledLink to={to('/')} onClick={onToggleShowAssistants}>
|
||||
<Icon className={isRoute('/')}>
|
||||
<i className="iconfont icon-chat"></i>
|
||||
</Icon>
|
||||
</StyledLink>
|
||||
<StyledLink to="/agents">
|
||||
<StyledLink to={to('/agents')}>
|
||||
<Icon className={isRoute('/agents')}>
|
||||
<i className="iconfont icon-business-smart-assistant"></i>
|
||||
</Icon>
|
||||
</StyledLink>
|
||||
<StyledLink to="/translate">
|
||||
<StyledLink to={to('/translate')}>
|
||||
<Icon className={isRoute('/translate')}>
|
||||
<TranslationOutlined />
|
||||
</Icon>
|
||||
</StyledLink>
|
||||
<StyledLink to="/apps">
|
||||
<StyledLink to={to('/apps')}>
|
||||
<Icon className={isRoute('/apps')}>
|
||||
<i className="iconfont icon-appstore"></i>
|
||||
</Icon>
|
||||
@ -51,7 +67,7 @@ const Sidebar: FC = () => {
|
||||
</Menus>
|
||||
</MainMenus>
|
||||
<Menus>
|
||||
<StyledLink to={isLocalAi ? '/settings/assistant' : '/settings/provider'}>
|
||||
<StyledLink to={to(isLocalAi ? '/settings/assistant' : '/settings/provider')}>
|
||||
<Icon className={pathname.startsWith('/settings') ? 'active' : ''}>
|
||||
<i className="iconfont icon-setting"></i>
|
||||
</Icon>
|
||||
|
||||
@ -255,46 +255,60 @@ export const SYSTEM_MODELS: Record<string, SystemModel[]> = {
|
||||
}
|
||||
],
|
||||
zhipu: [
|
||||
{
|
||||
id: 'glm-4-0520',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-0520',
|
||||
group: 'GLM',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: 'glm-4',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4',
|
||||
group: 'GLM',
|
||||
group: 'GLM-4',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4-airx',
|
||||
id: 'glm-4-plus',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-AirX',
|
||||
group: 'GLM',
|
||||
name: 'GLM-4-Plus',
|
||||
group: 'GLM-4',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4-air',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-Air',
|
||||
group: 'GLM',
|
||||
group: 'GLM-4',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: 'glm-4-airx',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-AirX',
|
||||
group: 'GLM-4',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4-flash',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-Flash',
|
||||
group: 'GLM-4',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4v',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4V',
|
||||
group: 'GLM',
|
||||
name: 'GLM 4V',
|
||||
group: 'GLM-4v',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4v-plus',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4V-Plus',
|
||||
group: 'GLM-4v',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'glm-4-alltools',
|
||||
provider: 'zhipu',
|
||||
name: 'GLM-4-AllTools',
|
||||
group: 'GLM',
|
||||
group: 'GLM-4-AllTools',
|
||||
enabled: false
|
||||
}
|
||||
],
|
||||
|
||||
@ -2,7 +2,7 @@ import BaicuanAppLogo from '@renderer/assets/images/apps/baixiaoying.webp'
|
||||
import KimiAppLogo from '@renderer/assets/images/apps/kimi.jpg'
|
||||
import YuewenAppLogo from '@renderer/assets/images/apps/yuewen.png'
|
||||
import BaichuanModelLogo from '@renderer/assets/images/models/baichuan.png'
|
||||
import ChatGLMModelLogo from '@renderer/assets/images/models/chatglm.jpeg'
|
||||
import ChatGLMModelLogo from '@renderer/assets/images/models/chatglm.png'
|
||||
import ChatGPTModelLogo from '@renderer/assets/images/models/chatgpt.jpeg'
|
||||
import ClaudeModelLogo from '@renderer/assets/images/models/claude.png'
|
||||
import DeepSeekModelLogo from '@renderer/assets/images/models/deepseek.png'
|
||||
|
||||
@ -1,17 +1,5 @@
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { setShowRightSidebar, toggleRightSidebar, toggleShowAssistants } from '@renderer/store/settings'
|
||||
|
||||
export function useShowRightSidebar() {
|
||||
const showRightSidebar = useAppSelector((state) => state.settings.showRightSidebar)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
rightSidebarShown: showRightSidebar,
|
||||
toggleRightSidebar: () => dispatch(toggleRightSidebar()),
|
||||
showRightSidebar: () => dispatch(setShowRightSidebar(true)),
|
||||
hideRightSidebar: () => dispatch(setShowRightSidebar(false))
|
||||
}
|
||||
}
|
||||
import { toggleShowAssistants } from '@renderer/store/settings'
|
||||
|
||||
export function useShowAssistants() {
|
||||
const showAssistants = useAppSelector((state) => state.settings.showAssistants)
|
||||
|
||||
@ -2,9 +2,12 @@ import { Assistant, Topic } from '@renderer/types'
|
||||
import { find } from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { useAssistant } from './useAssistant'
|
||||
|
||||
let _activeTopic: Topic
|
||||
|
||||
export function useActiveTopic(assistant: Assistant) {
|
||||
export function useActiveTopic(_assistant: Assistant) {
|
||||
const { assistant } = useAssistant(_assistant.id)
|
||||
const [activeTopic, setActiveTopic] = useState(_activeTopic || assistant?.topics[0])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -29,7 +29,8 @@ const resources = {
|
||||
select: 'Select',
|
||||
search: 'Search',
|
||||
default: 'Default',
|
||||
warning: 'Warning'
|
||||
warning: 'Warning',
|
||||
back: 'Back'
|
||||
},
|
||||
button: {
|
||||
add: 'Add',
|
||||
@ -67,7 +68,6 @@ const resources = {
|
||||
'topics.delete.all.title': 'Delete all topics',
|
||||
'topics.delete.all.content': 'Are you sure you want to delete all topics?',
|
||||
'input.new_topic': 'New Topic',
|
||||
'input.topics': ' Topics ',
|
||||
'input.clear': 'Clear',
|
||||
'input.expand': 'Expand',
|
||||
'input.collapse': 'Collapse',
|
||||
@ -267,7 +267,8 @@ const resources = {
|
||||
select: '选择',
|
||||
search: '搜索',
|
||||
default: '默认',
|
||||
warning: '警告'
|
||||
warning: '警告',
|
||||
back: '返回'
|
||||
},
|
||||
button: {
|
||||
add: '添加',
|
||||
@ -305,7 +306,6 @@ const resources = {
|
||||
'topics.delete.all.title': '删除所有话题',
|
||||
'topics.delete.all.content': '确定要删除所有话题吗?',
|
||||
'input.new_topic': '新话题',
|
||||
'input.topics': ' 话题 ',
|
||||
'input.clear': '清除',
|
||||
'input.expand': '展开',
|
||||
'input.collapse': '收起',
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { CopyOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
import { ArrowRightOutlined, CopyOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons'
|
||||
import DragableList from '@renderer/components/DragableList'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingPopup'
|
||||
import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { getDefaultTopic, syncAsistantToAgent } from '@renderer/services/assistant'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Dropdown } from 'antd'
|
||||
import { ItemType } from 'antd/es/menu/interface'
|
||||
@ -14,13 +16,27 @@ import { FC, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Topics from './Topics'
|
||||
|
||||
interface Props {
|
||||
activeAssistant: Assistant
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
showTopics: boolean
|
||||
setShowTopics: (showTopics: boolean) => void
|
||||
onCreateAssistant: () => void
|
||||
}
|
||||
|
||||
const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => {
|
||||
const Assistants: FC<Props> = ({
|
||||
activeAssistant,
|
||||
setActiveAssistant,
|
||||
activeTopic,
|
||||
setActiveTopic,
|
||||
showTopics,
|
||||
setShowTopics,
|
||||
onCreateAssistant
|
||||
}) => {
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
const { updateAssistant } = useAssistant(activeAssistant.id)
|
||||
@ -80,10 +96,23 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
}
|
||||
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
|
||||
setActiveAssistant(assistant)
|
||||
setShowTopics(true)
|
||||
},
|
||||
[generating, setActiveAssistant, t]
|
||||
[generating, setActiveAssistant, setShowTopics, t]
|
||||
)
|
||||
|
||||
if (showTopics) {
|
||||
return (
|
||||
<Container>
|
||||
<NavigtaionHeader onClick={() => setShowTopics(false)}>
|
||||
<ArrowLeftOutlined />
|
||||
{t('common.back')}
|
||||
</NavigtaionHeader>
|
||||
<Topics assistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<DragableList list={assistants} onUpdate={updateAssistants}>
|
||||
@ -93,6 +122,9 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
onClick={() => onSwitchAssistant(assistant)}
|
||||
className={assistant.id === activeAssistant?.id ? 'active' : ''}>
|
||||
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
|
||||
<HStack alignItems="center">
|
||||
<ArrowRightOutlined />
|
||||
</HStack>
|
||||
</AssistantItem>
|
||||
</Dropdown>
|
||||
)}
|
||||
@ -108,26 +140,31 @@ const Container = styled.div`
|
||||
max-width: var(--assistants-width);
|
||||
border-right: 0.5px solid var(--color-border);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
padding: 10px 0;
|
||||
`
|
||||
|
||||
const AssistantItem = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 7px 10px;
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
font-family: Ubuntu;
|
||||
.anticon {
|
||||
display: none;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
.count {
|
||||
display: none;
|
||||
}
|
||||
.anticon {
|
||||
display: block;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
@ -139,6 +176,19 @@ const AssistantItem = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const NavigtaionHeader = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
padding: 0 5px;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-3);
|
||||
margin: 10px;
|
||||
margin-top: 0;
|
||||
`
|
||||
|
||||
const AssistantName = styled.div`
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
|
||||
@ -1,29 +1,35 @@
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Flex } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { FC, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Inputbar from './Inputbar/Inputbar'
|
||||
import Messages from './Messages/Messages'
|
||||
import RightSidebar from './RightSidebar'
|
||||
import Settings from './Settings'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const Chat: FC<Props> = (props) => {
|
||||
const { assistant } = useAssistant(props.assistant.id)
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(assistant)
|
||||
const [showSetting, setShowSetting] = useState(false)
|
||||
|
||||
return (
|
||||
<Container id="chat">
|
||||
<Main vertical flex={1} justify="space-between">
|
||||
<Messages assistant={assistant} topic={activeTopic} />
|
||||
<Inputbar assistant={assistant} setActiveTopic={setActiveTopic} />
|
||||
<Messages assistant={assistant} topic={props.activeTopic} />
|
||||
<Inputbar
|
||||
assistant={assistant}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
showSetting={showSetting}
|
||||
setShowSetting={setShowSetting}
|
||||
/>
|
||||
</Main>
|
||||
<RightSidebar assistant={assistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
{showSetting && <Settings assistant={assistant} />}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
import { NavbarCenter } from '@renderer/components/app/Navbar'
|
||||
import { isMac } from '@renderer/config/constant'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowAssistants } from '@renderer/hooks/useStore'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { removeLeadingEmoji } from '@renderer/utils'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
import { NewButton } from './HomePage'
|
||||
|
||||
interface Props {
|
||||
activeAssistant: Assistant
|
||||
}
|
||||
|
||||
const HomeHeader: FC<Props> = ({ activeAssistant }) => {
|
||||
const { assistant } = useAssistant(activeAssistant.id)
|
||||
const { t } = useTranslation()
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
|
||||
return (
|
||||
<NavbarCenter style={{ paddingLeft: isMac ? 16 : 8 }}>
|
||||
{!showAssistants && (
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginRight: isMac ? 8 : 25 }}>
|
||||
<i className="iconfont icon-showsidebarhoriz" />
|
||||
</NewButton>
|
||||
)}
|
||||
<AssistantName>{removeLeadingEmoji(assistant?.name) || t('chat.default.name')}</AssistantName>
|
||||
<SelectModelButton assistant={assistant} />
|
||||
</NavbarCenter>
|
||||
)
|
||||
}
|
||||
|
||||
const AssistantName = styled.span`
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
font-family: Ubuntu;
|
||||
`
|
||||
|
||||
export default HomeHeader
|
||||
@ -1,30 +1,37 @@
|
||||
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import { isMac, isWindows } from '@renderer/config/constant'
|
||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { useShowAssistants } from '@renderer/hooks/useStore'
|
||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||
import { useTheme } from '@renderer/providers/ThemeProvider'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Switch } from 'antd'
|
||||
import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import AddAssistantPopup from '../../components/Popups/AddAssistantPopup'
|
||||
import Assistants from './Assistants'
|
||||
import Chat from './Chat'
|
||||
import Navigation from './Header'
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
|
||||
let _activeAssistant: Assistant
|
||||
let _showTopics = false
|
||||
|
||||
const HomePage: FC = () => {
|
||||
const { assistants, addAssistant } = useAssistants()
|
||||
const [activeAssistant, setActiveAssistant] = useState(_activeAssistant || assistants[0])
|
||||
const { rightSidebarShown, toggleRightSidebar } = useShowRightSidebar()
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { showAssistants } = useShowAssistants()
|
||||
const { defaultAssistant } = useDefaultAssistant()
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
const [showTopics, setShowTopics] = useState(_showTopics)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(activeAssistant)
|
||||
|
||||
_activeAssistant = activeAssistant
|
||||
_showTopics = showTopics
|
||||
|
||||
const onCreateDefaultAssistant = () => {
|
||||
const assistant = { ...defaultAssistant, id: uuid() }
|
||||
@ -37,20 +44,25 @@ const HomePage: FC = () => {
|
||||
assistant && setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
const onSetActiveTopic = (topic: Topic) => {
|
||||
setActiveTopic(topic)
|
||||
setShowTopics(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Navbar>
|
||||
{showAssistants && (
|
||||
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: '0 8px' }}>
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 8 : 0 }}>
|
||||
<i className="iconfont icon-hidesidebarhoriz" />
|
||||
</NewButton>
|
||||
<NavbarLeft style={{ justifyContent: 'flex-end', borderRight: 'none', padding: '0 8px' }}>
|
||||
<NewButton onClick={onCreateAssistant}>
|
||||
<i className="iconfont icon-a-addchat"></i>
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
<Navigation activeAssistant={activeAssistant} />
|
||||
<NavbarCenter style={{ paddingLeft: isMac ? 16 : 8 }}>
|
||||
<AssistantName>{activeAssistant?.name || t('chat.default.name')}</AssistantName>
|
||||
<SelectModelButton assistant={activeAssistant} />
|
||||
</NavbarCenter>
|
||||
<NavbarRight style={{ justifyContent: 'flex-end', paddingRight: isWindows ? 140 : 12 }}>
|
||||
<ThemeSwitch
|
||||
checkedChildren={<i className="iconfont icon-theme icon-dark1" />}
|
||||
@ -58,9 +70,6 @@ const HomePage: FC = () => {
|
||||
checked={theme === 'dark'}
|
||||
onChange={toggleTheme}
|
||||
/>
|
||||
<NewButton onClick={toggleRightSidebar}>
|
||||
<i className={`iconfont ${rightSidebarShown ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} />
|
||||
</NewButton>
|
||||
</NavbarRight>
|
||||
</Navbar>
|
||||
<ContentContainer>
|
||||
@ -68,10 +77,14 @@ const HomePage: FC = () => {
|
||||
<Assistants
|
||||
activeAssistant={activeAssistant}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
activeTopic={activeTopic}
|
||||
setActiveTopic={setActiveTopic}
|
||||
showTopics={showTopics}
|
||||
setShowTopics={setShowTopics}
|
||||
onCreateAssistant={onCreateDefaultAssistant}
|
||||
/>
|
||||
)}
|
||||
<Chat assistant={activeAssistant} />
|
||||
<Chat assistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={onSetActiveTopic} />
|
||||
</ContentContainer>
|
||||
</Container>
|
||||
)
|
||||
@ -90,6 +103,12 @@ const ContentContainer = styled.div`
|
||||
background-color: var(--color-background);
|
||||
`
|
||||
|
||||
const AssistantName = styled.span`
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
font-family: Ubuntu;
|
||||
`
|
||||
|
||||
export const NewButton = styled.div`
|
||||
-webkit-app-region: none;
|
||||
border-radius: 4px;
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
ControlOutlined,
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
HistoryOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlusCircleOutlined,
|
||||
QuestionCircleOutlined
|
||||
@ -32,11 +31,13 @@ import SendMessageButton from './SendMessageButton'
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
showSetting: boolean
|
||||
setShowSetting: (show: boolean) => void
|
||||
}
|
||||
|
||||
let _text = ''
|
||||
|
||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic, showSetting, setShowSetting }) => {
|
||||
const [text, setText] = useState(_text)
|
||||
const [inputFocus, setInputFocus] = useState(false)
|
||||
const { addTopic } = useAssistant(assistant.id)
|
||||
@ -194,6 +195,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
variant="borderless"
|
||||
rows={1}
|
||||
ref={textareaRef}
|
||||
style={{ fontSize }}
|
||||
styles={{ textarea: TextareaStyle }}
|
||||
onFocus={() => setInputFocus(true)}
|
||||
onBlur={() => setInputFocus(false)}
|
||||
@ -219,13 +221,8 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
</ToolbarButton>
|
||||
</Popconfirm>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.topics')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR)}>
|
||||
<HistoryOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS)}>
|
||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow className={showSetting ? 'active' : ''}>
|
||||
<ToolbarButton type="text" onClick={() => setShowSetting(!showSetting)}>
|
||||
<ControlOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
|
||||
@ -162,7 +162,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
{canRegenerate && (
|
||||
<SelectModelDropdown model={model} onSelect={onRegenerate} placement="topRight">
|
||||
<SelectModelDropdown model={model} onSelect={onRegenerate} placement="topLeft">
|
||||
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
|
||||
<ActionButton>
|
||||
<SyncOutlined />
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Segmented } from 'antd'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import SettingsTab from './SettingsTab'
|
||||
import TopicsTab from './TopicsTab'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const RightSidebar: FC<Props> = (props) => {
|
||||
const [tab, setTab] = useState<'topic' | 'settings'>('topic')
|
||||
const { rightSidebarShown, showRightSidebar, hideRightSidebar } = useShowRightSidebar()
|
||||
const { t } = useTranslation()
|
||||
const isTopicTab = tab === 'topic'
|
||||
const isSettingsTab = tab === 'settings'
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
||||
if (rightSidebarShown && isTopicTab) {
|
||||
return hideRightSidebar()
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
return setTab('topic')
|
||||
}
|
||||
showRightSidebar()
|
||||
setTab('topic')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
|
||||
if (rightSidebarShown && isSettingsTab) {
|
||||
return hideRightSidebar()
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
return setTab('settings')
|
||||
}
|
||||
showRightSidebar()
|
||||
setTab('settings')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => setTab('topic'))
|
||||
]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
}, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar])
|
||||
|
||||
if (!rightSidebarShown) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Segmented
|
||||
value={tab}
|
||||
style={{ borderRadius: 0, padding: '10px', gap: 5, borderBottom: '0.5px solid var(--color-border)' }}
|
||||
options={[
|
||||
{ label: t('common.topics'), value: 'topic', icon: <BarsOutlined /> },
|
||||
{ label: t('settings.title'), value: 'settings', icon: <SettingOutlined /> }
|
||||
]}
|
||||
block
|
||||
onChange={(value) => setTab(value as 'topic' | 'settings')}
|
||||
/>
|
||||
<TabContent>
|
||||
{tab === 'topic' && <TopicsTab {...props} />}
|
||||
{tab === 'settings' && <SettingsTab assistant={props.assistant} />}
|
||||
</TabContent>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: var(--topic-list-width);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
.collapsed {
|
||||
width: 0;
|
||||
border-left: none;
|
||||
}
|
||||
`
|
||||
|
||||
const TabContent = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
`
|
||||
|
||||
export default RightSidebar
|
||||
@ -234,7 +234,13 @@ const Container = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: var(--topic-list-width);
|
||||
max-width: var(--topic-list-width);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
padding: 0 15px;
|
||||
padding-bottom: 20px;
|
||||
overflow-y: auto;
|
||||
`
|
||||
|
||||
const Label = styled.p`
|
||||
@ -18,7 +18,7 @@ interface Props {
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
|
||||
const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
|
||||
const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
|
||||
const { t } = useTranslation()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
@ -136,11 +136,12 @@ const Container = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 10px 10px;
|
||||
overflow-y: scroll;
|
||||
`
|
||||
|
||||
const TopicListItem = styled.div`
|
||||
padding: 7px 10px;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
@ -155,4 +156,4 @@ const TopicListItem = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
export default TopicsTab
|
||||
export default Topics
|
||||
@ -1,5 +1,4 @@
|
||||
import { PlusOutlined } from '@ant-design/icons'
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
|
||||
import { getProviderLogo } from '@renderer/config/provider'
|
||||
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
|
||||
|
||||
@ -2,8 +2,6 @@ import { Divider } from 'antd'
|
||||
import Link from 'antd/es/typography/Link'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import SettingsPage from './SettingsPage'
|
||||
|
||||
export const SettingContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -69,5 +67,3 @@ export const SettingHelpLink = styled(Link)`
|
||||
font-size: 11px;
|
||||
padding: 0 5px;
|
||||
`
|
||||
|
||||
export default SettingsPage
|
||||
|
||||
@ -54,12 +54,7 @@ export default class ProviderSDK {
|
||||
const userMessages = takeRight(messages, contextCount + 1).map((message) => {
|
||||
return {
|
||||
role: message.role,
|
||||
content: message.images
|
||||
? [
|
||||
{ type: 'text', text: message.content },
|
||||
...message.images!.map((image) => ({ type: 'image_url', image_url: image }))
|
||||
]
|
||||
: message.content
|
||||
content: message.content
|
||||
}
|
||||
})
|
||||
|
||||
@ -132,10 +127,22 @@ export default class ProviderSDK {
|
||||
return
|
||||
}
|
||||
|
||||
const _userMessages = takeRight(messages, contextCount + 1).map((message) => {
|
||||
return {
|
||||
role: message.role,
|
||||
content: message.images
|
||||
? [
|
||||
{ type: 'text', text: message.content },
|
||||
...message.images!.map((image) => ({ type: 'image_url', image_url: image }))
|
||||
]
|
||||
: message.content
|
||||
}
|
||||
})
|
||||
|
||||
// @ts-ignore key is not typed
|
||||
const stream = await this.openaiSdk.chat.completions.create({
|
||||
model: model.id,
|
||||
messages: [systemMessage, ...userMessages].filter(Boolean) as ChatCompletionMessageParam[],
|
||||
messages: [systemMessage, ..._userMessages].filter(Boolean) as ChatCompletionMessageParam[],
|
||||
stream: true,
|
||||
temperature: assistant?.settings?.temperature,
|
||||
max_tokens: maxTokens,
|
||||
|
||||
@ -9,7 +9,6 @@ export enum ThemeMode {
|
||||
}
|
||||
|
||||
export interface SettingsState {
|
||||
showRightSidebar: boolean
|
||||
showAssistants: boolean
|
||||
sendMessageShortcut: SendMessageShortcut
|
||||
language: string
|
||||
@ -23,7 +22,6 @@ export interface SettingsState {
|
||||
}
|
||||
|
||||
const initialState: SettingsState = {
|
||||
showRightSidebar: true,
|
||||
showAssistants: true,
|
||||
sendMessageShortcut: 'Enter',
|
||||
language: navigator.language,
|
||||
@ -40,12 +38,6 @@ const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
reducers: {
|
||||
toggleRightSidebar: (state) => {
|
||||
state.showRightSidebar = !state.showRightSidebar
|
||||
},
|
||||
setShowRightSidebar: (state, action: PayloadAction<boolean>) => {
|
||||
state.showRightSidebar = action.payload
|
||||
},
|
||||
toggleShowAssistants: (state) => {
|
||||
state.showAssistants = !state.showAssistants
|
||||
},
|
||||
@ -80,8 +72,6 @@ const settingsSlice = createSlice({
|
||||
})
|
||||
|
||||
export const {
|
||||
setShowRightSidebar,
|
||||
toggleRightSidebar,
|
||||
toggleShowAssistants,
|
||||
setSendMessageShortcut,
|
||||
setLanguage,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user