diff --git a/package.json b/package.json index a0fda671..cd16dd77 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lodash": "^4.17.21", "numeral": "^2.0.6", "query-string": "^9.0.0", + "react-hotkeys-hook": "^4.5.0", "umi-presets-pro": "^2.0.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a15ff623..3ca35041 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ dependencies: query-string: specifier: ^9.0.0 version: 9.0.0 + react-hotkeys-hook: + specifier: ^4.5.0 + version: 4.5.0(react-dom@18.3.1)(react@18.3.1) umi-presets-pro: specifier: ^2.0.3 version: 2.0.3(@babel/core@7.24.5)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.17.0)(dva@2.5.0-beta.2)(rc-field-form@1.44.0)(react-dom@18.3.1)(react@18.3.1)(umi@4.2.1) @@ -14203,6 +14206,16 @@ packages: shallowequal: 1.1.0 dev: false + /react-hotkeys-hook@4.5.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==, tarball: https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz} + peerDependencies: + react: '>=16.8.1' + react-dom: '>=16.8.1' + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /react-intl@3.12.1(react@18.3.1): resolution: {integrity: sha512-cgumW29mwROIqyp8NXStYsoIm27+8FqnxykiLSawWjOxGIBeLuN/+p2srei5SRIumcJefOkOIHP+NDck05RgHg==} peerDependencies: diff --git a/src/assets/styles/common.less b/src/assets/styles/common.less index e9eae4e2..cd5b0e64 100644 --- a/src/assets/styles/common.less +++ b/src/assets/styles/common.less @@ -27,3 +27,11 @@ display: flex; align-items: center; } + +.opct-7 { + opacity: 0.7; +} + +.opct-8 { + opacity: 0.8; +} diff --git a/src/config/hotkeys.ts b/src/config/hotkeys.ts index 6027ed38..82620bb9 100644 --- a/src/config/hotkeys.ts +++ b/src/config/hotkeys.ts @@ -1,13 +1,14 @@ export default { - Create: ['ctrl+n', 'cmd+n'], - Save: ['ctrl+s', 'cmd+s'], - SaveAs: ['ctrl+shift+s', 'cmd+shift+s'], - Open: ['ctrl+o', 'cmd+o'], - Cancel: ['ctrl+w', 'cmd+w'], - Delete: ['delete'], - Copy: ['ctrl+c', 'cmd+c'], - Refresh: ['ctrl+r', 'cmd+r'], - Edit: ['ctrl+e', 'cmd+e'], - Search: ['ctrl+f', 'cmd+f'], - Reset: ['ctrl+shift+r', 'cmd+shift+r'] + CREATE: ['ctrl+n', 'meta+n'], + SAVE: ['ctrl+s', 'meta+s'], + SUBMIT: ['ctrl+enter', 'meta+enter'], + SAVEAS: ['ctrl+shift+s', 'meta+shift+s'], + OPEN: ['ctrl+o', 'meta+o'], + CANCEL: ['ctrl+w', 'meta+w'], + DELETE: ['delete'], + COPY: ['ctrl+c', 'meta+c'], + REFRESH: ['ctrl+r', 'meta+r'], + EDIT: ['ctrl+e', 'meta+e'], + SEARCH: ['ctrl+f', 'meta+f'], + RESET: ['ctrl+shift+r', 'meta+shift+r'] }; diff --git a/src/pages/llmodels/config/types.ts b/src/pages/llmodels/config/types.ts index 2a08f539..6f01c90b 100644 --- a/src/pages/llmodels/config/types.ts +++ b/src/pages/llmodels/config/types.ts @@ -26,8 +26,8 @@ export interface ModelInstanceListItem { huggingface_repo_id: string; huggingface_filename: string; s3_address: string; - node_id: number; - node_ip: string; + worker_id: number; + worker_ip: string; pid: number; port: number; state: string; diff --git a/src/pages/llmodels/index.tsx b/src/pages/llmodels/index.tsx index 7c461681..d7d1fa86 100644 --- a/src/pages/llmodels/index.tsx +++ b/src/pages/llmodels/index.tsx @@ -338,7 +338,7 @@ const Models: React.FC = () => { - {item.node_ip}:{item.port} + {item.worker_ip}:{item.port} {item.huggingface_filename} diff --git a/src/pages/playground/components/chat-footer.tsx b/src/pages/playground/components/chat-footer.tsx index 550891d7..fa3cf394 100644 --- a/src/pages/playground/components/chat-footer.tsx +++ b/src/pages/playground/components/chat-footer.tsx @@ -1,11 +1,14 @@ +import HotKeys from '@/config/hotkeys'; import { CodeOutlined, DeleteOutlined, - PlusOutlined, - SaveOutlined + EnterOutlined, + MacCommandOutlined, + PlusOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Button, Col, Row, Space } from 'antd'; +import { useHotkeys } from 'react-hotkeys-hook'; import '../style/chat-footer.less'; interface ChatFooterProps { @@ -20,6 +23,14 @@ interface ChatFooterProps { const ChatFooter: React.FC = (props) => { const intl = useIntl(); const { onSubmit, onClear, onNewMessage, onView, feedback, disabled } = props; + useHotkeys( + HotKeys.SUBMIT.join(','), + () => { + onSubmit(); + }, + { enabled: !disabled } + ); + return (
@@ -52,13 +63,11 @@ const ChatFooter: React.FC = (props) => { > {intl.formatMessage({ id: 'playground.viewcode' })} - diff --git a/src/pages/playground/components/ground-left.tsx b/src/pages/playground/components/ground-left.tsx index c1c49a33..6ecb1a57 100644 --- a/src/pages/playground/components/ground-left.tsx +++ b/src/pages/playground/components/ground-left.tsx @@ -1,10 +1,12 @@ import TransitionWrapper from '@/components/transition'; +import HotKeys from '@/config/hotkeys'; import { EyeInvisibleOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; import { useIntl } from '@umijs/max'; import { Button, Input, Spin } from 'antd'; import _ from 'lodash'; import { useRef, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; import { fetchChatStream, receiveChatStream } from '../apis'; import { Roles } from '../config'; import '../style/ground-left.less'; @@ -13,6 +15,7 @@ import ChatFooter from './chat-footer'; import MessageItem from './message-item'; import ReferenceParams from './reference-params'; import ViewCodeModal from './view-code-modal'; + interface MessageProps { parameters: any; } @@ -40,6 +43,7 @@ const MessageList: React.FC = (props) => { const [loading, setLoading] = useState(false); const [activeIndex, setActiveIndex] = useState(-1); const [tokenResult, setTokenResult] = useState(null); + const [currentIsFocus, setCurrentIsFocus] = useState(false); const systemRef = useRef(null); const contentRef = useRef(''); @@ -153,6 +157,27 @@ const MessageList: React.FC = (props) => {
); }; + + const handleFocus = () => { + setCurrentIsFocus(true); + }; + + const handleBlur = () => { + setCurrentIsFocus(false); + }; + + useHotkeys( + HotKeys.SUBMIT, + () => { + handleSubmit(); + }, + { + enabled: currentIsFocus && !loading, + enableOnFormTags: currentIsFocus && !loading, + preventDefault: true + } + ); + return (
@@ -166,6 +191,8 @@ const MessageList: React.FC = (props) => { value={systemMessage} variant="filled" autoSize={true} + onFocus={handleFocus} + onBlur={handleBlur} placeholder={intl.formatMessage({ id: 'playground.system.tips' })} onChange={handleSystemMessageChange} > @@ -184,6 +211,7 @@ const MessageList: React.FC = (props) => { updateMessage={(message: MessageItemProps) => handleUpdateMessage(index, message) } + onSubmit={handleSubmit} message={item} /> ); diff --git a/src/pages/playground/components/message-item.tsx b/src/pages/playground/components/message-item.tsx index 3a210a77..18aa4483 100644 --- a/src/pages/playground/components/message-item.tsx +++ b/src/pages/playground/components/message-item.tsx @@ -1,7 +1,9 @@ +import HotKeys from '@/config/hotkeys'; import { MinusCircleOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Button, Input } from 'antd'; import { memo, useEffect, useRef, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; import { Roles } from '../config'; import '../style/message-item.less'; interface MessageItemProps { @@ -14,18 +16,32 @@ const MessageItem: React.FC<{ message: MessageItemProps; loading?: boolean; islast?: boolean; + onSubmit: () => void; updateMessage: (message: MessageItemProps) => void; isFocus: boolean; onDelete: () => void; -}> = ({ message, isFocus, onDelete, updateMessage }) => { +}> = ({ message, isFocus, onDelete, updateMessage, onSubmit, loading }) => { const intl = useIntl(); const [roleType, setRoleType] = useState(message.role); const [isTyping, setIsTyping] = useState(false); const [messageContent, setMessageContent] = useState(message.content); const isInitialRender = useRef(true); const [isAnimating, setIsAnimating] = useState(false); + const [currentIsFocus, setCurrentIsFocus] = useState(isFocus); const inputRef = useRef(null); + useHotkeys( + HotKeys.SUBMIT, + () => { + onSubmit(); + }, + { + enabled: currentIsFocus && !loading, + enableOnFormTags: currentIsFocus && !loading, + preventDefault: true + } + ); + useEffect(() => { if (inputRef.current && isFocus) { inputRef.current.focus(); @@ -75,6 +91,11 @@ const MessageItem: React.FC<{ const handleBlur = () => { setIsTyping(true); + setCurrentIsFocus(false); + }; + + const handleFocus = () => { + setCurrentIsFocus(true); }; const handleRoleChange = () => { @@ -103,6 +124,7 @@ const MessageItem: React.FC<{ autoSize={true} variant="filled" onChange={handleMessageChange} + onFocus={handleFocus} onBlur={handleBlur} >
@@ -110,6 +132,7 @@ const MessageItem: React.FC<{