OpenAI
chat/completions
API 支持通过传递 stream=true
的流响应。这使得响应能够以数据块的形式出现,而不是一个完整的响应。这将类似于 ChatGPT 输出答案的方式。
我看到不同语言或技术堆栈的类似问题(如here)。但是我找不到一个完整的例子来说明如何使用
OkHttp
客户端在 java(或 kotlin)中实现它。
如何以流的形式获取OpenAI的API响应? 谢谢!
我修改了代码,现在ChatGPT完全可以通过Java在控制台实现流式对话了
import com.theokanning.openai.completion.chat.*;
import com.theokanning.openai.service.OpenAiService;
import io.reactivex.Flowable;
import java.util.*;
public class Starter {
// Create a new OpenAiService instance with the given API key
public static OpenAiService service = new OpenAiService("Your API Token");
public static void main(String[] args) {
System.out.println("Streaming chat completion...");
Scanner scanner = new Scanner(System.in);
String userInput = scanner.nextLine();
// Create a list of ChatMessage objects
List<ChatMessage> message = new ArrayList<ChatMessage>();
message.add(new ChatMessage(ChatMessageRole.USER.value(), userInput));
// Create a ChatCompletionRequest object
ChatCompletionRequest chatCompletionRequest;
boolean running = true;
// Run the loop until the user enters "exit"
while (running) {
chatCompletionRequest = ChatCompletionRequest
.builder()
.model("gpt-3.5-turbo")
.messages(message)
.n(1)
.maxTokens(500)
.logitBias(Collections.emptyMap())
.build();
// Create a Flowable object to stream the chat completion
Flowable<ChatCompletionChunk> flowableResult = service.streamChatCompletion(chatCompletionRequest);
// Create a StringBuilder object to store the result
StringBuilder buffer = new StringBuilder();
// Subscribe to the Flowable object and print the result
flowableResult.subscribe(chunk -> {
chunk.getChoices().forEach(choice -> {
String result = choice.getMessage().getContent();
if (result != null) {
buffer.append(result);
System.out.print(choice.getMessage().getContent());
}
});
}, Throwable::printStackTrace, () -> System.out.println());
// Get the user input
userInput = scanner.nextLine();
// Add the user input to the list of ChatMessage objects
message.add(new ChatMessage(ChatMessageRole.SYSTEM.value(), buffer.toString()));
message.add(new ChatMessage(ChatMessageRole.USER.value(), userInput));
// Exit the loop if the user enters "exit"
if (userInput.equals("exit")) {
running = false;
}
}
scanner.close();
service.shutdownExecutor();
}
}
这是用 java 接收来自 ChatGPT 的流响应的 okhttp:
public static void okHttpEvent(SseEmitter emitter, String prompt, String openAiKey) {
Request request = new Request.Builder()
.url("https://{open-api-address}/v1/chat/stream/completions?q=" + prompt + "&eid=" + RequestContext.getRequestId())
.build();
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", "Bearer " + openAiKey)
.header("Accept", MediaType.TEXT_EVENT_STREAM.toString())
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
})
.connectTimeout(3, TimeUnit.MINUTES)
.readTimeout(3, TimeUnit.MINUTES)
.build();
RealEventSource realEventSource = new RealEventSource(request, new EventSourceListener() {
@Override
public void onOpen(EventSource eventSource, Response response) {
}
@Override
public void onEvent(EventSource eventSource, String id, String type, String data) {
try {
HttpUrl url = eventSource.request().url();
String reqId = url.queryParameter("eid");
SseChatService.getInstance().appendMsg(data, reqId);
emitter.send(data);
} catch (IOException e) {
emitter.completeWithError(e);
log.error("send sse to client error", e);
}
}
@Override
public void onClosed(EventSource eventSource) {
emitter.complete();
}
@Override
public void onFailure(EventSource eventSource, Throwable t, Response response) {
emitter.completeWithError(t);
log.error("event source failure", t);
}
});
realEventSource.connect(okHttpClient);
}