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