react实现chatGPT流式对话

in React with 0 comment
  1. React 组件部分

    import React, { useState } from "react";

    function ChatComponent() {
    const [messages, setMessages] = useState([

    { role: "user", content: "Tell me about JavaScript." },

    ]);
    const [streamingText, setStreamingText] = useState(""); // 保存流式响应的内容
    const [isLoading, setIsLoading] = useState(false);

    // 处理发送消息
    const sendMessage = async () => {

    const apiKey = "your-api-key"; // 替换成你的 OpenAI API Key
    const url = "https://api.openai.com/v1/chat/completions";
    
    const headers = {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    };
    
    const body = JSON.stringify({
      model: "gpt-3.5-turbo",
      messages: [
        { role: "system", content: "You are a helpful assistant." },
        ...messages,
      ],
      stream: true, // 启用流式输出
    });
    
    setIsLoading(true);
    setStreamingText(""); // 清空之前的流式内容
    
    const response = await fetch(url, {
      method: "POST",
      headers: headers,
      body: body,
    });
    
    if (!response.body) return;
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder("utf-8");
    let done = false;
    
    // 逐块读取流
    while (!done) {
      const { value, done: readerDone } = await reader.read();
      done = readerDone;
      const chunk = decoder.decode(value, { stream: true });
    
      // 解析并提取流式内容
      const lines = chunk.split("\n").filter((line) => line.trim() !== "");
      for (const line of lines) {
        const parsedLine = line.replace(/^data: /, ""); // 去掉开头的 "data: "
        if (parsedLine === "[DONE]") {
          return; // 流结束
        }
    
        try {
          const parsed = JSON.parse(parsedLine);
          const content = parsed.choices[0].delta?.content || "";
          setStreamingText((prev) => prev + content); // 更新 UI 中的流式文本
        } catch (err) {
          console.error("Could not parse stream chunk", err);
        }
      }
    }
    
    setIsLoading(false);

    };

    return (

    <div>
      <h2>ChatGPT Stream Output</h2>
      <div className="messages">
        {messages.map((msg, index) => (
          <div key={index}>
            <strong>{msg.role === "user" ? "You" : "Assistant"}: </strong>
            {msg.content}
          </div>
        ))}
        {isLoading && (
          <div>
            <strong>Assistant: </strong>
            {streamingText}
          </div>
        )}
      </div>
      <button onClick={sendMessage} disabled={isLoading}>
        Send Message
      </button>
    </div>

    );
    }

    export default ChatComponent;

  2. 样式 (CSS)
    可以添加一些简单的样式来美化聊天窗口:
.messages {
  border: 1px solid #ddd;
  padding: 10px;
  max-width: 600px;
  height: 400px;
  overflow-y: auto;
  margin-bottom: 20px;
  background-color: #f9f9f9;
}

button {
  padding: 10px 20px;
  font-size: 16px;
}

关键点解析:
fetch 和 ReadableStream:

fetch 返回的流通过 response.body.getReader() 读取数据块。
使用 TextDecoder 将二进制流解码为文本。
逐步更新状态:

每次读取到新的数据块时,通过 setStreamingText 将内容逐步追加到当前的流式输出中。
这样可以确保用户能逐步看到 ChatGPT 的回复,而不是一次性全部显示。
控制按钮状态:

使用 isLoading 来控制按钮是否可点击,防止重复请求。
通过这种方式,你可以在 React 应用中实现 ChatGPT 流式输出的效果,并逐步显示内容。

Comments are closed.