跳至主要內容

24日


24日

服务端流式推送信息道客户端

除了 WebSocket ,还可以使用 Server-Sent Events

提示

以下是一个使用java后端调用GPT4的api,将返回信息使用text/event-stream,流式传输到基于nextjs实现的网页中的Demo

  1. 后端Java服务
    • 使用Java的HTTP客户端库(如Apache HttpClient或OkHttp)向OpenAI的GPT-4 API发送请求
    • 在响应头中设置Content-Type为text/event-stream
    • 使用ServletOutputStream或其他流式输出将OpenAI API返回的数据流式传输到前端
  2. NextJS前端
    • 使用浏览器提供的EventSource API建立到后端服务的流连接
    • 监听从服务端推送的文本事件,将其渲染到UI上

下面是一些伪代码示例:

Java后端:

@RequestMapping(path = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestBody String prompt) {
    // 构建OpenAI API请求
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.openai.com/v1/engines/gpt-4/completions"))
        .header("Content-Type", "application/json")
        .header("Authorization", "Bearer YOUR_API_KEY")
        .POST(HttpRequest.BodyPublishers.ofString("{\"prompt\": \"" + prompt + "\"}"))
        .build();

    // 发送请求并获取响应
    HttpResponse<Stream<String>> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofLines());

    // 流式传输响应数据
    return response.body().map(data -> "data: " + data + "\n\n");
}

NextJS前端:

import { useState, useEffect } from 'react';

export default function ChatPage() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const eventSource = new EventSource('/api/chat');
    eventSource.onmessage = (event) => {
      if (event.data === '') return;
      setMessages((prevMessages) => [...prevMessages, event.data]);
    };
  }, []);

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}>{msg}</div>
      ))}
    </div>
  );
}

在这个示例中,Java后端使用Flux对象作为响应体,将OpenAI API返回的数据流式传输到前端。前端使用EventSource API接收服务端推送的文本事件,并将其渲染到UI上。

需要注意的是,这只是一个概念性的实现,在实际使用中还需要考虑错误处理、连接重试、UI优化等问题。此外,还需要将OpenAI API密钥作为环境变量或其他安全方式提供给服务端。

提示

以下是WebSocket的Demo

使用WebSocket来实现双向通信,使后端服务器能够主动向客户端推送数据。

Java后端:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.openai.OpenAI;
import com.openai.CompletionResponse;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class GPT4WebSocket extends WebSocketServer {
    private static final ObjectMapper MAPPER = new ObjectMapper();
    private static final Map<WebSocket, String> SESSIONS = new ConcurrentHashMap<>();

    public GPT4WebSocket(int port) {
        super(new InetSocketAddress(port));
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        SESSIONS.put(conn, "");
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        SESSIONS.remove(conn);
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        String session = SESSIONS.get(conn);
        session += message;
        SESSIONS.put(conn, session);

        try {
            CompletionResponse response = OpenAI.completion(Collections.singletonMap("prompt", session));
            String reply = response.getChoices().get(0).getText();
            conn.send(reply);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        ex.printStackTrace();
    }

    public static void main(String[] args) throws InterruptedException {
        OpenAI.apiKey = "YOUR_API_KEY";
        GPT4WebSocket server = new GPT4WebSocket(8080);
        server.start();
        System.out.println("Server started on port 8080");
    }
}

Next.js前端:

import { useState, useEffect } from 'react';

export default function ChatPage() {
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState('');
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const newSocket = new WebSocket('ws://localhost:8080');

    newSocket.onopen = () => {
      console.log('WebSocket connection opened');
    };

    newSocket.onmessage = (event) => {
      setMessages((prevMessages) => [...prevMessages, event.data]);
    };

    newSocket.onclose = () => {
      console.log('WebSocket connection closed');
    };

    setSocket(newSocket);

    return () => {
      newSocket.close();
    };
  }, []);

  const sendMessage = () => {
    if (inputText.trim() !== '' && socket) {
      socket.send(inputText);
      setInputText('');
    }
  };

  return (
    <div>
      <div>
        {messages.map((msg, i) => (
          <div key={i}>{msg}</div>
        ))}
      </div>
      <input
        type="text"
        value={inputText}
        onChange={(e) => setInputText(e.target.value)}
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            sendMessage();
          }
        }}
      />
    </div>
  );
}

在这个示例中,Java后端使用WebSocket服务器与客户端建立长连接。当客户端发送消息时,服务器会将消息累加到会话上下文中,然后调用GPT-4 API获取响应,并将响应发送回客户端。

Next.js前端使用WebSocket API连接到服务器,并监听从服务器发送的消息。用户可以在输入框中输入消息,按回车键发送。

需要注意的是,这个示例没有考虑会话上下文的长度限制和清理机制,在实际使用中可能需要对此进行优化。

上次编辑于:
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度