React使用OpenAI流式傳輸會在更新和顯示響應時產生重復值

我試圖將OpenAI流式響應的響應進行流式傳輸,并在聊天界面中向用戶顯示響應。然而,雖然每個響應塊本身都是正確的,但我的狀態最終還是出現了重復的單詞。。。我哪里做錯了?

以下是我的代碼以及顯示UI和控制臺輸出的屏幕截圖:

useEffect(() => {
  const doCompletion = async () => {
    if (!newMessage) return;
      
    try {
      await handleCompletion(messages);
      setNewMessage(false);
    } catch (err) {
      console.log("unable to communicate with model service: ", 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: ", 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: ", prevContent)
      
      const newContent = prevContent! + content!;
      console.log("newContent: ", 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 stream setup

    assistantContentRef.current = ''; // Reset ref

    for await (const chunk of stream) {
      const content = chunk.choices[0]?.delta?.content;
      if(content){
        assistantContentRef.current += content;

        setMessages((prev) => {
          // update messages using 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;
        });
      }
    }
  };

  // rest of your code 
};

export default YourComponent;

這種方法保證您的React狀態始終反映最新的AI響應,防止重復。:)

主站蜘蛛池模板: 精品91一区二区三区| 国产乱码一区二区三区爽爽爽| 亚洲熟妇AV一区二区三区宅男| 精品aⅴ一区二区三区| 亚洲美女高清一区二区三区| 中文字幕久久久久一区| 久久免费国产精品一区二区| 精品无码日韩一区二区三区不卡| 精品无码人妻一区二区三区18| 国产成人免费一区二区三区| 中文字幕一区二区三区乱码| 亚洲国产精品第一区二区| 日韩人妻精品一区二区三区视频 | 国产SUV精品一区二区88| 麻豆视传媒一区二区三区| 美女啪啪一区二区三区| 亚洲一区二区三区高清在线观看 | 久99精品视频在线观看婷亚洲片国产一区一级在线 | 精品3d动漫视频一区在线观看| 激情内射亚州一区二区三区爱妻| 麻豆AV一区二区三区| 日本一区二区三区精品国产| 人妻AV一区二区三区精品| 精品一区二区91| 亚洲一区中文字幕在线观看| chinese国产一区二区| 亚洲日韩一区二区三区| 三上悠亚一区二区观看| 日韩精品人妻一区二区三区四区| 区三区激情福利综合中文字幕在线一区 | 日本免费电影一区二区| 午夜视频在线观看一区二区| 国产日韩一区二区三区在线观看| 日本一区中文字幕日本一二三区视频 | 国产激情无码一区二区三区 | 福利一区福利二区| 亚洲色无码专区一区| 国产成人无码一区二区三区| 波多野结衣一区二区免费视频| 中文字幕一区二区三匹| 久久国产精品一区免费下载 |