Skip to content

Commit 9555b01

Browse files
authored
✏️ fix: slove if retrun null, still loading flag problem (#115)
1 parent cee8dda commit 9555b01

2 files changed

Lines changed: 31 additions & 109 deletions

File tree

src/ProChat/components/ScrollAnchor/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ const ChatScrollAnchor = memo(({ target }: { target: React.RefObject<HTMLDivElem
3737

3838
useEffect(() => {
3939
if (isWindowAvailable) {
40-
// 如果是移动端,可能200太多了,认为超过 1/3 即可,PC默认200
41-
setScrollOffset(window.innerHeight / 3 > 200 ? 200 : window.innerHeight / 4);
40+
// 如果是移动端,可能100太多了,认为超过 1/3 即可,PC默认100
41+
setScrollOffset(window.innerHeight / 3 > 100 ? 100 : window.innerHeight / 4);
4242
}
4343
}, [isWindowAvailable]);
4444

src/ProChat/store/action.ts

Lines changed: 29 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { isFunctionMessage } from '@/ProChat/utils/message';
88
import { setNamespace } from '@/ProChat/utils/storeDebug';
99
import { nanoid } from '@/ProChat/utils/uuid';
1010
import { ChatMessage } from '@/types/message';
11+
import { startTransition } from 'react';
1112

1213
import { initialModelConfig } from '@/ProChat/store/initialState';
1314
import { ChatStreamPayload } from '@/ProChat/types/chat';
@@ -109,16 +110,6 @@ export interface ChatAction {
109110
*/
110111
updateMessageContent: (id: string, content: string) => Promise<void>;
111112

112-
/**
113-
* 创建一条平滑输出的内容
114-
*/
115-
createSmoothMessage: (id: string) => {
116-
startAnimation: (speed?: number) => Promise<void>;
117-
stopAnimation: () => void;
118-
outputQueue: string[];
119-
isAnimationActive: boolean;
120-
};
121-
122113
/**
123114
* 获取当前 loading 生成的消息 id
124115
* @returns 消息 id | undefined
@@ -161,14 +152,7 @@ export const chatAction: StateCreator<ChatStore, [['zustand/devtools', never]],
161152
onChatsChange?.(nextChats);
162153
},
163154
generateMessage: async (messages, assistantId) => {
164-
const {
165-
dispatchMessage,
166-
toggleChatLoading,
167-
config,
168-
defaultModelFetcher,
169-
createSmoothMessage,
170-
updateMessageContent,
171-
} = get();
155+
const { dispatchMessage, toggleChatLoading, config, defaultModelFetcher } = get();
172156

173157
const abortController = toggleChatLoading(
174158
true,
@@ -219,35 +203,23 @@ export const chatAction: StateCreator<ChatStore, [['zustand/devtools', never]],
219203
let output = '';
220204
let isFunctionCall = false;
221205

222-
const { startAnimation, stopAnimation, outputQueue, isAnimationActive } =
223-
createSmoothMessage(assistantId);
224-
225206
await fetchSSE(fetcher, {
226207
onErrorHandle: (error) => {
227208
dispatchMessage({ id: assistantId, key: 'error', type: 'updateMessage', value: error });
228209
},
229-
onAbort: async () => {
230-
stopAnimation();
231-
},
232-
onFinish: async (content) => {
233-
stopAnimation();
234-
235-
if (outputQueue.length > 0 && !isFunctionCall) {
236-
await startAnimation(15);
237-
}
238-
239-
await updateMessageContent(assistantId, content);
240-
},
241210
onMessageHandle: (text) => {
242211
output += text;
243-
244-
if (!isAnimationActive && !isFunctionCall) startAnimation();
245-
246-
if (abortController?.signal.aborted) {
247-
// aborted 后停止当前输出
248-
return;
212+
if (!abortController.signal.aborted) {
213+
startTransition(() => {
214+
dispatchMessage({
215+
id: assistantId,
216+
key: 'content',
217+
type: 'updateMessage',
218+
value: output,
219+
});
220+
});
249221
} else {
250-
outputQueue.push(...text.split(''));
222+
return;
251223
}
252224

253225
// TODO: need a function call judge callback
@@ -258,76 +230,13 @@ export const chatAction: StateCreator<ChatStore, [['zustand/devtools', never]],
258230
},
259231
});
260232

261-
toggleChatLoading(false, undefined, t('generateMessage(end)') as string);
233+
startTransition(() => {
234+
toggleChatLoading(false, undefined, t('generateMessage(end)') as string);
235+
});
262236

263237
return { isFunctionCall };
264238
},
265239

266-
createSmoothMessage: (id) => {
267-
const { dispatchMessage } = get();
268-
269-
let buffer = '';
270-
// why use queue: https://shareg.pt/GLBrjpK
271-
let outputQueue: string[] = [];
272-
273-
// eslint-disable-next-line no-undef
274-
let animationTimeoutId: NodeJS.Timeout | null = null;
275-
let isAnimationActive = false;
276-
277-
// when you need to stop the animation, call this function
278-
const stopAnimation = () => {
279-
isAnimationActive = false;
280-
if (animationTimeoutId !== null) {
281-
clearTimeout(animationTimeoutId);
282-
animationTimeoutId = null;
283-
}
284-
};
285-
286-
// define startAnimation function to display the text in buffer smooth
287-
// when you need to start the animation, call this function
288-
const startAnimation = (speed = 2) =>
289-
new Promise<void>((resolve) => {
290-
if (isAnimationActive) {
291-
resolve();
292-
return;
293-
}
294-
295-
isAnimationActive = true;
296-
297-
const updateText = () => {
298-
// 如果动画已经不再激活,则停止更新文本
299-
if (!isAnimationActive) {
300-
clearTimeout(animationTimeoutId!);
301-
animationTimeoutId = null;
302-
resolve();
303-
}
304-
305-
// 如果还有文本没有显示
306-
// 检查队列中是否有字符待显示
307-
if (outputQueue.length > 0) {
308-
// 从队列中获取前两个字符(如果存在)
309-
const charsToAdd = outputQueue.splice(0, speed).join('');
310-
buffer += charsToAdd;
311-
312-
// 更新消息内容,这里可能需要结合实际情况调整
313-
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: buffer });
314-
315-
// 设置下一个字符的延迟
316-
animationTimeoutId = setTimeout(updateText, 16); // 16 毫秒的延迟模拟打字机效果
317-
} else {
318-
// 当所有字符都显示完毕时,清除动画状态
319-
isAnimationActive = false;
320-
animationTimeoutId = null;
321-
resolve();
322-
}
323-
};
324-
325-
updateText();
326-
});
327-
328-
return { startAnimation, stopAnimation, outputQueue, isAnimationActive };
329-
},
330-
331240
realFetchAIResponse: async (messages, userMessageId) => {
332241
const { dispatchMessage, generateMessage, config, getMessageId } = get();
333242

@@ -412,7 +321,20 @@ export const chatAction: StateCreator<ChatStore, [['zustand/devtools', never]],
412321
},
413322

414323
stopGenerateMessage: () => {
415-
const { abortController, toggleChatLoading } = get();
324+
const { abortController, toggleChatLoading, chatLoadingId, chats, dispatchMessage } = get();
325+
// 如果当前 最后一条为 chatLoadingId 停止前需要清空
326+
if (chats && chats.length > 0) {
327+
const lastChat = chats[chats.length - 1];
328+
if (lastChat.content === LOADING_FLAT) {
329+
dispatchMessage({
330+
id: chatLoadingId,
331+
key: 'content',
332+
type: 'updateMessage',
333+
value: '',
334+
});
335+
}
336+
}
337+
416338
if (!abortController) return;
417339

418340
abortController.abort();

0 commit comments

Comments
 (0)