feat: add send message button

This commit is contained in:
kangfenmao 2024-07-31 13:03:05 +08:00
parent cb0b9de1e9
commit 62b0908dfa
6 changed files with 57 additions and 39 deletions

View File

@ -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'] {

View File

@ -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 } }}
/> />
{showInputEstimatedTokens && ( <Footer>
<TextCount> {showInputEstimatedTokens && (
<HistoryOutlined /> {assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT} | T <TextCount>
{`${inputTokenCount}/${estimateTokenCount}`} <HistoryOutlined /> {assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT} | T
</TextCount> {`${inputTokenCount}/${estimateTokenCount}`}
)} </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

View File

@ -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;
} }

View File

@ -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

View File

@ -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>

View File

@ -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 }> {