Explorar el Código

[core-ai]新增baseUrl接口前缀地址参数,不传默认取配置文件的值

deason hace 1 mes
padre
commit
28e21e4089

+ 14 - 7
core-ai/src/main/java/com/qmth/boot/core/ai/client/LlmApiClient.java

@@ -19,46 +19,53 @@ public interface LlmApiClient {
     /**
      * 大模型chat类型请求
      *
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用机构AK构造Secret类型签名
      * @param type      大模型应用类型
      * @param request   标准chat请求对象
      * @return
      */
     @POST(AiConstants.LLM_CHAT_PATH)
-    ChatResult chat(@Tag SignatureInfo signature, @Header(AiConstants.LLM_APP_TYPE_HEADER) LlmAppType type,
-            @Body ChatRequest request);
+    ChatResult chat(@Header(AiConstants.BASE_URL) String baseUrl, @Tag SignatureInfo signature,
+                    @Header(AiConstants.LLM_APP_TYPE) LlmAppType type,
+                    @Body ChatRequest request);
 
     /**
      * 基于Prompt模版的大模型chat类型请求
      *
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用机构AK构造Secret类型签名
      * @param type      大模型应用类型
      * @param param     模版变量
      * @return
      */
     @POST(AiConstants.LLM_CHAT_TEMPLATE_PATH)
-    ChatResult chatTemplate(@Tag SignatureInfo signature, @Header(AiConstants.LLM_APP_TYPE_HEADER) LlmAppType type,
-            @Body Object param);
+    ChatResult chatTemplate(@Header(AiConstants.BASE_URL) String baseUrl, @Tag SignatureInfo signature,
+                            @Header(AiConstants.LLM_APP_TYPE) LlmAppType type,
+                            @Body Object param);
 
     /**
      * 大模型接口余额查询
      *
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用机构AK构造Secret类型签名
      * @param type      大模型应用类型
      * @return
      */
     @POST(AiConstants.LLM_BALANCE_PATH)
-    LlmAppBalance getBalance(@Tag SignatureInfo signature, @Header(AiConstants.LLM_APP_TYPE_HEADER) LlmAppType type);
+    LlmAppBalance getBalance(@Header(AiConstants.BASE_URL) String baseUrl, @Tag SignatureInfo signature,
+                             @Header(AiConstants.LLM_APP_TYPE) LlmAppType type);
 
     /**
      * 大模型提示词模版获取
      *
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用机构AK构造Secret类型签名
      * @param type      大模型应用类型
      * @return
      */
     @POST(AiConstants.LLM_PROMPT_TEMPLATE_PATH)
-    PromptTemplate getPromptTemplate(@Tag SignatureInfo signature,
-            @Header(AiConstants.LLM_APP_TYPE_HEADER) LlmAppType type);
+    PromptTemplate getPromptTemplate(@Header(AiConstants.BASE_URL) String baseUrl, @Tag SignatureInfo signature,
+                                     @Header(AiConstants.LLM_APP_TYPE) LlmAppType type);
 
 }

+ 3 - 1
core-ai/src/main/java/com/qmth/boot/core/ai/client/OcrApiClient.java

@@ -17,6 +17,7 @@ public interface OcrApiClient {
     /**
      * OCR识别图片
      *
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用机构AK构造Secret类型签名
      * @param type      识别类型
      * @param image     待识别图片
@@ -24,6 +25,7 @@ public interface OcrApiClient {
      */
     @Multipart
     @POST(AiConstants.OCR_IMAGE_PATH)
-    String forImage(@Tag SignatureInfo signature, @Query("type") OcrType type, @Part MultipartBody.Part image);
+    String forImage(@Header(AiConstants.BASE_URL) String baseUrl, @Tag SignatureInfo signature,
+                    @Query("type") OcrType type, @Part MultipartBody.Part image);
 
 }

+ 4 - 1
core-ai/src/main/java/com/qmth/boot/core/ai/model/AiConstants.java

