feat: narrow layout
This commit is contained in:
parent
ea7a42f736
commit
42ede42f62
@ -1,88 +1,91 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'iconfont'; /* Project id 4753420 */
|
font-family: "iconfont"; /* Project id 4753420 */
|
||||||
src: url('iconfont.woff2?t=1733224456443') format('woff2');
|
src: url('iconfont.woff2?t=1736309723926') format('woff2'),
|
||||||
|
url('iconfont.woff?t=1736309723926') format('woff'),
|
||||||
|
url('iconfont.ttf?t=1736309723926') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-family: 'iconfont' !important;
|
font-family: "iconfont" !important;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-at1:before {
|
.icon-at:before {
|
||||||
content: '\e7df';
|
content: "\e623";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-at:before {
|
.icon-icon-adaptive-width:before {
|
||||||
content: '\e630';
|
content: "\e87a";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-a-darkmode:before {
|
.icon-a-darkmode:before {
|
||||||
content: '\e6cd';
|
content: "\e6cd";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-ai-model:before {
|
.icon-ai-model:before {
|
||||||
content: '\e827';
|
content: "\e827";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-ai-model1:before {
|
.icon-ai-model1:before {
|
||||||
content: '\ec09';
|
content: "\ec09";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-gridlines:before {
|
.icon-gridlines:before {
|
||||||
content: '\e942';
|
content: "\e942";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-inbox:before {
|
.icon-inbox:before {
|
||||||
content: '\e869';
|
content: "\e869";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-business-smart-assistant:before {
|
.icon-business-smart-assistant:before {
|
||||||
content: '\e601';
|
content: "\e601";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-copy:before {
|
.icon-copy:before {
|
||||||
content: '\e6ae';
|
content: "\e6ae";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-ic_send:before {
|
.icon-ic_send:before {
|
||||||
content: '\e795';
|
content: "\e795";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-dark1:before {
|
.icon-dark1:before {
|
||||||
content: '\e72f';
|
content: "\e72f";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-theme-light:before {
|
.icon-theme-light:before {
|
||||||
content: '\e6b7';
|
content: "\e6b7";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-translate_line:before {
|
.icon-translate_line:before {
|
||||||
content: '\e7de';
|
content: "\e7de";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-history:before {
|
.icon-history:before {
|
||||||
content: '\e758';
|
content: "\e758";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-hide-sidebar:before {
|
.icon-hide-sidebar:before {
|
||||||
content: '\e8eb';
|
content: "\e8eb";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-show-sidebar:before {
|
.icon-show-sidebar:before {
|
||||||
content: '\e944';
|
content: "\e944";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-appstore:before {
|
.icon-appstore:before {
|
||||||
content: '\e792';
|
content: "\e792";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-chat:before {
|
.icon-chat:before {
|
||||||
content: '\e615';
|
content: "\e615";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-setting:before {
|
.icon-setting:before {
|
||||||
content: '\e78e';
|
content: "\e78e";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -35,6 +35,7 @@ import { CSSProperties, FC, useCallback, useEffect, useMemo, useRef, useState }
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
import NarrowLayout from '../Messages/NarrowLayout'
|
||||||
import AttachmentButton from './AttachmentButton'
|
import AttachmentButton from './AttachmentButton'
|
||||||
import AttachmentPreview from './AttachmentPreview'
|
import AttachmentPreview from './AttachmentPreview'
|
||||||
import KnowledgeBaseButton from './KnowledgeBaseButton'
|
import KnowledgeBaseButton from './KnowledgeBaseButton'
|
||||||
@ -387,114 +388,116 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container onDragOver={handleDragOver} onDrop={handleDrop} className="inputbar">
|
<Container onDragOver={handleDragOver} onDrop={handleDrop} className="inputbar">
|
||||||
<AttachmentPreview files={files} setFiles={setFiles} />
|
<NarrowLayout style={{ width: '100%' }}>
|
||||||
<InputBarContainer
|
<AttachmentPreview files={files} setFiles={setFiles} />
|
||||||
id="inputbar"
|
<InputBarContainer
|
||||||
className={classNames('inputbar-container', inputFocus && 'focus')}
|
id="inputbar"
|
||||||
ref={containerRef}>
|
className={classNames('inputbar-container', inputFocus && 'focus')}
|
||||||
<Textarea
|
ref={containerRef}>
|
||||||
value={text}
|
<Textarea
|
||||||
onChange={(e) => setText(e.target.value)}
|
value={text}
|
||||||
onKeyDown={handleKeyDown}
|
onChange={(e) => setText(e.target.value)}
|
||||||
placeholder={isTranslating ? t('chat.input.translating') : t('chat.input.placeholder')}
|
onKeyDown={handleKeyDown}
|
||||||
autoFocus
|
placeholder={isTranslating ? t('chat.input.translating') : t('chat.input.placeholder')}
|
||||||
contextMenu="true"
|
autoFocus
|
||||||
variant="borderless"
|
contextMenu="true"
|
||||||
spellCheck={false}
|
variant="borderless"
|
||||||
rows={textareaRows}
|
spellCheck={false}
|
||||||
ref={textareaRef}
|
rows={textareaRows}
|
||||||
style={{ fontSize }}
|
ref={textareaRef}
|
||||||
styles={{ textarea: TextareaStyle }}
|
style={{ fontSize }}
|
||||||
onFocus={() => setInputFocus(true)}
|
styles={{ textarea: TextareaStyle }}
|
||||||
onBlur={() => setInputFocus(false)}
|
onFocus={() => setInputFocus(true)}
|
||||||
onInput={onInput}
|
onBlur={() => setInputFocus(false)}
|
||||||
disabled={searching}
|
onInput={onInput}
|
||||||
onPaste={(e) => onPaste(e.nativeEvent)}
|
disabled={searching}
|
||||||
onClick={() => searching && dispatch(setSearching(false))}
|
onPaste={(e) => onPaste(e.nativeEvent)}
|
||||||
/>
|
onClick={() => searching && dispatch(setSearching(false))}
|
||||||
<Toolbar>
|
/>
|
||||||
<ToolbarMenu>
|
<Toolbar>
|
||||||
<Tooltip placement="top" title={t('chat.input.new_topic', { Command: newTopicShortcut })} arrow>
|
<ToolbarMenu>
|
||||||
<ToolbarButton type="text" onClick={addNewTopic}>
|
<Tooltip placement="top" title={t('chat.input.new_topic', { Command: newTopicShortcut })} arrow>
|
||||||
<FormOutlined />
|
<ToolbarButton type="text" onClick={addNewTopic}>
|
||||||
</ToolbarButton>
|
<FormOutlined />
|
||||||
</Tooltip>
|
</ToolbarButton>
|
||||||
{isWebSearchModel(model) && (
|
</Tooltip>
|
||||||
<Tooltip placement="top" title={t('chat.input.web_search')} arrow>
|
{isWebSearchModel(model) && (
|
||||||
|
<Tooltip placement="top" title={t('chat.input.web_search')} arrow>
|
||||||
|
<ToolbarButton
|
||||||
|
type="text"
|
||||||
|
onClick={() => updateAssistant({ ...assistant, enableWebSearch: !assistant.enableWebSearch })}>
|
||||||
|
<GlobalOutlined
|
||||||
|
style={{ color: assistant.enableWebSearch ? 'var(--color-link)' : 'var(--color-icon)' }}
|
||||||
|
/>
|
||||||
|
</ToolbarButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<Tooltip placement="top" title={t('chat.input.clear')} arrow>
|
||||||
|
<Popconfirm
|
||||||
|
title={t('chat.input.clear.content')}
|
||||||
|
placement="top"
|
||||||
|
onConfirm={clearTopic}
|
||||||
|
okButtonProps={{ danger: true }}
|
||||||
|
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
|
||||||
|
okText={t('chat.input.clear')}>
|
||||||
|
<ToolbarButton type="text">
|
||||||
|
<ClearOutlined />
|
||||||
|
</ToolbarButton>
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip placement="top" title={t('chat.input.settings')} arrow>
|
||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
type="text"
|
type="text"
|
||||||
onClick={() => updateAssistant({ ...assistant, enableWebSearch: !assistant.enableWebSearch })}>
|
onClick={() => {
|
||||||
<GlobalOutlined
|
!showTopics && toggleShowTopics()
|
||||||
style={{ color: assistant.enableWebSearch ? 'var(--color-link)' : 'var(--color-icon)' }}
|
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS), 0)
|
||||||
/>
|
}}>
|
||||||
|
<ControlOutlined />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
{showKnowledgeIcon && (
|
||||||
<Tooltip placement="top" title={t('chat.input.clear')} arrow>
|
<KnowledgeBaseButton
|
||||||
<Popconfirm
|
selectedBase={selectedKnowledgeBase}
|
||||||
title={t('chat.input.clear.content')}
|
onSelect={handleKnowledgeBaseSelect}
|
||||||
placement="top"
|
ToolbarButton={ToolbarButton}
|
||||||
onConfirm={clearTopic}
|
disabled={files.length > 0}
|
||||||
okButtonProps={{ danger: true }}
|
/>
|
||||||
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
|
)}
|
||||||
okText={t('chat.input.clear')}>
|
<AttachmentButton model={model} files={files} setFiles={setFiles} ToolbarButton={ToolbarButton} />
|
||||||
<ToolbarButton type="text">
|
<ToolbarButton type="text" onClick={onNewContext}>
|
||||||
<ClearOutlined />
|
<Tooltip placement="top" title={t('chat.input.new.context')}>
|
||||||
</ToolbarButton>
|
<PicCenterOutlined />
|
||||||
</Popconfirm>
|
</Tooltip>
|
||||||
</Tooltip>
|
|
||||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow>
|
|
||||||
<ToolbarButton
|
|
||||||
type="text"
|
|
||||||
onClick={() => {
|
|
||||||
!showTopics && toggleShowTopics()
|
|
||||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS), 0)
|
|
||||||
}}>
|
|
||||||
<ControlOutlined />
|
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
<Tooltip placement="top" title={expended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
|
||||||
{showKnowledgeIcon && (
|
<ToolbarButton type="text" onClick={onToggleExpended}>
|
||||||
<KnowledgeBaseButton
|
{expended ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
||||||
selectedBase={selectedKnowledgeBase}
|
</ToolbarButton>
|
||||||
onSelect={handleKnowledgeBaseSelect}
|
</Tooltip>
|
||||||
|
<TokenCount
|
||||||
|
estimateTokenCount={estimateTokenCount}
|
||||||
|
inputTokenCount={inputTokenCount}
|
||||||
|
contextCount={contextCount}
|
||||||
ToolbarButton={ToolbarButton}
|
ToolbarButton={ToolbarButton}
|
||||||
disabled={files.length > 0}
|
onClick={onNewContext}
|
||||||
/>
|
/>
|
||||||
)}
|
</ToolbarMenu>
|
||||||
<AttachmentButton model={model} files={files} setFiles={setFiles} ToolbarButton={ToolbarButton} />
|
<ToolbarMenu>
|
||||||
<ToolbarButton type="text" onClick={onNewContext}>
|
{!language.startsWith('en') && (
|
||||||
<Tooltip placement="top" title={t('chat.input.new.context')}>
|
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
|
||||||
<PicCenterOutlined />
|
)}
|
||||||
</Tooltip>
|
{generating && (
|
||||||
</ToolbarButton>
|
<Tooltip placement="top" title={t('chat.input.pause')} arrow>
|
||||||
<Tooltip placement="top" title={expended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
|
<ToolbarButton type="text" onClick={onPause} style={{ marginRight: -2, marginTop: 1 }}>
|
||||||
<ToolbarButton type="text" onClick={onToggleExpended}>
|
<PauseCircleOutlined style={{ color: 'var(--color-error)', fontSize: 20 }} />
|
||||||
{expended ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
</ToolbarButton>
|
||||||
</ToolbarButton>
|
</Tooltip>
|
||||||
</Tooltip>
|
)}
|
||||||
<TokenCount
|
{!generating && <SendMessageButton sendMessage={sendMessage} disabled={generating || inputEmpty} />}
|
||||||
estimateTokenCount={estimateTokenCount}
|
</ToolbarMenu>
|
||||||
inputTokenCount={inputTokenCount}
|
</Toolbar>
|
||||||
contextCount={contextCount}
|
</InputBarContainer>
|
||||||
ToolbarButton={ToolbarButton}
|
</NarrowLayout>
|
||||||
onClick={onNewContext}
|
|
||||||
/>
|
|
||||||
</ToolbarMenu>
|
|
||||||
<ToolbarMenu>
|
|
||||||
{!language.startsWith('en') && (
|
|
||||||
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
|
|
||||||
)}
|
|
||||||
{generating && (
|
|
||||||
<Tooltip placement="top" title={t('chat.input.pause')} arrow>
|
|
||||||
<ToolbarButton type="text" onClick={onPause} style={{ marginRight: -2, marginTop: 1 }}>
|
|
||||||
<PauseCircleOutlined style={{ color: 'var(--color-error)', fontSize: 20 }} />
|
|
||||||
</ToolbarButton>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
{!generating && <SendMessageButton sendMessage={sendMessage} disabled={generating || inputEmpty} />}
|
|
||||||
</ToolbarMenu>
|
|
||||||
</Toolbar>
|
|
||||||
</InputBarContainer>
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -224,7 +224,7 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
{canRegenerate && (
|
{canRegenerate && (
|
||||||
<Tooltip title={t('chat.message.regenerate.model')} mouseEnterDelay={0.8}>
|
<Tooltip title={t('chat.message.regenerate.model')} mouseEnterDelay={0.8}>
|
||||||
<ActionButton className="message-action-button" onClick={onAtModelRegenerate}>
|
<ActionButton className="message-action-button" onClick={onAtModelRegenerate}>
|
||||||
<i className="iconfont icon-at1"></i>
|
<i className="iconfont icon-at"></i>
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
@ -335,7 +335,7 @@ const ActionButton = styled.div`
|
|||||||
&:hover {
|
&:hover {
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
.icon-at1 {
|
.icon-at {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import Suggestions from '../components/Suggestions'
|
import Suggestions from '../components/Suggestions'
|
||||||
import MessageItem from './Message'
|
import MessageItem from './Message'
|
||||||
|
import NarrowLayout from './NarrowLayout'
|
||||||
import Prompt from './Prompt'
|
import Prompt from './Prompt'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -283,33 +284,35 @@ const Messages: FC<Props> = ({ assistant, topic, setActiveTopic }) => {
|
|||||||
key={assistant.id}
|
key={assistant.id}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
right={topicPosition === 'left'}>
|
right={topicPosition === 'left'}>
|
||||||
<Suggestions assistant={assistant} messages={messages} />
|
<NarrowLayout style={{ display: 'flex', flexDirection: 'column-reverse' }}>
|
||||||
<InfiniteScroll
|
<Suggestions assistant={assistant} messages={messages} />
|
||||||
dataLength={displayMessages.length}
|
<InfiniteScroll
|
||||||
next={loadMoreMessages}
|
dataLength={displayMessages.length}
|
||||||
hasMore={hasMore}
|
next={loadMoreMessages}
|
||||||
loader={null}
|
hasMore={hasMore}
|
||||||
inverse={true}
|
loader={null}
|
||||||
scrollableTarget="messages">
|
inverse={true}
|
||||||
<ScrollContainer>
|
scrollableTarget="messages">
|
||||||
<LoaderContainer $loading={isLoadingMore}>
|
<ScrollContainer>
|
||||||
<BeatLoader size={8} color="var(--color-text-2)" />
|
<LoaderContainer $loading={isLoadingMore}>
|
||||||
</LoaderContainer>
|
<BeatLoader size={8} color="var(--color-text-2)" />
|
||||||
{displayMessages.map((message, index) => (
|
</LoaderContainer>
|
||||||
<MessageItem
|
{displayMessages.map((message, index) => (
|
||||||
key={message.id}
|
<MessageItem
|
||||||
message={message}
|
key={message.id}
|
||||||
topic={topic}
|
message={message}
|
||||||
index={index}
|
topic={topic}
|
||||||
hidePresetMessages={assistant.settings?.hideMessages}
|
index={index}
|
||||||
onSetMessages={setMessages}
|
hidePresetMessages={assistant.settings?.hideMessages}
|
||||||
onDeleteMessage={onDeleteMessage}
|
onSetMessages={setMessages}
|
||||||
onGetMessages={onGetMessages}
|
onDeleteMessage={onDeleteMessage}
|
||||||
/>
|
onGetMessages={onGetMessages}
|
||||||
))}
|
/>
|
||||||
</ScrollContainer>
|
))}
|
||||||
</InfiniteScroll>
|
</ScrollContainer>
|
||||||
<Prompt assistant={assistant} key={assistant.prompt} />
|
</InfiniteScroll>
|
||||||
|
<Prompt assistant={assistant} key={assistant.prompt} />
|
||||||
|
</NarrowLayout>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/renderer/src/pages/home/Messages/NarrowLayout.tsx
Normal file
24
src/renderer/src/pages/home/Messages/NarrowLayout.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import { FC, HTMLAttributes } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const NarrowLayout: FC<Props> = ({ children, ...props }) => {
|
||||||
|
const { narrowMode } = useSettings()
|
||||||
|
|
||||||
|
if (narrowMode) {
|
||||||
|
return <Container {...props}>{children}</Container>
|
||||||
|
}
|
||||||
|
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default NarrowLayout
|
||||||
@ -28,7 +28,7 @@ const Container = styled.div`
|
|||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
background-color: var(--color-background-soft);
|
background-color: var(--color-background-soft);
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
margin: 0 20px 0 20px;
|
margin: 4px 20px 0 20px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 0.5px solid var(--color-border);
|
border: 0.5px solid var(--color-border);
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import { useShortcut } from '@renderer/hooks/useShortcuts'
|
|||||||
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
|
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
|
||||||
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
|
import { useAppDispatch } from '@renderer/store'
|
||||||
|
import { setNarrowMode } from '@renderer/store/settings'
|
||||||
import { Assistant, Topic } from '@renderer/types'
|
import { Assistant, Topic } from '@renderer/types'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -25,8 +27,9 @@ interface Props {
|
|||||||
const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
||||||
const { assistant } = useAssistant(activeAssistant.id)
|
const { assistant } = useAssistant(activeAssistant.id)
|
||||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||||
const { topicPosition, sidebarIcons } = useSettings()
|
const { topicPosition, sidebarIcons, narrowMode } = useSettings()
|
||||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
useShortcut('toggle_show_assistants', () => {
|
useShortcut('toggle_show_assistants', () => {
|
||||||
toggleShowAssistants()
|
toggleShowAssistants()
|
||||||
@ -75,19 +78,22 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
|||||||
</TitleText>
|
</TitleText>
|
||||||
<SelectModelButton assistant={assistant} />
|
<SelectModelButton assistant={assistant} />
|
||||||
</HStack>
|
</HStack>
|
||||||
<HStack alignItems="center">
|
<HStack alignItems="center" gap={8}>
|
||||||
<NavbarIcon onClick={() => SearchPopup.show()}>
|
<NavbarIcon onClick={() => SearchPopup.show()}>
|
||||||
<SearchOutlined />
|
<SearchOutlined />
|
||||||
</NavbarIcon>
|
</NavbarIcon>
|
||||||
|
<NavbarIcon onClick={() => dispatch(setNarrowMode(!narrowMode))}>
|
||||||
|
<i className="iconfont icon-icon-adaptive-width"></i>
|
||||||
|
</NavbarIcon>
|
||||||
{sidebarIcons.visible.includes('minapp') && (
|
{sidebarIcons.visible.includes('minapp') && (
|
||||||
<AppStorePopover>
|
<AppStorePopover>
|
||||||
<NavbarIcon style={{ marginLeft: isMac ? 5 : 10 }}>
|
<NavbarIcon>
|
||||||
<i className="iconfont icon-appstore" />
|
<i className="iconfont icon-appstore" />
|
||||||
</NavbarIcon>
|
</NavbarIcon>
|
||||||
</AppStorePopover>
|
</AppStorePopover>
|
||||||
)}
|
)}
|
||||||
{topicPosition === 'right' && (
|
{topicPosition === 'right' && (
|
||||||
<NavbarIcon onClick={toggleShowTopics} style={{ marginLeft: isMac ? 5 : 10 }}>
|
<NavbarIcon onClick={toggleShowTopics}>
|
||||||
<i className={`iconfont icon-${showTopics ? 'show' : 'hide'}-sidebar`} />
|
<i className={`iconfont icon-${showTopics ? 'show' : 'hide'}-sidebar`} />
|
||||||
</NavbarIcon>
|
</NavbarIcon>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -133,7 +133,13 @@ export default class OpenAIProvider extends BaseProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isOpenAIo1 = model.id.includes('o1-')
|
const isOpenAIo1 = model.id.includes('o1-')
|
||||||
const isSupportStreamOutput = streamOutput
|
|
||||||
|
const isSupportStreamOutput = () => {
|
||||||
|
if (this.provider.id === 'github' && isOpenAIo1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return streamOutput
|
||||||
|
}
|
||||||
|
|
||||||
let time_first_token_millsec = 0
|
let time_first_token_millsec = 0
|
||||||
const start_time_millsec = new Date().getTime()
|
const start_time_millsec = new Date().getTime()
|
||||||
@ -148,12 +154,12 @@ export default class OpenAIProvider extends BaseProvider {
|
|||||||
top_p: assistant?.settings?.topP,
|
top_p: assistant?.settings?.topP,
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
keep_alive: this.keepAliveTime,
|
keep_alive: this.keepAliveTime,
|
||||||
stream: isSupportStreamOutput,
|
stream: isSupportStreamOutput(),
|
||||||
...(assistant.enableWebSearch ? getWebSearchParams(model) : {}),
|
...(assistant.enableWebSearch ? getWebSearchParams(model) : {}),
|
||||||
...this.getCustomParameters(assistant)
|
...this.getCustomParameters(assistant)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!isSupportStreamOutput) {
|
if (!isSupportStreamOutput()) {
|
||||||
const time_completion_millsec = new Date().getTime() - start_time_millsec
|
const time_completion_millsec = new Date().getTime() - start_time_millsec
|
||||||
return onChunk({
|
return onChunk({
|
||||||
text: stream.choices[0].message?.content || '',
|
text: stream.choices[0].message?.content || '',
|
||||||
|
|||||||
@ -60,6 +60,7 @@ export interface SettingsState {
|
|||||||
visible: SidebarIcon[]
|
visible: SidebarIcon[]
|
||||||
disabled: SidebarIcon[]
|
disabled: SidebarIcon[]
|
||||||
}
|
}
|
||||||
|
narrowMode: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
@ -103,7 +104,8 @@ const initialState: SettingsState = {
|
|||||||
sidebarIcons: {
|
sidebarIcons: {
|
||||||
visible: DEFAULT_SIDEBAR_ICONS,
|
visible: DEFAULT_SIDEBAR_ICONS,
|
||||||
disabled: []
|
disabled: []
|
||||||
}
|
},
|
||||||
|
narrowMode: false
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsSlice = createSlice({
|
const settingsSlice = createSlice({
|
||||||
@ -230,6 +232,9 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setSidebarIcons: (state, action: PayloadAction<{ visible: SidebarIcon[]; disabled: SidebarIcon[] }>) => {
|
setSidebarIcons: (state, action: PayloadAction<{ visible: SidebarIcon[]; disabled: SidebarIcon[] }>) => {
|
||||||
state.sidebarIcons = action.payload
|
state.sidebarIcons = action.payload
|
||||||
|
},
|
||||||
|
setNarrowMode: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.narrowMode = action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -274,7 +279,8 @@ export const {
|
|||||||
setPasteLongTextThreshold,
|
setPasteLongTextThreshold,
|
||||||
setCustomCss,
|
setCustomCss,
|
||||||
setTopicNamingPrompt,
|
setTopicNamingPrompt,
|
||||||
setSidebarIcons
|
setSidebarIcons,
|
||||||
|
setNarrowMode
|
||||||
} = settingsSlice.actions
|
} = settingsSlice.actions
|
||||||
|
|
||||||
export default settingsSlice.reducer
|
export default settingsSlice.reducer
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user