我正在尝试从OpenAI的流式响应中获取响应,并在聊天界面中向用户显示响应。然而,虽然响应的每个块本身是正确的,但我的状态最终会出现重复的词语… 问题出在哪里?
这是我的代码以及显示UI和控制台输出的截图:
useEffect(() => { const doCompletion = async () => { if (!newMessage) return; try { await handleCompletion(messages); setNewMessage(false); } catch (err) { console.log("无法与模型服务通信: ", err) } } doCompletion();}, [newMessage]);const handleNewMessage = async (formData: FormData) => { const message = formData.get("message") as string; addMessage({id: uuidv4(), data: {role: "user", content: message}}); setNewMessage(true);}const handleCompletion = async (messages: Message[]) => { const formattedMessages = messages.map((message: Message)=> message.data) const stream = await openai.chat.completions.create({ messages: formattedMessages, model: "deepseek-chat", stream: true }); for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content; console.log("内容: ", content) setMessages((prev) => { let tmpMessages = [...prev]; const lastMessageIndex = tmpMessages.length-1; if (tmpMessages[lastMessageIndex].data.role !== "assistant") { tmpMessages.push({id: chunk.id, data: {role: "assistant", content: ""}}); return tmpMessages; } const prevContent = tmpMessages[lastMessageIndex].data.content; console.log("之前的内容: ", prevContent) const newContent = prevContent! + content!; console.log("新的内容: ", newContent) tmpMessages[lastMessageIndex].data.content = newContent; return tmpMessages; }); }}
回答:
让我们尝试修复它!
你的问题是在React中流式传输OpenAI响应时,快速的块更新可能会导致状态过时,从而在显示的聊天中出现重复的词语。
我的建议是使用useRef
来存储来自OpenAI流的最新累积内容。这样可以确保状态更新基于最新的数据。
import React, { useState, useEffect, useRef } from 'react';const YourComponent = () => { const [messages, setMessages] = useState([]); const assistantContentRef = useRef(''); const handleCompletion = async (messages) => { // 设置OpenAI流 assistantContentRef.current = ''; // 重置ref for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content; if(content){ assistantContentRef.current += content; setMessages((prev) => { // 使用assistantContentRef.current更新消息 let tmpMessages = [...prev]; const lastMessageIndex = tmpMessages.length - 1; if (tmpMessages[lastMessageIndex]?.data.role !== 'assistant') { tmpMessages.push({ id: chunk.id, data: { role: 'assistant', content: assistantContentRef.current }, }); } else { tmpMessages[lastMessageIndex].data.content = assistantContentRef.current; } return tmpMessages; }); } } }; // 你的其他代码 };export default YourComponent;
这种方法可以保证你的React状态始终反映最新的AI响应,防止重复出现。:)