24日
...
24日
服务端流式推送信息道客户端
除了 WebSocket
,还可以使用 Server-Sent Events
提示
以下是一个使用java后端调用GPT4的api,将返回信息使用text/event-stream,流式传输到基于nextjs实现的网页中的Demo
- 后端Java服务
- 使用Java的HTTP客户端库(如Apache HttpClient或OkHttp)向OpenAI的GPT-4 API发送请求
- 在响应头中设置Content-Type为text/event-stream
- 使用ServletOutputStream或其他流式输出将OpenAI API返回的数据流式传输到前端
- 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