Skip to content

Commit

Permalink
Update Generator.tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
babaohuang committed Dec 14, 2023
1 parent eae250e commit ee89e6b
Showing 1 changed file with 106 additions and 104 deletions.
210 changes: 106 additions & 104 deletions src/components/Generator.tsx
Original file line number Diff line number Diff line change
@@ -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<ChatMessage[]>([]);
const [currentError, setCurrentError] = createSignal<ErrorMessage>();
const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal('');
const [loading, setLoading] = createSignal(false);
const [controller, setController] = createSignal<AbortController>(null);
const [isStick, setStick] = createSignal(false);
const maxHistoryMessages = parseInt(import.meta.env.PUBLIC_MAX_HISTORY_MESSAGES || '9');
let inputRef: HTMLTextAreaElement
const [messageList, setMessageList] = createSignal<ChatMessage[]>([])
const [currentError, setCurrentError] = createSignal<ErrorMessage>()
const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal('')
const [loading, setLoading] = createSignal(false)
const [controller, setController] = createSignal<AbortController>(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({
Expand All @@ -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()) {
Expand All @@ -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 (
<div my-6>
Expand Down Expand Up @@ -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"
Expand All @@ -247,5 +249,5 @@ export default () => {
</div>
</div>
</div>
);
};
)
}

0 comments on commit ee89e6b

Please sign in to comment.