fix: submit completion by fetch

main
jialin 2 years ago
parent 4dcd11e119
commit bd6b3dcbe3

@ -0,0 +1,61 @@
import qs from 'query-string';
import { useRef } from 'react';
export const createEventSourceURL = (url: string) => {
const { host, protocol } = window.location;
return `${protocol}://${host}${url}`;
};
/*
0: connecting
1: connect successfully
2: closed
*/
export default function useEventSource() {
const eventSourceRef = useRef<any>(null);
const createEventSourceConnection = (query: {
url: string;
params: any;
onmessage?: (data: any) => void;
}) => {
eventSourceRef.current?.close?.();
const { url, params, onmessage = () => {} } = query;
const sseurl = createEventSourceURL(url);
eventSourceRef.current = new EventSource(
`${url}?${qs.stringify({
...params
})}`,
{
withCredentials: true
}
);
eventSourceRef.current.onmessage = (res: any) => {
try {
const data = JSON.parse(res.data);
console.log('event source message: ', { data, resData: res });
onmessage(data);
} catch (error) {
// error
}
};
eventSourceRef.current.onopen = () => {
console.log('event source connected...');
};
eventSourceRef.current.onerror = (error: any) => {
console.log('event source error: ', error);
};
};
return {
eventSourceRef: eventSourceRef,
createEventSourceConnection
};
}

@ -8,3 +8,43 @@ export async function execChatCompletions(params: any) {
data: params
});
}
export const fetchChatStream = async (params: any) => {
const response = await fetch(`/v1${CHAT_API}`, {
method: 'POST',
body: JSON.stringify(params),
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
return null;
}
const reader = response?.body?.getReader();
const decoder = new TextDecoder('utf-8');
return {
reader,
decoder
};
};
export const receiveChatStream = async (
reader: any,
decoder: TextDecoder,
callback: (data: any) => void
) => {
const { done, value } = await reader.read();
if (done) {
return;
}
let chunk = decoder.decode(value, { stream: true });
if (chunk.startsWith('data: ')) {
chunk = chunk.substring('data: '.length);
}
const item = JSON.parse(chunk?.trim());
callback(item);
await receiveChatStream(reader, decoder, callback);
};

@ -5,7 +5,7 @@ import { useIntl } from '@umijs/max';
import { Button, Input, Spin } from 'antd';
import _ from 'lodash';
import { useRef, useState } from 'react';
import { execChatCompletions } from '../apis';
import { fetchChatStream, receiveChatStream } from '../apis';
import { Roles } from '../config';
import '../style/ground-left.less';
import '../style/system-message-wrap.less';
@ -13,7 +13,6 @@ 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;
}
@ -42,7 +41,11 @@ const MessageList: React.FC<MessageProps> = (props) => {
const [activeIndex, setActiveIndex] = useState(-1);
const [tokenResult, setTokenResult] = useState<any>(null);
const systemRef = useRef<any>(null);
const contentRef = useRef<any>('');
const handleReceiveMessage = (data: any) => {
console.log('event source message: ', { data });
};
const handleSystemMessageChange = (e: any) => {
setSystemMessage(e.target.value);
};
@ -61,10 +64,32 @@ const MessageList: React.FC<MessageProps> = (props) => {
setActiveIndex(messageList.length - 1);
};
const joinMessage = (chunk: any) => {
if (_.get(chunk, 'choices.0.finish_reason')) {
setTokenResult({
...chunk?.usage
});
return true;
}
contentRef.current =
contentRef.current + _.get(chunk, 'choices.0.delta.content');
setMessageList([
...messageList,
{
role: Roles.Assistant,
content: contentRef.current,
uid: messageId.current
}
]);
return false;
};
const submitMessage = async () => {
try {
setLoading(true);
setMessageId();
setTokenResult(null);
contentRef.current = '';
const chatParams = {
messages: systemMessage
? [
@ -75,22 +100,19 @@ const MessageList: React.FC<MessageProps> = (props) => {
...messageList
]
: [...messageList],
...parameters
...parameters,
stream: true
};
const data = await execChatCompletions(chatParams);
const assistant = _.get(data, ['choices', '0', 'message']);
setTokenResult({
...data.usage
const result = await fetchChatStream(chatParams);
if (!result) {
return;
}
const { reader, decoder } = result;
await receiveChatStream(reader, decoder, (data: any) => {
joinMessage(data);
});
setMessageList([
...messageList,
{
role: Roles.Assistant,
content: assistant.content,
uid: messageId.current + 1
}
]);
setMessageId();
setLoading(false);
} catch (error) {
setLoading(false);
@ -105,7 +127,6 @@ const MessageList: React.FC<MessageProps> = (props) => {
};
const handleSubmit = () => {
console.log('submit');
submitMessage();
};

@ -32,28 +32,32 @@ const MessageItem: React.FC<{
}
}, [isFocus]);
// useEffect(() => {
// if (isTyping) return;
// let index = 0;
// const text = message.content;
// if (!text.length) {
// return;
// }
// setMessageContent('');
// setIsAnimating(true);
// const intervalId = setInterval(() => {
// setMessageContent((prev) => prev + text[index]);
// index += 1;
// if (index === text.length) {
// setIsAnimating(false);
// clearInterval(intervalId);
// }
// }, 20);
// return () => clearInterval(intervalId);
// }, [message.content, isTyping]);
useEffect(() => {
if (isTyping) return;
let index = 0;
const text = message.content;
if (!text.length) {
return;
}
setMessageContent('');
setIsAnimating(true);
const intervalId = setInterval(() => {
setMessageContent((prev) => prev + text[index]);
index += 1;
if (index === text.length) {
setIsAnimating(false);
clearInterval(intervalId);
}
}, 20);
return () => clearInterval(intervalId);
}, [message.content, isTyping]);
setMessageContent(message.content);
}, [message.content]);
useEffect(() => {
if (!isAnimating && !isInitialRender.current) {
if (!isInitialRender.current) {
updateMessage({
role: roleType,
content: messageContent,

@ -28,7 +28,6 @@ export const requestConfig: RequestConfig = {
],
responseInterceptors: [
(response) => {
console.log('responseInterceptors+++++++++++++++', response);
return response;
}
]

Loading…
Cancel
Save