From 752b72e2c974589a0e2567b5c8d269ca174f6140 Mon Sep 17 00:00:00 2001 From: josc146 Date: Fri, 19 May 2023 20:10:30 +0800 Subject: [PATCH] improve chat page --- backend-python/utils/torch.py | 5 +- frontend/src/components/ToolTipButton.tsx | 7 +- frontend/src/pages/Chat.tsx | 250 ++++++++++++---------- 3 files changed, 151 insertions(+), 111 deletions(-) diff --git a/backend-python/utils/torch.py b/backend-python/utils/torch.py index 5b4ee69..426d03a 100644 --- a/backend-python/utils/torch.py +++ b/backend-python/utils/torch.py @@ -10,9 +10,10 @@ def set_torch(): if torch_path in paths: print("torch already set") else: - print("run:") os.environ["PATH"] = paths + os.pathsep + torch_path + os.pathsep - print(f"set Path={paths + os.pathsep + torch_path + os.pathsep}") + print("torch set") + # print("run:") + # print(f"set Path={paths + os.pathsep + torch_path + os.pathsep}") else: print("torch not found") diff --git a/frontend/src/components/ToolTipButton.tsx b/frontend/src/components/ToolTipButton.tsx index ef00322..e1099d5 100644 --- a/frontend/src/components/ToolTipButton.tsx +++ b/frontend/src/components/ToolTipButton.tsx @@ -6,6 +6,8 @@ export const ToolTipButton: FC<{ desc: string, icon?: ReactElement, size?: 'small' | 'medium' | 'large', + shape?: 'rounded' | 'circular' | 'square'; + appearance?: 'secondary' | 'primary' | 'outline' | 'subtle' | 'transparent'; disabled?: boolean, onClick?: MouseEventHandler }> = ({ @@ -13,12 +15,15 @@ export const ToolTipButton: FC<{ desc, icon, size, + shape, + appearance, disabled, onClick }) => { return ( - + ); }; diff --git a/frontend/src/pages/Chat.tsx b/frontend/src/pages/Chat.tsx index 11230f5..bd9c8d4 100644 --- a/frontend/src/pages/Chat.tsx +++ b/frontend/src/pages/Chat.tsx @@ -12,6 +12,8 @@ import {fetchEventSource} from '@microsoft/fetch-event-source'; import {ConversationPair, getConversationPairs, Record} from '../utils/get-conversation-pairs'; import logo from '../../../build/appicon.png'; import MarkdownRender from '../components/MarkdownRender'; +import {ToolTipButton} from '../components/ToolTipButton'; +import {ArrowCircleUp28Regular, Delete28Regular, RecordStop28Regular} from '@fluentui/react-icons'; const userName = 'M E'; const botName = 'A I'; @@ -48,6 +50,16 @@ const ChatPanel: FC = observer(() => { const bodyRef = useRef(null); const inputRef = useRef(null); const port = commonStore.getCurrentModelConfig().apiParameters.apiPort; + const sseControllerRef = useRef(null); + + let lastMessageId: string; + let generating: boolean = false; + if (conversationsOrder.length > 0) { + lastMessageId = conversationsOrder[conversationsOrder.length - 1]; + const lastMessage = conversations[lastMessageId]; + if (lastMessage.sender === botName) + generating = !lastMessage.done; + } useEffect(() => { if (inputRef.current) @@ -59,103 +71,111 @@ const ChatPanel: FC = observer(() => { bodyRef.current.scrollTop = bodyRef.current.scrollHeight; }; - const handleSubmit = (e: React.ChangeEvent) => { - e.preventDefault(); - if (message !== '') { + const handleKeyDownOrClick = (e: any) => { + e.stopPropagation(); + if (e.type === 'click' || (e.keyCode === 13 && !e.shiftKey)) { + e.preventDefault(); + if (!message) return; + onSubmit(message); setMessage(''); - const newId = uuid(); - conversations[newId] = { - sender: userName, - type: MessageType.Normal, - color: 'brand', - time: new Date().toISOString(), - content: message, - side: 'right', - done: true - }; - setConversations(conversations); - conversationsOrder.push(newId); - setConversationsOrder(conversationsOrder); + } + }; - const records: Record[] = []; - conversationsOrder.forEach((uuid, index) => { - const conversation = conversations[uuid]; - if (conversation.done && conversation.type === MessageType.Normal && conversation.sender === botName) { - if (index > 0) { - const questionId = conversationsOrder[index - 1]; - const question = conversations[questionId]; - if (question.done && question.type === MessageType.Normal && question.sender === userName) { - records.push({question: question.content, answer: conversation.content}); - } + const onSubmit = (message: string) => { + const newId = uuid(); + conversations[newId] = { + sender: userName, + type: MessageType.Normal, + color: 'brand', + time: new Date().toISOString(), + content: message, + side: 'right', + done: true + }; + setConversations(conversations); + conversationsOrder.push(newId); + setConversationsOrder(conversationsOrder); + + const records: Record[] = []; + conversationsOrder.forEach((uuid, index) => { + const conversation = conversations[uuid]; + if (conversation.done && conversation.type === MessageType.Normal && conversation.sender === botName) { + if (index > 0) { + const questionId = conversationsOrder[index - 1]; + const question = conversations[questionId]; + if (question.done && question.type === MessageType.Normal && question.sender === userName) { + records.push({question: question.content, answer: conversation.content}); } } - }); - const messages = getConversationPairs(records, false); - (messages as ConversationPair[]).push({role: 'user', content: message}); + } + }); + const messages = getConversationPairs(records, false); + (messages as ConversationPair[]).push({role: 'user', content: message}); - const answerId = uuid(); - conversations[answerId] = { - sender: botName, - type: MessageType.Normal, - color: 'colorful', - avatarImg: logo, - time: new Date().toISOString(), - content: '', - side: 'left', - done: false - }; - setConversations(conversations); - conversationsOrder.push(answerId); - setConversationsOrder(conversationsOrder); - setTimeout(scrollToBottom); - let answer = ''; - fetchEventSource(`http://127.0.0.1:${port}/chat/completions`, // https://api.openai.com/v1/chat/completions || http://127.0.0.1:${port}/chat/completions - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer sk-` - }, - body: JSON.stringify({ - messages, - stream: true, - model: 'gpt-3.5-turbo' - }), - onmessage(e) { - console.log('sse message', e); - scrollToBottom(); - if (e.data === '[DONE]') { - conversations[answerId].done = true; - setConversations(conversations); - setConversationsOrder([...conversationsOrder]); - return; - } - let data; - try { - data = JSON.parse(e.data); - } catch (error) { - console.debug('json error', error); - return; - } - if (data.choices && Array.isArray(data.choices) && data.choices.length > 0) { - answer += data.choices[0]?.delta?.content || ''; - conversations[answerId].content = answer; - setConversations(conversations); - setConversationsOrder([...conversationsOrder]); - } - }, - onclose() { - console.log('Connection closed'); - }, - onerror(err) { - conversations[answerId].type = MessageType.Error; + const answerId = uuid(); + conversations[answerId] = { + sender: botName, + type: MessageType.Normal, + color: 'colorful', + avatarImg: logo, + time: new Date().toISOString(), + content: '', + side: 'left', + done: false + }; + setConversations(conversations); + conversationsOrder.push(answerId); + setConversationsOrder(conversationsOrder); + setTimeout(scrollToBottom); + let answer = ''; + sseControllerRef.current = new AbortController(); + fetchEventSource(`http://127.0.0.1:${port}/chat/completions`, // https://api.openai.com/v1/chat/completions || http://127.0.0.1:${port}/chat/completions + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer sk-` + }, + body: JSON.stringify({ + messages, + stream: true, + model: 'gpt-3.5-turbo' + }), + signal: sseControllerRef.current?.signal, + onmessage(e) { + console.log('sse message', e); + scrollToBottom(); + if (e.data === '[DONE]') { conversations[answerId].done = true; setConversations(conversations); setConversationsOrder([...conversationsOrder]); - throw err; + return; } - }); - } + let data; + try { + data = JSON.parse(e.data); + } catch (error) { + console.debug('json error', error); + return; + } + if (data.choices && Array.isArray(data.choices) && data.choices.length > 0) { + answer += data.choices[0]?.delta?.content || ''; + conversations[answerId].content = answer; + setConversations(conversations); + setConversationsOrder([...conversationsOrder]); + } + }, + onclose() { + console.log('Connection closed'); + }, + onerror(err) { + conversations[answerId].type = MessageType.Error; + conversations[answerId].done = true; + setConversations(conversations); + setConversationsOrder([...conversationsOrder]); + throw err; + } + }); }; return ( @@ -192,26 +212,40 @@ const ChatPanel: FC = observer(() => { ; })} -
- -
-