feat: add send message button
This commit is contained in:
parent
cb0b9de1e9
commit
62b0908dfa
@ -45,7 +45,7 @@
|
|||||||
--topic-list-width: 260px;
|
--topic-list-width: 260px;
|
||||||
--settings-width: var(--assistants-width);
|
--settings-width: var(--assistants-width);
|
||||||
--status-bar-height: 40px;
|
--status-bar-height: 40px;
|
||||||
--input-bar-height: 125px;
|
--input-bar-height: 135px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme-mode='light'] {
|
body[theme-mode='light'] {
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import {
|
|||||||
FullscreenExitOutlined,
|
FullscreenExitOutlined,
|
||||||
FullscreenOutlined,
|
FullscreenOutlined,
|
||||||
HistoryOutlined,
|
HistoryOutlined,
|
||||||
MoreOutlined,
|
|
||||||
PauseCircleOutlined,
|
PauseCircleOutlined,
|
||||||
PlusCircleOutlined
|
PlusCircleOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
|
import { DEFAULT_CONEXTCOUNT } from '@renderer/config/constant'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { getDefaultTopic } from '@renderer/services/assistant'
|
import { getDefaultTopic } from '@renderer/services/assistant'
|
||||||
@ -23,8 +23,7 @@ import { debounce, isEmpty } from 'lodash'
|
|||||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import SendMessageSetting from './SendMessageSetting'
|
import SendMessageButton from './SendMessageButton'
|
||||||
import { DEFAULT_CONEXTCOUNT } from '@renderer/config/constant'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
assistant: Assistant
|
assistant: Assistant
|
||||||
@ -63,11 +62,25 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE, message)
|
EventEmitter.emit(EVENT_NAMES.SEND_MESSAGE, message)
|
||||||
|
|
||||||
setText('')
|
setText('')
|
||||||
|
|
||||||
|
setExpend(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputTokenCount = useMemo(() => estimateInputTokenCount(text), [text])
|
const inputTokenCount = useMemo(() => estimateInputTokenCount(text), [text])
|
||||||
|
|
||||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||||
|
if (expended) {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
setExpend(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (event.key === 'Enter' && event.shiftKey) {
|
||||||
|
sendMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (sendMessageShortcut === 'Enter' && event.key === 'Enter') {
|
if (sendMessageShortcut === 'Enter' && event.key === 'Enter') {
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
return
|
return
|
||||||
@ -127,7 +140,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
}, [assistant])
|
}, [assistant])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container id="inputbar" style={{ minHeight: expended ? '35%' : 'var(--input-bar-height)' }}>
|
<Container id="inputbar" style={{ minHeight: expended ? '100%' : 'var(--input-bar-height)' }}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
<Tooltip placement="top" title={t('assistant.input.new_chat')} arrow>
|
<Tooltip placement="top" title={t('assistant.input.new_chat')} arrow>
|
||||||
@ -158,11 +171,6 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
<ControlOutlined />
|
<ControlOutlined />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip placement="top" title={expended ? t('assistant.input.collapse') : t('assistant.input.expand')} arrow>
|
|
||||||
<ToolbarButton type="text" onClick={() => setExpend(!expended)}>
|
|
||||||
{expended ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
|
||||||
</ToolbarButton>
|
|
||||||
</Tooltip>
|
|
||||||
</ToolbarMenu>
|
</ToolbarMenu>
|
||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
{generating && (
|
{generating && (
|
||||||
@ -172,11 +180,11 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<SendMessageSetting>
|
<Tooltip placement="top" title={expended ? t('assistant.input.collapse') : t('assistant.input.expand')} arrow>
|
||||||
<ToolbarButton type="text" style={{ marginRight: 0 }}>
|
<ToolbarButton type="text" onClick={() => setExpend(!expended)}>
|
||||||
<MoreOutlined />
|
{expended ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</SendMessageSetting>
|
</Tooltip>
|
||||||
</ToolbarMenu>
|
</ToolbarMenu>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<Textarea
|
<Textarea
|
||||||
@ -187,16 +195,18 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
contextMenu="true"
|
contextMenu="true"
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
showCount
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
styles={{ textarea: { paddingLeft: 0 } }}
|
styles={{ textarea: { paddingLeft: 0 } }}
|
||||||
/>
|
/>
|
||||||
|
<Footer>
|
||||||
{showInputEstimatedTokens && (
|
{showInputEstimatedTokens && (
|
||||||
<TextCount>
|
<TextCount>
|
||||||
<HistoryOutlined /> {assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT} | T↑
|
<HistoryOutlined /> {assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT} | T↑
|
||||||
{`${inputTokenCount}/${estimateTokenCount}`}
|
{`${inputTokenCount}/${estimateTokenCount}`}
|
||||||
</TextCount>
|
</TextCount>
|
||||||
)}
|
)}
|
||||||
|
<SendMessageButton sendMessage={sendMessage} />
|
||||||
|
</Footer>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -225,6 +235,7 @@ const Toolbar = styled.div`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 0 -5px;
|
margin: 0 -5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
margin-right: -8px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ToolbarMenu = styled.div`
|
const ToolbarMenu = styled.div`
|
||||||
@ -253,17 +264,22 @@ const ToolbarButton = styled(Button)`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const Footer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
`
|
||||||
|
|
||||||
const TextCount = styled.div`
|
const TextCount = styled.div`
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--color-text-3);
|
color: var(--color-text-3);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background-color: var(--color-background-soft);
|
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-top-left-radius: 7px;
|
border-top-left-radius: 7px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
margin-right: 10px;
|
||||||
`
|
`
|
||||||
|
|
||||||
export default Inputbar
|
export default Inputbar
|
||||||
|
|||||||
@ -129,8 +129,6 @@ const Container = styled.div`
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
max-height: calc(100vh - var(--input-bar-height) - var(--navbar-height));
|
max-height: calc(100vh - var(--input-bar-height) - var(--navbar-height));
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
.message:first-child {
|
.message:first-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { Dropdown, MenuProps } from 'antd'
|
import { Dropdown, MenuProps } from 'antd'
|
||||||
import { FC, PropsWithChildren } from 'react'
|
import { FC } from 'react'
|
||||||
import { ArrowUpOutlined, EnterOutlined } from '@ant-design/icons'
|
import { ArrowUpOutlined, EnterOutlined } from '@ant-design/icons'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { DownOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
interface Props extends PropsWithChildren {}
|
interface Props {
|
||||||
|
sendMessage: () => void
|
||||||
|
}
|
||||||
|
|
||||||
const SendMessageSetting: FC<Props> = ({ children }) => {
|
const SendMessageButton: FC<Props> = ({ sendMessage }) => {
|
||||||
const { sendMessageShortcut, setSendMessageShortcut } = useSettings()
|
const { sendMessageShortcut, setSendMessageShortcut } = useSettings()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -26,14 +29,15 @@ const SendMessageSetting: FC<Props> = ({ children }) => {
|
|||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown.Button
|
||||||
menu={{ items: sendSettingItems, selectable: true, defaultSelectedKeys: [sendMessageShortcut] }}
|
onClick={sendMessage}
|
||||||
placement="topRight"
|
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
arrow>
|
menu={{ items: sendSettingItems, selectable: true, defaultSelectedKeys: [sendMessageShortcut] }}
|
||||||
{children}
|
icon={<DownOutlined />}
|
||||||
</Dropdown>
|
style={{ width: 'auto' }}>
|
||||||
|
{t('assistant.input.send')}
|
||||||
|
</Dropdown.Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SendMessageSetting
|
export default SendMessageButton
|
||||||
@ -34,7 +34,7 @@ export const ThemeProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.setAttribute('theme-mode', _theme)
|
document.body.setAttribute('theme-mode', _theme)
|
||||||
window.api.setTheme(_theme === ThemeMode.dark ? 'dark' : 'light')
|
window.api?.setTheme(_theme === ThemeMode.dark ? 'dark' : 'light')
|
||||||
}, [_theme])
|
}, [_theme])
|
||||||
|
|
||||||
return <ThemeContext.Provider value={{ theme: _theme, toggleTheme }}>{children}</ThemeContext.Provider>
|
return <ThemeContext.Provider value={{ theme: _theme, toggleTheme }}>{children}</ThemeContext.Provider>
|
||||||
|
|||||||
@ -153,7 +153,7 @@ export default class ProviderSDK {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return response?.questions?.map((q: any) => ({ content: q })) || []
|
return response?.questions?.filter(Boolean)?.map((q: any) => ({ content: q })) || []
|
||||||
}
|
}
|
||||||
|
|
||||||
public async check(): Promise<{ valid: boolean; error: Error | null }> {
|
public async check(): Promise<{ valid: boolean; error: Error | null }> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user