Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useXChat的defaultMessages和Bubble.List组件的逐条显示列表问题 #442

Open
CatchMeX opened this issue Jan 2, 2025 · 8 comments
Labels
bug Something isn't working

Comments

@CatchMeX
Copy link

CatchMeX commented Jan 2, 2025

重现步骤

在线示例链接:(必填)

步骤:
1.接口请求一组数据 异步设置到state中 useXChat的defaultMessages使用接口请求回来的数据
2.接口请求一组数据 并使用useXChat的setMessages应用这组数据 然后用Bubble.List渲染
3.

当前行为

步骤1中 useXChat的defaultMessages并不是响应性的 messages并没有变化
步骤2中 执行setMessages之后 消息列表并不是一次性把所有的消息渲染出来 而是一条一条的逐步渲染

预期行为

从接口异步获取历史记录后 调用setMessages 使用Bubble.List渲染的时候 期望一次性全部渲染 而不是一条一条逐步渲染

上下文

No response

版本

1.0.4

您在哪些浏览器上遇到了这个问题?

No response

@CatchMeX CatchMeX added the bug Something isn't working label Jan 2, 2025
Copy link

您提到的问题涉及到 useXChatdefaultMessagesBubble.List 组件的渲染行为。根据您的描述,您希望在调用 setMessages 后,Bubble.List 能够一次性渲染所有消息,而不是逐条渲染。

可能的解决方案

  1. 检查数据更新逻辑

    • 确保在接口请求数据后,setMessages 被正确调用,并且数据格式符合 useXChat 的要求。
    • 确保 setMessages 的调用是在数据完全获取并准备好之后进行的。
  2. 组件渲染优化

    • 检查 Bubble.List 的渲染逻辑,确保没有设置逐条渲染的机制。
    • 如果 Bubble.List 有批量渲染的配置选项,确保该选项已启用。
  3. 状态管理

    • 确保 useXChat 的状态管理正确,特别是在 defaultMessagessetMessages 的使用上。
    • 检查是否有其他状态更新影响了 Bubble.List 的渲染。

如果这些建议没有解决您的问题,您可以提供更多的代码细节,我将更好地帮助您分析问题。

🪧 Tips For further assistance, please describe your question in the comments and @petercat-assistant to start a conversation with me.

@YumoImer
Copy link
Collaborator

YumoImer commented Jan 3, 2025

根据描述无法定位和复现,来个最小复现示例

@EternallyTm
Copy link

重现步骤

在线示例链接:(必填)

步骤: 1.接口请求一组数据 异步设置到state中 useXChat的defaultMessages使用接口请求回来的数据 2.接口请求一组数据 并使用useXChat的setMessages应用这组数据 然后用Bubble.List渲染 3.

当前行为

步骤1中 useXChat的defaultMessages并不是响应性的 messages并没有变化 步骤2中 执行setMessages之后 消息列表并不是一次性把所有的消息渲染出来 而是一条一条的逐步渲染

预期行为

从接口异步获取历史记录后 调用setMessages 使用Bubble.List渲染的时候 期望一次性全部渲染 而不是一条一条逐步渲染

上下文

No response

版本

1.0.4

您在哪些浏览器上遇到了这个问题?

No response

@EternallyTm
Copy link

我也遇到了这个问题,加载历史聊天记录时,调用setMessages,也是一条一条的流式渲染,期望历史聊天记录一次渲染完成

@ASAMUL
Copy link

ASAMUL commented Jan 6, 2025

没遇到过,我也是useXChat和setMessages来显示历史消息,目前我的不是流式渲染,建议贴个代码看看

@EternallyTm
Copy link

没遇到过,我也是useXChat和setMessages来显示历史消息,目前我的不是流式渲染,建议贴个代码看看

