Aias00 commented on code in PR #6145: URL: https://github.com/apache/shenyu/pull/6145#discussion_r2371305428
########## shenyu-spring-boot-starter/shenyu-spring-boot-starter-sync-data-center/shenyu-spring-boot-starter-sync-data-websocket/src/main/java/org/apache/shenyu/springboot/starter/sync/data/websocket/WebsocketSyncDataConfiguration.java: ########## @@ -38,41 +39,49 @@ import java.util.Collections; import java.util.List; -/** - * Websocket sync data configuration for spring boot. - */ +/** Websocket sync data configuration for spring boot. */ @Configuration @ConditionalOnClass(WebsocketSyncDataService.class) @ConditionalOnProperty(prefix = "shenyu.sync.websocket", name = "urls") public class WebsocketSyncDataConfiguration { - private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketSyncDataConfiguration.class); + private static final Logger LOGGER = + LoggerFactory.getLogger(WebsocketSyncDataConfiguration.class); /** * Websocket sync data service. * - * @param websocketConfig the websocket config - * @param shenyuConfig the shenyu config - * @param pluginSubscriber the plugin subscriber - * @param metaSubscribers the meta subscribers - * @param authSubscribers the auth subscribers - * @param proxySelectorSubscribers the proxySelector subscribers + * @param websocketConfig the websocket config Review Comment: why remove the indentation? ########## shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-ai-proxy/src/main/java/org/apache/shenyu/springboot/starter/plugin/ai/proxy/AiProxyPluginConfiguration.java: ########## @@ -17,40 +17,108 @@ package org.apache.shenyu.springboot.starter.plugin.ai.proxy; -import org.apache.shenyu.plugin.ai.proxy.AiProxyPlugin; -import org.apache.shenyu.plugin.ai.proxy.handler.AiProxyPluginHandler; +import org.apache.shenyu.plugin.ai.common.spring.ai.AiModelFactory; +import org.apache.shenyu.plugin.ai.common.spring.ai.factory.DeepSeekModelFactory; +import org.apache.shenyu.plugin.ai.common.spring.ai.factory.OpenAiModelFactory; +import org.apache.shenyu.plugin.ai.common.spring.ai.registry.AiModelFactoryRegistry; +import org.apache.shenyu.plugin.ai.proxy.enhanced.AiProxyPlugin; +import org.apache.shenyu.plugin.ai.proxy.enhanced.cache.ChatClientCache; +import org.apache.shenyu.plugin.ai.proxy.enhanced.handler.AiProxyPluginHandler; +import org.apache.shenyu.plugin.ai.proxy.enhanced.service.AiProxyConfigService; +import org.apache.shenyu.plugin.ai.proxy.enhanced.service.AiProxyExecutorService; +import org.apache.shenyu.plugin.ai.proxy.enhanced.subscriber.CommonAiProxyApiKeyDataSubscriber; import org.apache.shenyu.plugin.api.ShenyuPlugin; +import org.apache.shenyu.sync.data.api.AiProxyApiKeyDataSubscriber; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.codec.ServerCodecConfigurer; -/** - * The type ai proxy plugin configuration. - */ +import java.util.List; + +/** The type ai proxy plugin configuration. */ Review Comment: not change the format ########## shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-proxy-enhanced/src/main/java/org/apache/shenyu/plugin/ai/proxy/enhanced/AiProxyPlugin.java: ########## @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.plugin.ai.proxy.enhanced; + +import org.apache.shenyu.common.constant.Constants; +import org.apache.shenyu.common.dto.RuleData; +import org.apache.shenyu.common.dto.SelectorData; +import org.apache.shenyu.common.dto.convert.rule.AiProxyHandle; +import org.apache.shenyu.common.enums.AiModelProviderEnum; +import org.apache.shenyu.common.enums.PluginEnum; +import org.apache.shenyu.common.utils.JsonUtils; +import org.apache.shenyu.plugin.ai.common.config.AiCommonConfig; +import org.apache.shenyu.plugin.ai.common.spring.ai.registry.AiModelFactoryRegistry; +import org.apache.shenyu.plugin.ai.proxy.enhanced.cache.AiProxyApiKeyCache; +import org.apache.shenyu.plugin.ai.proxy.enhanced.cache.ChatClientCache; +import org.apache.shenyu.plugin.ai.proxy.enhanced.handler.AiProxyPluginHandler; +import org.apache.shenyu.plugin.ai.proxy.enhanced.service.AiProxyConfigService; +import org.apache.shenyu.plugin.ai.proxy.enhanced.service.AiProxyExecutorService; +import org.apache.shenyu.plugin.api.ShenyuPluginChain; +import org.apache.shenyu.plugin.api.utils.WebFluxResultUtils; +import org.apache.shenyu.plugin.base.AbstractShenyuPlugin; +import org.apache.shenyu.plugin.base.utils.CacheKeyUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.Optional; + +/** AI proxy plugin. This plugin is used to proxy requests to AI services. */ +public class AiProxyPlugin extends AbstractShenyuPlugin { + + private static final Logger LOG = LoggerFactory.getLogger(AiProxyPlugin.class); + + private final AiModelFactoryRegistry aiModelFactoryRegistry; + + private final AiProxyConfigService aiProxyConfigService; + + private final AiProxyExecutorService aiProxyExecutorService; + + private final ChatClientCache chatClientCache; + + private final AiProxyPluginHandler aiProxyPluginHandler; + + public AiProxyPlugin( + final AiModelFactoryRegistry aiModelFactoryRegistry, + final AiProxyConfigService aiProxyConfigService, + final AiProxyExecutorService aiProxyExecutorService, + final ChatClientCache chatClientCache, + final AiProxyPluginHandler aiProxyPluginHandler) { + this.aiModelFactoryRegistry = aiModelFactoryRegistry; + this.aiProxyConfigService = aiProxyConfigService; + this.aiProxyExecutorService = aiProxyExecutorService; + this.chatClientCache = chatClientCache; + this.aiProxyPluginHandler = aiProxyPluginHandler; + } + + @Override + protected Mono<Void> doExecute( + final ServerWebExchange exchange, + final ShenyuPluginChain chain, + final SelectorData selector, + final RuleData rule) { + final AiProxyHandle selectorHandle = + aiProxyPluginHandler + .getSelectorCachedHandle() + .obtainHandle( + CacheKeyUtils.INST.getKey( + selector.getId(), Constants.DEFAULT_RULE)); + + return DataBufferUtils.join(exchange.getRequest().getBody()) + .flatMap(dataBuffer -> { + final String requestBody = dataBuffer.toString(StandardCharsets.UTF_8); + DataBufferUtils.release(dataBuffer); + + final AiCommonConfig primaryConfig = + aiProxyConfigService.resolvePrimaryConfig(selectorHandle); + + // override apiKey by proxy key if provided in header + final HttpHeaders headers = exchange.getRequest().getHeaders(); + final String proxyApiKey = headers.getFirst("X-API-KEY"); Review Comment: use constant ########## shenyu-admin/src/main/java/org/apache/shenyu/admin/service/support/AiProxyRealKeyResolver.java: ########## @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.admin.service.support; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.apache.shenyu.admin.mapper.SelectorMapper; +import org.apache.shenyu.admin.model.entity.SelectorDO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; + +/** + * AiProxyRealKeyResolver resolves real api key from selector handle JSON. + * Event-driven invalidation, single-flight resolve, no time TTL by default. + */ +@Component +public class AiProxyRealKeyResolver { Review Comment: I think this class is useless -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@shenyu.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org