chore: press enter to submit chat message

This commit is contained in:
jialin
2025-03-09 21:31:58 +08:00
parent a2ef9d781d
commit ab6e98aae2
17 changed files with 76 additions and 65 deletions
+1
View File
@@ -75,6 +75,7 @@
} }
.file-name { .file-name {
margin-bottom: 6px;
line-height: 20px; line-height: 20px;
height: 20px; height: 20px;
display: flex; display: flex;
+1 -1
View File
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
// import './iconfont/iconfont.js'; // import './iconfont/iconfont.js';
const IconFont = createFromIconfontCN({ const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4613488_d7ffxju7lc6.js' scriptUrl: '//at.alicdn.com/t/c/font_4613488_yikpvmcl8ag.js'
}); });
export default IconFont; export default IconFont;
+1 -1
View File
@@ -18,7 +18,7 @@
} }
.overlay-canvas:hover { .overlay-canvas:hover {
cursor: 'none !important'; cursor: none !important;
} }
.upload-mask { .upload-mask {
+7 -6
View File
@@ -27,6 +27,7 @@ type Stroke = Point[];
type CanvasImageEditorProps = { type CanvasImageEditorProps = {
ref?: any; ref?: any;
loading: boolean;
imageSrc: string; imageSrc: string;
disabled?: boolean; disabled?: boolean;
imguid: string | number; imguid: string | number;
@@ -48,6 +49,7 @@ const COLOR = 'rgba(0, 0, 255, 0.3)';
const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef( const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
( (
{ {
loading,
imageSrc, imageSrc,
disabled: isDisabled, disabled: isDisabled,
imageStatus, imageStatus,
@@ -597,7 +599,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
canvas!.height = img.height; canvas!.height = img.height;
// fit the image to the container // fit the image to the container
autoScale.current = autoScale.current || 1; autoScale.current = 1;
updateCanvasSize(); updateCanvasSize();
clearCanvas(); clearCanvas();
@@ -735,12 +737,10 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
const mouseX = event.clientX - rect.left; const mouseX = event.clientX - rect.left;
const mouseY = event.clientY - rect.top; const mouseY = event.clientY - rect.top;
setCanvasTransformOrigin(event);
updateZoom(scaleChange, mouseX, mouseY);
overlayCanvasRef.current!.style.transform = `scale(${autoScale.current})`; overlayCanvasRef.current!.style.transform = `scale(${autoScale.current})`;
canvasRef.current!.style.transform = `scale(${autoScale.current})`; canvasRef.current!.style.transform = `scale(${autoScale.current})`;
setCanvasTransformOrigin(event);
updateZoom(scaleChange, mouseX, mouseY);
}; };
const updateCursorPosOnZoom = (e: any) => { const updateCursorPosOnZoom = (e: any) => {
@@ -757,6 +757,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
}; };
const handleFitView = () => { const handleFitView = () => {
resetCanvas();
autoScale.current = baseScale.current; autoScale.current = baseScale.current;
translatePos.current = { x: 0, y: 0 }; translatePos.current = { x: 0, y: 0 };
setTransform(); setTransform();
@@ -908,7 +909,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
onClick={handleFitView} onClick={handleFitView}
size="middle" size="middle"
type="text" type="text"
disabled={isDisabled} disabled={loading}
> >
<ExpandOutlined className="font-size-14" /> <ExpandOutlined className="font-size-14" />
</Button> </Button>
+5 -1
View File
@@ -6,7 +6,11 @@ const KeybindingsMap = {
CLEAR: ['Alt+Ctrl+K', 'Alt+Meta+K'], CLEAR: ['Alt+Ctrl+K', 'Alt+Meta+K'],
RIGHT: ['Ctrl+RIGHT', 'Meta+RIGHT'], RIGHT: ['Ctrl+RIGHT', 'Meta+RIGHT'],
SAVE: ['Ctrl+S', 'Meta+S'], SAVE: ['Ctrl+S', 'Meta+S'],
SUBMIT: ['Ctrl+Enter', 'Meta+Enter'], SUBMIT: ['Enter', 'Enter'],
ENTER: ['Enter', 'Enter'],
SHIFT: ['Shift', 'Shift'],
CTRL: ['Ctrl', 'Meta'],
OPTION: ['Alt', 'Option'],
SAVEAS: ['Alt+Ctrl+S', 'Alt+Meta+S'], SAVEAS: ['Alt+Ctrl+S', 'Alt+Meta+S'],
OPEN: ['Alt+Ctrl+O', 'Alt+Meta+O'], OPEN: ['Alt+Ctrl+O', 'Alt+Meta+O'],
UNDO: ['Ctrl+Z', 'Meta+Z'], UNDO: ['Ctrl+Z', 'Meta+Z'],
+3 -1
View File
@@ -3,7 +3,9 @@ const externalLinks = {
github: 'https://github.com/gpustack/gpustack', github: 'https://github.com/gpustack/gpustack',
discord: 'https://discord.gg/VXYJzuaqwD', discord: 'https://discord.gg/VXYJzuaqwD',
site: 'https://gpustack.ai/', site: 'https://gpustack.ai/',
release: 'https://github.com/gpustack/gpustack/releases' release: 'https://github.com/gpustack/gpustack/releases',
reportIssue: 'https://github.com/gpustack/gpustack/issues/new/choose',
faq: 'https://github.com/gpustack/gpustack/wiki/FAQ'
}; };
export default externalLinks; export default externalLinks;
+9 -2
View File
@@ -1,5 +1,6 @@
// @ts-nocheck // @ts-nocheck
import avatarImg from '@/assets/images/avatar.png'; import avatarImg from '@/assets/images/avatar.png';
import IconFont from '@/components/icon-font';
import externalLinks from '@/constants/external-links'; import externalLinks from '@/constants/external-links';
import langConfigMap from '@/locales/lang-config-map'; import langConfigMap from '@/locales/lang-config-map';
import { import {
@@ -79,8 +80,14 @@ export const getRightRenderContent = (opts: {
{ {
key: 'github', key: 'github',
icon: <GithubOutlined />, icon: <GithubOutlined />,
label: 'GitHub', label: intl.formatMessage({ id: 'common.issue.report' }),
url: externalLinks.github url: externalLinks.reportIssue
},
{
key: 'faq',
icon: <IconFont type="icon-fankuifaqs"></IconFont>,
label: intl.formatMessage({ id: 'common.button.faq' }),
url: externalLinks.faq
}, },
{ {
key: 'Discord', key: 'Discord',
+2 -1
View File
@@ -228,5 +228,6 @@ export default {
'common.options.none': 'None', 'common.options.none': 'None',
'common.options.auto': 'Auto', 'common.options.auto': 'Auto',
'common.search.empty': 'No matching results found.', 'common.search.empty': 'No matching results found.',
'common.button.downloadLog': 'Download Log' 'common.button.downloadLog': 'Download Log',
'common.button.faq': 'FAQ'
}; };
+2 -1
View File
@@ -226,5 +226,6 @@ export default {
'common.options.none': 'Нет', 'common.options.none': 'Нет',
'common.options.auto': 'Авто', 'common.options.auto': 'Авто',
'common.search.empty': 'Ничего не найдено', 'common.search.empty': 'Ничего не найдено',
'common.button.downloadLog': 'Скачать логи' 'common.button.downloadLog': 'Скачать логи',
'common.button.faq': 'TODO: Translate key "common.button.faq"'
}; };
+2 -1
View File
@@ -221,5 +221,6 @@ export default {
'common.options.none': '无', 'common.options.none': '无',
'common.options.auto': '自动', 'common.options.auto': '自动',
'common.search.empty': '未找到匹配结果', 'common.search.empty': '未找到匹配结果',
'common.button.downloadLog': '下载日志' 'common.button.downloadLog': '下载日志',
'common.button.faq': '常见问题'
}; };
@@ -238,7 +238,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
const generateFileNameByTime = (type?: string) => { const generateFileNameByTime = (type?: string) => {
const format = getAudioFormat(type); const format = getAudioFormat(type);
return `recording-${dayjs().format('YYYY-MM-DD-HH_mm_ss')}${format.suffix}`; return `Recording-${dayjs().format('YYYY-MM-DD-HH_mm_ss')}${format.suffix}`;
}; };
// start recording // start recording
const StartRecording = async () => { const StartRecording = async () => {
@@ -3,7 +3,6 @@ import ScatterChart from '@/components/echarts/scatter';
import HighlightCode from '@/components/highlight-code'; import HighlightCode from '@/components/highlight-code';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import SealInputNumber from '@/components/seal-form/input-number'; import SealInputNumber from '@/components/seal-form/input-number';
import HotKeys, { KeyMap } from '@/config/hotkeys';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import useRequestToken from '@/hooks/use-request-token'; import useRequestToken from '@/hooks/use-request-token';
import { import {
@@ -29,7 +28,6 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { EMBEDDING_API, handleEmbedding } from '../apis'; import { EMBEDDING_API, handleEmbedding } from '../apis';
import { LLM_METAKEYS } from '../hooks/config'; import { LLM_METAKEYS } from '../hooks/config';
import { useInitLLmMeta } from '../hooks/use-init-meta'; import { useInitLLmMeta } from '../hooks/use-init-meta';
@@ -447,17 +445,17 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
[] []
); );
useHotkeys( // useHotkeys(
HotKeys.SUBMIT, // HotKeys.SUBMIT,
(e: any) => { // (e: any) => {
e.preventDefault(); // e.preventDefault();
handleSendMessage(); // handleSendMessage();
}, // },
{ // {
enabled: !loading, // enabled: !loading,
preventDefault: true // preventDefault: true
} // }
); // );
useEffect(() => { useEffect(() => {
if (scroller.current) { if (scroller.current) {
@@ -526,7 +524,6 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
<Tooltip <Tooltip
title={ title={
<span> <span>
[{KeyMap.SUBMIT.textKeybinding}]{' '}
{intl.formatMessage({ id: 'common.button.submit' })} {intl.formatMessage({ id: 'common.button.submit' })}
</span> </span>
} }
@@ -1,6 +1,5 @@
import AlertInfo from '@/components/alert-info'; import AlertInfo from '@/components/alert-info';
import SealInputNumber from '@/components/seal-form/input-number'; import SealInputNumber from '@/components/seal-form/input-number';
import HotKeys, { KeyMap } from '@/config/hotkeys';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import useRequestToken from '@/hooks/use-request-token'; import useRequestToken from '@/hooks/use-request-token';
import { import {
@@ -23,7 +22,6 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { rerankerQuery } from '../apis'; import { rerankerQuery } from '../apis';
import { ParamsSchema } from '../config/types'; import { ParamsSchema } from '../config/types';
import { LLM_METAKEYS } from '../hooks/config'; import { LLM_METAKEYS } from '../hooks/config';
@@ -439,17 +437,17 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
} }
}, []); }, []);
useHotkeys( // useHotkeys(
HotKeys.SUBMIT, // HotKeys.SUBMIT,
(e: any) => { // (e: any) => {
e.preventDefault(); // e.preventDefault();
handleSearch(queryValue); // handleSearch(queryValue);
}, // },
{ // {
enabled: !loading, // enabled: !loading,
preventDefault: true // preventDefault: true
} // }
); // );
useEffect(() => { useEffect(() => {
if (scroller.current) { if (scroller.current) {
@@ -483,7 +481,6 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
<Tooltip <Tooltip
title={ title={
<span> <span>
[{KeyMap.SUBMIT.textKeybinding}]{' '}
{intl.formatMessage({ id: 'common.button.submit' })} {intl.formatMessage({ id: 'common.button.submit' })}
</span> </span>
} }
@@ -5,7 +5,6 @@ import SealSelect from '@/components/seal-form/seal-select';
import SpeechContent from '@/components/speech-content'; import SpeechContent from '@/components/speech-content';
import routeCachekey from '@/config/route-cachekey'; import routeCachekey from '@/config/route-cachekey';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { SendOutlined } from '@ant-design/icons';
import { getLocale, useIntl, useSearchParams } from '@umijs/max'; import { getLocale, useIntl, useSearchParams } from '@umijs/max';
import { Form, Spin } from 'antd'; import { Form, Spin } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
@@ -392,7 +391,6 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
onInputChange={handleInputChange} onInputChange={handleInputChange}
clearAll={handleClear} clearAll={handleClear}
shouldResetMessage={false} shouldResetMessage={false}
submitIcon={<SendOutlined></SendOutlined>}
/> />
</div> </div>
</div> </div>
@@ -314,6 +314,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
imguid={activeImgUid} imguid={activeImgUid}
imageStatus={imageStatus} imageStatus={imageStatus}
imageSrc={image} imageSrc={image}
loading={loading}
disabled={loading || !imageStatus.isOriginal} disabled={loading || !imageStatus.isOriginal}
onSave={handleOnSave} onSave={handleOnSave}
clearUploadMask={handleClearUploadMask} clearUploadMask={handleClearUploadMask}
@@ -1,6 +1,6 @@
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import HotKeys, { KeyMap } from '@/config/hotkeys'; import HotKeys, { KeyMap } from '@/config/hotkeys';
import { ClearOutlined, SendOutlined, SwapOutlined } from '@ant-design/icons'; import { ClearOutlined, EnterOutlined, SwapOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Checkbox, Divider, Input, Tooltip } from 'antd'; import { Button, Checkbox, Divider, Input, Tooltip } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
@@ -279,6 +279,16 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
} }
}; };
const handleOnKeydown = (e: any) => {
if (e.key === KeyMap.ENTER.keybinding) {
if (e.shiftKey) {
return;
}
e.preventDefault();
handleSendMessage();
}
};
const handleDeleteLastImage = useCallback(() => { const handleDeleteLastImage = useCallback(() => {
if (message.imgs && message.imgs?.length > 0) { if (message.imgs && message.imgs?.length > 0) {
const newImgList = [...(message.imgs || [])]; const newImgList = [...(message.imgs || [])];
@@ -293,19 +303,6 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
handleInputChange: handleInputChange handleInputChange: handleInputChange
})); }));
useHotkeys(
HotKeys.SUBMIT,
(e: any) => {
console.log('submit message', loading);
e.preventDefault();
handleSendMessage();
},
{
enabled: !loading && !isDisabled,
enableOnFormTags: focused,
preventDefault: true
}
);
useHotkeys( useHotkeys(
HotKeys.ADD, HotKeys.ADD,
(e: any) => { (e: any) => {
@@ -428,7 +425,7 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
disabled={isDisabled} disabled={isDisabled}
> >
{submitIcon ?? ( {submitIcon ?? (
<SendOutlined rotate={0} className="font-size-14" /> <EnterOutlined rotate={0} className="font-size-14" />
)} )}
</Button> </Button>
</Tooltip> </Tooltip>
@@ -461,6 +458,7 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
minRows: defaultSize.minRows, minRows: defaultSize.minRows,
maxRows: defaultSize.maxRows maxRows: defaultSize.maxRows
}} }}
onKeyDown={handleOnKeydown}
onChange={handleInputChange} onChange={handleInputChange}
value={message.content} value={message.content}
size="large" size="large"
@@ -476,6 +474,7 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
minRows: defaultSize.minRows, minRows: defaultSize.minRows,
maxRows: defaultSize.maxRows maxRows: defaultSize.maxRows
}} }}
onKeyDown={handleOnKeydown}
onChange={handleInputChange} onChange={handleInputChange}
value={message.content} value={message.content}
size="large" size="large"
+5 -4
View File
@@ -69,10 +69,11 @@ export const useInitLLmMeta = (
const { initialize: innitializeParams } = useOverlayScroller(); const { initialize: innitializeParams } = useOverlayScroller();
const defaultModel = useMemo(() => { const defaultModel = useMemo(() => {
return ( if (isChat) {
searchParams.get('model') || return searchParams.get('model') || model || modelList?.[0]?.value;
(isChat ? model ?? modelList?.[0]?.value : model) }
); // use for multiple chat
return model;
}, [model, modelList, isChat]); }, [model, modelList, isChat]);
const extractLLMMeta = (meta: any) => { const extractLLMMeta = (meta: any) => {
const towKeys = new Set(precisionTwoKeys); const towKeys = new Set(precisionTwoKeys);