我是这样使用的:
const [agent] = useXAgent({
request: async ({ message }, { onSuccess, onUpdate, onError }) => {
if (!message || !message.conversationId) {
return;
}

        const chatParam: ChatParam = {
            message: message.message,
            role: selectedRole,
            model: selectedModel,
            conversationId: message.conversationId,
        };
        const token = getToken();
        abortControllerRef.current = new AbortController();

        try {
            let fullMessage = '';
            const loadingMessage: MessageResp = {
                id: nanoid(),
                message: 'loading...',
                sender: 'BOT',
                createdAt: new Date().toISOString(),
                loading: true
            };
            onUpdate(loadingMessage);

            await fetchEventSource('http://localhost:8888/api/v1/chat/assistant/chat', {
                method: 'POST',
                body: JSON.stringify(chatParam),
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${token}`,
                },
                openWhenHidden: true,
                signal: abortControllerRef.current.signal,
                onopen(response) {
                    if (response.ok) {
                        console.log('SSE connection opened');
                    } else {
                        console.error('Failed to open SSE connection', response.statusText);
                        onError(new Error('Failed to open SSE connection'));
                    }
                    return Promise.resolve();
                },
                onmessage(event) {
                    if (!isValidJson(event.data)) {
                        console.error('Invalid JSON data');
                        return;
                    }
                    const parsedData = JSON.parse(event.data);
                    fullMessage += parsedData.message;
                    onUpdate({
                        id: parsedData.id,
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                    scrollToBottom();
                },
                onerror(err) {
                    console.error('SSE request error', err);
                    onError(new Error('SSE request error'));
                },
                onclose() {
                    onSuccess({
                        id: nanoid(),
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                },
            });
        } catch (error) {
            console.error('Request error', error);
            onError(new Error("Request exception occurred"));
        }
    }
});

const { onRequest, messages, setMessages } = useXChat<MessageResp>({
    agent,
    parser: (message) => ({
        id: message.id,
        sender: message.sender,
        message: message.message,
        createdAt: message.createdAt,
    }),
    requestFallback: ERROR_MESSAGES,
});

useEffect(() => {
    if (conversationId === 0 || !routerState?.state.message) return;
    sendMessage(routerState.state.message).then(() => setRouterState({...routerState,message: null}));
}, [conversationId]);

useEffect(() => {
    if (conversationId === 0) return;
    getConversationDetail(conversationId)
        .then(res => setConversationTitle(res.title))
        .catch(err => console.error('Failed to fetch conversation detail', err));

    if (routerState?.state.isNew) return;

    getMessagesList(conversationId)
        .then((res) => {
            const msgs = res.length ? res : DEFAULT_MESSAGES;
            setMessages(msgs.map((item) => ({
                id: item.id,
                message: item,
                status: res.length ? 'local' : 'success',
            })));
        })
        .catch(err => console.error('Failed to fetch message list', err));
}, [conversationId, setMessages, routerState]);

消息渲染:
return (





<Bubble.List
className="messages-list"
items={messages.map(message => ({
key: message.id,
role: message.message.sender,
content: message.message.message,
loading: message.message.loading,
}))}
roles={roles}
/>




@ASAMUL
Copy link

ASAMUL commented Jan 6, 2025

没遇到过,我也是useXChat和setMessages来显示历史消息,目前我的不是流式渲染,建议贴个代码看看

我是这样使用的: const [agent] = useXAgent({ request: async ({ message }, { onSuccess, onUpdate, onError }) => { if (!message || !message.conversationId) { return; }

        const chatParam: ChatParam = {
            message: message.message,
            role: selectedRole,
            model: selectedModel,
            conversationId: message.conversationId,
        };
        const token = getToken();
        abortControllerRef.current = new AbortController();

        try {
            let fullMessage = '';
            const loadingMessage: MessageResp = {
                id: nanoid(),
                message: 'loading...',
                sender: 'BOT',
                createdAt: new Date().toISOString(),
                loading: true
            };
            onUpdate(loadingMessage);

            await fetchEventSource('http://localhost:8888/api/v1/chat/assistant/chat', {
                method: 'POST',
                body: JSON.stringify(chatParam),
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${token}`,
                },
                openWhenHidden: true,
                signal: abortControllerRef.current.signal,
                onopen(response) {
                    if (response.ok) {
                        console.log('SSE connection opened');
                    } else {
                        console.error('Failed to open SSE connection', response.statusText);
                        onError(new Error('Failed to open SSE connection'));
                    }
                    return Promise.resolve();
                },
                onmessage(event) {
                    if (!isValidJson(event.data)) {
                        console.error('Invalid JSON data');
                        return;
                    }
                    const parsedData = JSON.parse(event.data);
                    fullMessage += parsedData.message;
                    onUpdate({
                        id: parsedData.id,
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                    scrollToBottom();
                },
                onerror(err) {
                    console.error('SSE request error', err);
                    onError(new Error('SSE request error'));
                },
                onclose() {
                    onSuccess({
                        id: nanoid(),
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                },
            });
        } catch (error) {
            console.error('Request error', error);
            onError(new Error("Request exception occurred"));
        }
    }
});

const { onRequest, messages, setMessages } = useXChat<MessageResp>({
    agent,
    parser: (message) => ({
        id: message.id,
        sender: message.sender,
        message: message.message,
        createdAt: message.createdAt,
    }),
    requestFallback: ERROR_MESSAGES,
});

useEffect(() => {
    if (conversationId === 0 || !routerState?.state.message) return;
    sendMessage(routerState.state.message).then(() => setRouterState({...routerState,message: null}));
}, [conversationId]);

useEffect(() => {
    if (conversationId === 0) return;
    getConversationDetail(conversationId)
        .then(res => setConversationTitle(res.title))
        .catch(err => console.error('Failed to fetch conversation detail', err));

    if (routerState?.state.isNew) return;

    getMessagesList(conversationId)
        .then((res) => {
            const msgs = res.length ? res : DEFAULT_MESSAGES;
            setMessages(msgs.map((item) => ({
                id: item.id,
                message: item,
                status: res.length ? 'local' : 'success',
            })));
        })
        .catch(err => console.error('Failed to fetch message list', err));
}, [conversationId, setMessages, routerState]);

消息渲染: return (

<Bubble.List
className="messages-list"
items={messages.map(message => ({
key: message.id,
role: message.message.sender,
content: message.message.message,
loading: message.message.loading,
}))}
roles={roles}
/>

我大概知道问题了,你把 loading: message.message.loading,删掉试试,不要加loading,用loading就会触发他预设的typing应该是

@EternallyTm
Copy link

没遇到过,我也是useXChat和setMessages来显示历史消息,目前我的不是流式渲染,建议贴个代码看看

我是这样使用的: const [agent] = useXAgent({ request: async ({ message }, { onSuccess, onUpdate, onError }) => { if (!message || !message.conversationId) { return; }

        const chatParam: ChatParam = {
            message: message.message,
            role: selectedRole,
            model: selectedModel,
            conversationId: message.conversationId,
        };
        const token = getToken();
        abortControllerRef.current = new AbortController();

        try {
            let fullMessage = '';
            const loadingMessage: MessageResp = {
                id: nanoid(),
                message: 'loading...',
                sender: 'BOT',
                createdAt: new Date().toISOString(),
                loading: true
            };
            onUpdate(loadingMessage);

            await fetchEventSource('http://localhost:8888/api/v1/chat/assistant/chat', {
                method: 'POST',
                body: JSON.stringify(chatParam),
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${token}`,
                },
                openWhenHidden: true,
                signal: abortControllerRef.current.signal,
                onopen(response) {
                    if (response.ok) {
                        console.log('SSE connection opened');
                    } else {
                        console.error('Failed to open SSE connection', response.statusText);
                        onError(new Error('Failed to open SSE connection'));
                    }
                    return Promise.resolve();
                },
                onmessage(event) {
                    if (!isValidJson(event.data)) {
                        console.error('Invalid JSON data');
                        return;
                    }
                    const parsedData = JSON.parse(event.data);
                    fullMessage += parsedData.message;
                    onUpdate({
                        id: parsedData.id,
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                    scrollToBottom();
                },
                onerror(err) {
                    console.error('SSE request error', err);
                    onError(new Error('SSE request error'));
                },
                onclose() {
                    onSuccess({
                        id: nanoid(),
                        sender: 'BOT',
                        message: fullMessage,
                        createdAt: new Date().toISOString(),
                    });
                },
            });
        } catch (error) {
            console.error('Request error', error);
            onError(new Error("Request exception occurred"));
        }
    }
});

const { onRequest, messages, setMessages } = useXChat<MessageResp>({
    agent,
    parser: (message) => ({
        id: message.id,
        sender: message.sender,
        message: message.message,
        createdAt: message.createdAt,
    }),
    requestFallback: ERROR_MESSAGES,
});

useEffect(() => {
    if (conversationId === 0 || !routerState?.state.message) return;
    sendMessage(routerState.state.message).then(() => setRouterState({...routerState,message: null}));
}, [conversationId]);

useEffect(() => {
    if (conversationId === 0) return;
    getConversationDetail(conversationId)
        .then(res => setConversationTitle(res.title))
        .catch(err => console.error('Failed to fetch conversation detail', err));

    if (routerState?.state.isNew) return;

    getMessagesList(conversationId)
        .then((res) => {
            const msgs = res.length ? res : DEFAULT_MESSAGES;
            setMessages(msgs.map((item) => ({
                id: item.id,
                message: item,
                status: res.length ? 'local' : 'success',
            })));
        })
        .catch(err => console.error('Failed to fetch message list', err));
}, [conversationId, setMessages, routerState]);

消息渲染: return (
<Bubble.List
className="messages-list"
items={messages.map(message => ({
key: message.id,
role: message.message.sender,
content: message.message.message,
loading: message.message.loading,
}))}
roles={roles}
/>

我大概知道问题了,你把 loading: message.message.loading,删掉试试,不要加loading,用loading就会触发他预设的typing应该是

OK,我试试看,感谢🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants