From d0b256502ba9927e2e8d325b222bd54e0c57fac7 Mon Sep 17 00:00:00 2001 From: extio-de Date: Sun, 13 Jul 2025 10:33:17 +0200 Subject: [PATCH] Use netty client for Azure, remove proxy configuration --- README.md | 4 - .../lmlib/client/azureai/AzureAiClient.java | 79 ++++--------------- .../AzureAiClientAutoConfiguration.java | 19 +---- 3 files changed, 16 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 1e692bf..0b366a1 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,6 @@ Example profile: src/test/resources/llama3.3-70b-azure.properties com.azure azure-ai-inference - - com.squareup.okhttp3 - okhttp - com.knuddels jtokkit diff --git a/src/main/java/de/extio/lmlib/client/azureai/AzureAiClient.java b/src/main/java/de/extio/lmlib/client/azureai/AzureAiClient.java index f625ab7..dcdbfea 100755 --- a/src/main/java/de/extio/lmlib/client/azureai/AzureAiClient.java +++ b/src/main/java/de/extio/lmlib/client/azureai/AzureAiClient.java @@ -1,8 +1,6 @@ package de.extio.lmlib.client.azureai; import java.math.BigDecimal; -import java.net.InetSocketAddress; -import java.net.Proxy; import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayDeque; @@ -11,6 +9,7 @@ import java.util.Deque; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; @@ -28,7 +27,7 @@ import com.azure.ai.inference.models.ChatRequestUserMessage; import com.azure.ai.inference.models.CompletionsFinishReason; import com.azure.core.credential.AzureKeyCredential; import com.azure.core.http.HttpClient; -import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder; +import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; import com.azure.core.http.policy.ExponentialBackoffOptions; import com.azure.core.http.policy.RetryOptions; @@ -43,13 +42,9 @@ import de.extio.lmlib.profile.ModelProfile; import de.extio.lmlib.profile.ModelProfile.ModelProvider; import de.extio.lmlib.profile.ModelProfileService; import de.extio.lmlib.token.Tokenizer; -import okhttp3.Authenticator; -import okhttp3.Challenge; -import okhttp3.Credentials; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.Route; +import io.netty.channel.ChannelOption; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; public final class AzureAiClient implements Client { @@ -65,24 +60,9 @@ public final class AzureAiClient implements Client { private final Tokenizer tokenizer; - private final boolean proxyEnabled; - - private final String proxyHost; - - private final int proxyPort; - - private final String proxyUser; - - private final String proxyPassword; - - AzureAiClient(final ModelProfileService modelProfileService, final Tokenizer tokenizer, final boolean proxyEnabled, final String proxyHost, final int proxyPort, final String proxyUser, final String proxyPassword) { + AzureAiClient(final ModelProfileService modelProfileService, final Tokenizer tokenizer) { this.modelProfileService = modelProfileService; this.tokenizer = tokenizer; - this.proxyEnabled = proxyEnabled; - this.proxyHost = proxyHost; - this.proxyPort = proxyPort; - this.proxyUser = proxyUser; - this.proxyPassword = proxyPassword; } @Override @@ -109,7 +89,7 @@ public final class AzureAiClient implements Client { return this.requestCompletions(chat, modelCategory, modelProfile); } - + @Override public Completion streamConversation(final ModelCategory modelCategory, final Conversation conversation, final Consumer chunkConsumer) { throw new UnsupportedOperationException("Not implemented yet"); @@ -242,44 +222,13 @@ public final class AzureAiClient implements Client { return false; }); - final OkHttpClient.Builder nativeOkHttpClientBuilder = new OkHttpClient.Builder(); + final reactor.netty.http.client.HttpClient httpClient = reactor.netty.http.client.HttpClient.create() + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECT_TIMEOUT) + .responseTimeout(Duration.ofMillis(TIMEOUT)) + .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(TIMEOUT, TimeUnit.MILLISECONDS)).addHandlerLast(new WriteTimeoutHandler(TIMEOUT, TimeUnit.MILLISECONDS))); - if (this.proxyEnabled) { - LOGGER.info("Proxy is enabled. Configuring proxy settings for host: {} port: {} user: {}", this.proxyHost, this.proxyPort, this.proxyUser); - - final Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.proxyHost, this.proxyPort)); - nativeOkHttpClientBuilder.proxy(proxy); - - if (this.proxyUser != null && this.proxyPassword != null) { - final Authenticator proxyAuthenticator = new Authenticator() { - - @Override - public Request authenticate(final Route route, final Response response) { - for (final Challenge challenge : response.challenges()) { - if (challenge.scheme().equalsIgnoreCase("OkHttp-Preemptive")) { - final String credential = Credentials.basic(proxyUser, proxyPassword); - return response.request().newBuilder() - .header("Proxy-Authorization", credential) - .build(); - } - } - return null; - } - }; - nativeOkHttpClientBuilder.proxyAuthenticator(proxyAuthenticator); - } - else { - LOGGER.warn("Proxy user or password is not set. Skipping proxy authentication."); - } - } - else { - LOGGER.info("Proxy is not enabled. Skipping proxy configuration."); - } - - final OkHttpClient nativeOkHttpClient = nativeOkHttpClientBuilder.build(); - final OkHttpAsyncHttpClientBuilder okHttpClientBuilder = new OkHttpAsyncHttpClientBuilder(nativeOkHttpClient); - final HttpClient okHttpClient = okHttpClientBuilder - .connectionTimeout(Duration.ofMillis(CONNECT_TIMEOUT)) + final NettyAsyncHttpClientBuilder azureHttpClientBuilder = new NettyAsyncHttpClientBuilder(httpClient); + final HttpClient azureHttpClient = azureHttpClientBuilder .readTimeout(Duration.ofMillis(TIMEOUT)) .responseTimeout(Duration.ofMillis(TIMEOUT)) .writeTimeout(Duration.ofMillis(TIMEOUT)) @@ -289,7 +238,7 @@ public final class AzureAiClient implements Client { .credential(new AzureKeyCredential(modelProfile.apiKey())) .endpoint(modelProfile.url()) .retryOptions(retryOptions) - .httpClient(okHttpClient) + .httpClient(azureHttpClient) .buildClient(); return chatCompletionsClient; }); diff --git a/src/main/java/de/extio/lmlib/client/azureai/AzureAiClientAutoConfiguration.java b/src/main/java/de/extio/lmlib/client/azureai/AzureAiClientAutoConfiguration.java index 1238cdb..b7828e8 100755 --- a/src/main/java/de/extio/lmlib/client/azureai/AzureAiClientAutoConfiguration.java +++ b/src/main/java/de/extio/lmlib/client/azureai/AzureAiClientAutoConfiguration.java @@ -9,27 +9,12 @@ import de.extio.lmlib.profile.ModelProfileService; import de.extio.lmlib.token.Tokenizer; @AutoConfiguration -@ConditionalOnClass(name = {"com.azure.ai.inference.ChatCompletionsClient", "okhttp3.OkHttpClient" }) +@ConditionalOnClass(name = {"com.azure.ai.inference.ChatCompletionsClient" }) public class AzureAiClientAutoConfiguration { - @Value("${extproxy.enabled:false}") - private boolean proxyEnabled; - - @Value("${extproxy.host:}") - private String proxyHost; - - @Value("${extproxy.port:0}") - private int proxyPort; - - @Value("${extproxy.username:}") - private String proxyUser; - - @Value("${extproxy.password:}") - private String proxyPassword; - @Bean AzureAiClient azureAiClient(final ModelProfileService modelProfileService, final Tokenizer tokenizer) { - return new AzureAiClient(modelProfileService, tokenizer, this.proxyEnabled, this.proxyHost, this.proxyPort, this.proxyUser, this.proxyPassword); + return new AzureAiClient(modelProfileService, tokenizer); } }