import com.alibaba.nacos.common.utils.JacksonUtils;
import com.theokanning.openai.completion.chat.ChatCompletionChunk;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.Disposable;
import reactor.core.publisher.FluxSink;
@Slf4j
public class OpenAiSubscriber implements Subscriber<String>, Disposable {
private final FluxSink<String> emitter;
private final StringBuilder stringBuilder;
private Subscription subscription;
public OpenAiSubscriber(FluxSink<String> emitter) {
this.emitter = emitter;
this.stringBuilder = new StringBuilder();
}
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
subscription.request(1);
}
@Override
public void onNext(String data) {
log.info("OpenAI返回数据:{}", data);
if ("[DONE]".equals(data)) {
log.info("OpenAI返回数据结束了");
subscription.request(1);
emitter.complete();
} else {
ChatCompletionChunk response = JacksonUtils.toObj(data, ChatCompletionChunk.class);
String content = response.getChoices().get(0).getMessage().getContent();
content = content == null ? "" : content;
emitter.next(content);
stringBuilder.append(content);
subscription.request(1);
}
}
@Override
public void onError(Throwable t) {
log.error("OpenAI返回数据异常:{}", t.getMessage());
emitter.error(t);
}
@Override
public void onComplete() {
log.info("OpenAI返回数据完成");
emitter.complete();
}
@Override
public void dispose() {
log.warn("OpenAI返回数据关闭");
emitter.complete();
}
}
@Bean
public OpenAiClient openAiClient(OpenAiProperties openAiProperties, ObjectMapper objectMapper) {
ObjectMapper newMapper = objectMapper.copy();
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder().codecs(configurer -> {
ClientCodecConfigurer.ClientDefaultCodecs defaultCodecs = configurer.defaultCodecs();
defaultCodecs.jackson2JsonEncoder(new Jackson2JsonEncoder(newMapper));
defaultCodecs.maxInMemorySize(-1);
}).build();
SslContext context = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(context)).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000).responseTimeout(Duration.ofMillis(5000)).
doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)));
WebClient client = WebClient.builder().baseUrl(openAiProperties.getProxyUrl()).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).
exchangeStrategies(exchangeStrategies).clientConnector(new ReactorClientHttpConnector(httpClient)).build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).blockTimeout(Duration.ofMillis(5000)).build();
return factory.createClient(OpenAiClient.class);
}