@@ -2,7 +2,9 @@ package com.qmth.boot.core.ai.model;
 
 public interface AiConstants {
 
-    String LLM_APP_TYPE_HEADER = "llm_app_type";
+    String BASE_URL = "base_url";
+
+    String LLM_APP_TYPE = "llm_app_type";
 
     String API_PREFIX = "/api/ai";
 
@@ -15,4 +17,5 @@ public interface AiConstants {
     String LLM_PROMPT_TEMPLATE_PATH = API_PREFIX + "/llm/prompt_template";
 
     String OCR_IMAGE_PATH = API_PREFIX + "/ocr/image";
+
 }

+ 16 - 12
core-ai/src/main/java/com/qmth/boot/core/ai/service/AiService.java

@@ -38,23 +38,25 @@ public class AiService {
     /**
      * 获取当前机构大模型接口调用次数余额
      *
-     * @param appType   大模型接口应用类型
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用当前机构AK作为鉴权信息
+     * @param appType   大模型接口应用类型
      * @return 调用次数余额
      */
-    public LlmAppBalance getLlmBalance(@NotNull LlmAppType appType, @NotNull SignatureInfo signature) {
-        return llmApiClient.getBalance(signature, appType);
+    public LlmAppBalance getLlmBalance(String baseUrl, @NotNull SignatureInfo signature, @NotNull LlmAppType appType) {
+        return llmApiClient.getBalance(baseUrl, signature, appType);
     }
 
     /**
      * 使用自定义提示词进行自动命题
      *
-     * @param request   大模型通用Chat请求
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用当前机构AK作为鉴权信息
+     * @param request   大模型通用Chat请求
      * @return 大模型返回的文本集合
      */
-    public List<String> autoGenerateQuestion(@NotNull ChatRequest request, @NotNull SignatureInfo signature) {
-        ChatResult result = llmApiClient.chat(signature, LlmAppType.AUTO_GENERATE_QUESTION, request);
+    public List<String> autoGenerateQuestion(String baseUrl, @NotNull SignatureInfo signature, @NotNull ChatRequest request) {
+        ChatResult result = llmApiClient.chat(baseUrl, signature, LlmAppType.AUTO_GENERATE_QUESTION, request);
         return result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                 .map(choice -> choice.getMessage().getContent()).collect(Collectors.toList());
     }
@@ -62,12 +64,13 @@ public class AiService {
     /**
      * 使用预设模版进行自动命题
      *
-     * @param param     基于预设模版的参数对象,可以使用Map或自定义Object
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用当前机构AK作为鉴权信息
+     * @param param     基于预设模版的参数对象,可以使用Map或自定义Object
      * @return 大模型返回的文本集合
      */
-    public List<String> autoGenerateQuestion(@NotNull Object param, @NotNull SignatureInfo signature) {
-        ChatResult result = llmApiClient.chatTemplate(signature, LlmAppType.AUTO_GENERATE_QUESTION, param);
+    public List<String> autoGenerateQuestion(String baseUrl, @NotNull SignatureInfo signature, @NotNull Object param) {
+        ChatResult result = llmApiClient.chatTemplate(baseUrl, signature, LlmAppType.AUTO_GENERATE_QUESTION, param);
         return result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                 .map(choice -> choice.getMessage().getContent()).collect(Collectors.toList());
     }
@@ -75,11 +78,12 @@ public class AiService {
     /**
      * 使用预设模版进行自动判分,考生作答为文本
      *
-     * @param request   自动判分请求参数
+     * @param baseUrl   接口前缀地址,默认取配置文件的值(选填)
      * @param signature 使用当前机构AK作为鉴权信息
+     * @param request   自动判分请求参数
      * @return 判分结果;null表示无法获取判分结果
      */
-    public AutoScoreResult autoScore(@NotNull @Validated AutoScoreRequest request, @NotNull SignatureInfo signature) {
+    public AutoScoreResult autoScore(String baseUrl, @NotNull SignatureInfo signature, @NotNull @Validated AutoScoreRequest request) {
         if (StringUtils.isBlank(request.getSubjectName())) {
             throw new IllegalArgumentException("科目名称不能为空");
         }
@@ -102,7 +106,7 @@ public class AiService {
             throw new IllegalArgumentException("最小间隔分必须大于0");
         }
 
-        ChatResult result = llmApiClient.chatTemplate(signature, LlmAppType.AUTO_SCORE, request);
+        ChatResult result = llmApiClient.chatTemplate(baseUrl, signature, LlmAppType.AUTO_SCORE, request);
         String text = result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                 .map(choice -> choice.getMessage().getContent()).findFirst().orElse("");
 

+ 26 - 7
core-retrofit/src/main/java/com/qmth/boot/core/retrofit/interceptor/SignatureInterceptor.java

@@ -6,6 +6,9 @@ import com.qmth.boot.tools.signature.SignatureEntity;
 import okhttp3.Interceptor;
 import okhttp3.Request;
 import okhttp3.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 
@@ -14,6 +17,10 @@ import java.io.IOException;
  */
 public class SignatureInterceptor implements Interceptor {
 
+    private static final Logger log = LoggerFactory.getLogger(SignatureInterceptor.class);
+
+    private static final String BASE_URL = "base_url";
+
     private static final String HEADER_KEY_AUTHORIZATION = "authorization";
 
     private static final String HEADER_KEY_TIME = "time";
@@ -27,19 +34,31 @@ public class SignatureInterceptor implements Interceptor {
     @Override
     public Response intercept(Chain chain) throws IOException {
         Request request = chain.request();
+        String path = request.url().uri().getPath();
+        String queryParams = request.url().query();
+        queryParams = queryParams != null ? "?" + queryParams : "";
+
+        Request.Builder builder = request.newBuilder();
+        String baseUrl = request.header(BASE_URL);
+        if (StringUtils.isNotBlank(baseUrl)) {
+            log.debug("oldUrl:{} newUrl:{}{}{}", request.url(), baseUrl, path, queryParams);
+            builder.url(baseUrl + path + queryParams);
+        }
+
         SignatureProvider provider = getSignatureInfo(request);
         if (provider == null) {
             provider = this.provider;
         }
         if (provider != null) {
             long time = System.currentTimeMillis();
-            String signature = SignatureEntity
-                    .build(provider.getType(), request.method(), request.url().uri().getPath(), time,
-                            provider.getIdentity(), provider.getSecret());
-            return chain.proceed(
-                    request.newBuilder().removeHeader(HEADER_KEY_TIME).removeHeader(HEADER_KEY_AUTHORIZATION)
-                            .addHeader(HEADER_KEY_TIME, String.valueOf(time))
-                            .addHeader(HEADER_KEY_AUTHORIZATION, signature).build());
+            String signature = SignatureEntity.build(provider.getType(), request.method(), path, time,
+                    provider.getIdentity(), provider.getSecret());
+            builder.removeHeader(HEADER_KEY_TIME).removeHeader(HEADER_KEY_AUTHORIZATION)
+                    .addHeader(HEADER_KEY_TIME, String.valueOf(time)).addHeader(HEADER_KEY_AUTHORIZATION, signature);
+        }
+
+        if (StringUtils.isNotBlank(baseUrl) || provider != null) {
+            return chain.proceed(builder.build());
         } else {
             return chain.proceed(request);
         }