From ee89e6bb65d03669855c9a48016f43a75359924a Mon Sep 17 00:00:00 2001 From: babaohuang Date: Thu, 14 Dec 2023 21:26:08 +0800 Subject: [PATCH] Update Generator.tsx --- src/components/Generator.tsx | 210 ++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 104 deletions(-) diff --git a/src/components/Generator.tsx b/src/components/Generator.tsx index bd59478d..f8800ee9 100644 --- a/src/components/Generator.tsx +++ b/src/components/Generator.tsx @@ -1,91 +1,91 @@ -import { Index, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js'; -import { useThrottleFn } from 'solidjs-use'; -import { generateSignature } from '@/utils/auth'; -import IconClear from './icons/Clear'; -import MessageItem from './MessageItem'; -import ErrorMessageItem from './ErrorMessageItem'; -import type { ChatMessage, ErrorMessage } from '@/types'; +import { Index, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js' +import { useThrottleFn } from 'solidjs-use' +import { generateSignature } from '@/utils/auth' +import IconClear from './icons/Clear' +import MessageItem from './MessageItem' +import ErrorMessageItem from './ErrorMessageItem' +import type { ChatMessage, ErrorMessage } from '@/types' export default () => { - let inputRef: HTMLTextAreaElement; - const [messageList, setMessageList] = createSignal([]); - const [currentError, setCurrentError] = createSignal(); - const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal(''); - const [loading, setLoading] = createSignal(false); - const [controller, setController] = createSignal(null); - const [isStick, setStick] = createSignal(false); - const maxHistoryMessages = parseInt(import.meta.env.PUBLIC_MAX_HISTORY_MESSAGES || '9'); + let inputRef: HTMLTextAreaElement + const [messageList, setMessageList] = createSignal([]) + const [currentError, setCurrentError] = createSignal() + const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal('') + const [loading, setLoading] = createSignal(false) + const [controller, setController] = createSignal(null) + const [isStick, setStick] = createSignal(false) + const maxHistoryMessages = parseInt(import.meta.env.PUBLIC_MAX_HISTORY_MESSAGES || '9') - createEffect(() => (isStick() && smoothToBottom())); + createEffect(() => (isStick() && smoothToBottom())) onMount(() => { - let lastPostion = window.scrollY; + let lastPostion = window.scrollY window.addEventListener('scroll', () => { - const nowPostion = window.scrollY; - nowPostion < lastPostion && setStick(false); - lastPostion = nowPostion; - }); + const nowPostion = window.scrollY + nowPostion < lastPostion && setStick(false) + lastPostion = nowPostion + }) try { if (sessionStorage.getItem('messageList')) - setMessageList(JSON.parse(sessionStorage.getItem('messageList'))); + setMessageList(JSON.parse(sessionStorage.getItem('messageList'))) if (localStorage.getItem('stickToBottom') === 'stick') - setStick(true); + setStick(true) } catch (err) { - console.error(err); + console.error(err) } - window.addEventListener('beforeunload', handleBeforeUnload); + window.addEventListener('beforeunload', handleBeforeUnload) onCleanup(() => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }); - }); + window.removeEventListener('beforeunload', handleBeforeUnload) + }) + }) const handleBeforeUnload = () => { - sessionStorage.setItem('messageList', JSON.stringify(messageList())); - isStick() ? localStorage.setItem('stickToBottom', 'stick') : localStorage.removeItem('stickToBottom'); - }; + sessionStorage.setItem('messageList', JSON.stringify(messageList())) + isStick() ? localStorage.setItem('stickToBottom', 'stick') : localStorage.removeItem('stickToBottom') + } - const handleButtonClick = async () => { - const inputValue = inputRef.value; + const handleButtonClick = async() => { + const inputValue = inputRef.value if (!inputValue) - return; + return - inputRef.value = ''; + inputRef.value = '' setMessageList([ ...messageList(), { role: 'user', content: inputValue, }, - ]); - requestWithLatestMessage(); - instantToBottom(); - }; + ]) + requestWithLatestMessage() + instantToBottom() + } const smoothToBottom = useThrottleFn(() => { - window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); - }, 300, false, true); + window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }) + }, 300, false, true) const instantToBottom = () => { - window.scrollTo({ top: document.body.scrollHeight, behavior: 'instant' }); - }; - - const requestWithLatestMessage = async () => { - setLoading(true); - setCurrentAssistantMessage(''); - setCurrentError(null); - const storagePassword = localStorage.getItem('pass'); + window.scrollTo({ top: document.body.scrollHeight, behavior: 'instant' }) + } + + const requestWithLatestMessage = async() => { + setLoading(true) + setCurrentAssistantMessage('') + setCurrentError(null) + const storagePassword = localStorage.getItem('pass') try { - const controller = new AbortController(); - setController(controller); + const controller = new AbortController() + setController(controller) const requestMessageList = messageList().map(message => ({ role: message.role === 'assistant' ? 'model' : 'user', parts: [{ text: message.content }], - })).slice(-maxHistoryMessages); - const timestamp = Date.now(); + })).slice(-maxHistoryMessages) + const timestamp = Date.now() const response = await fetch('/api/generate', { method: 'POST', body: JSON.stringify({ @@ -95,47 +95,49 @@ export default () => { sign: await generateSignature({ t: timestamp, m: requestMessageList?.[requestMessageList.length - 1]?.parts[0]?.text || '', - }) + }), }), signal: controller.signal, - }); + }) if (!response.ok) { - const error = await response.json(); - console.error(error.error); - setCurrentError(error.error); - throw new Error('Request failed'); + const error = await response.json() + console.error(error.error) + setCurrentError(error.error) + throw new Error('Request failed') } - const data = response.body; + const data = response.body if (!data) - throw new Error('No data'); + throw new Error('No data') - const reader = data.getReader(); - const decoder = new TextDecoder('utf-8'); - let done = false; + const reader = data.getReader() + const decoder = new TextDecoder('utf-8') + let done = false while (!done) { - const { value, done: readerDone } = await reader.read(); + const { value, done: readerDone } = await reader.read() if (value) { - const char = decoder.decode(value); + const char = decoder.decode(value, { stream: true }) if (char === '\n' && currentAssistantMessage().endsWith('\n')) - continue; + continue if (char) - setCurrentAssistantMessage(currentAssistantMessage() + char); + setCurrentAssistantMessage(currentAssistantMessage() + char) - isStick() && instantToBottom(); + isStick() && instantToBottom() } - done = readerDone; + done = readerDone } + if (done) + setCurrentAssistantMessage(currentAssistantMessage() + decoder.decode()) } catch (e) { - console.error(e); - setLoading(false); - setController(null); - return; + console.error(e) + setLoading(false) + setController(null) + return } - archiveCurrentMessage(); - isStick() && instantToBottom(); - }; + archiveCurrentMessage() + isStick() && instantToBottom() + } const archiveCurrentMessage = () => { if (currentAssistantMessage()) { @@ -145,49 +147,49 @@ export default () => { role: 'assistant', content: currentAssistantMessage(), }, - ]); - setCurrentAssistantMessage(''); - setLoading(false); - setController(null); + ]) + setCurrentAssistantMessage('') + setLoading(false) + setController(null) // Disable auto-focus on touch devices if (!('ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0)) - inputRef.focus(); + inputRef.focus() } - }; + } const clear = () => { - inputRef.value = ''; - inputRef.style.height = 'auto'; - setMessageList([]); - setCurrentAssistantMessage(''); - setCurrentError(null); - }; + inputRef.value = '' + inputRef.style.height = 'auto' + setMessageList([]) + setCurrentAssistantMessage('') + setCurrentError(null) + } const stopStreamFetch = () => { if (controller()) { - controller().abort(); - archiveCurrentMessage(); + controller().abort() + archiveCurrentMessage() } - }; + } const retryLastFetch = () => { if (messageList().length > 0) { - const lastMessage = messageList()[messageList().length - 1]; + const lastMessage = messageList()[messageList().length - 1] if (lastMessage.role === 'assistant') - setMessageList(messageList().slice(0, -1)); - requestWithLatestMessage(); + setMessageList(messageList().slice(0, -1)) + requestWithLatestMessage() } - }; + } const handleKeydown = (e: KeyboardEvent) => { if (e.isComposing || e.shiftKey) - return; + return if (e.key === 'Enter') { - e.preventDefault(); - handleButtonClick(); + e.preventDefault() + handleButtonClick() } - }; + } return (
@@ -225,8 +227,8 @@ export default () => { autocomplete="off" autofocus onInput={() => { - inputRef.style.height = 'auto'; - inputRef.style.height = `${inputRef.scrollHeight}px`; + inputRef.style.height = 'auto' + inputRef.style.height = `${inputRef.scrollHeight}px` }} rows="1" class="gen-textarea" @@ -247,5 +249,5 @@ export default () => {
- ); -}; + ) +}