Browse Source

core-ai add chatEndpoint api

deason 1 month ago
parent
commit
701479a7c7

+ 35 - 4
src/main/java/com/qmth/ops/api/controller/ai/LlmController.java

@@ -3,6 +3,7 @@ package com.qmth.ops.api.controller.ai;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.core.ai.model.AiConstants;
 import com.qmth.boot.core.ai.model.llm.*;
+import com.qmth.boot.core.ai.model.llm.endpoint.ChatEndpoint;
 import com.qmth.boot.core.exception.ForbiddenException;
 import com.qmth.boot.core.exception.NotFoundException;
 import com.qmth.boot.tools.freemarker.FreemarkerUtil;
@@ -32,10 +33,39 @@ public class LlmController {
     @Resource
     private LlmPromptTemplateService llmPromptTemplateService;
 
+    @PostMapping(AiConstants.LLM_CHAT_ENDPOINT_PATH)
+    public ChatEndpoint chatEndpoint(@RequestAttribute AccessOrg accessOrg,
+                                     @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type,
+                                     @RequestBody Object param) throws Exception {
+        LlmOrgConfig config = llmOrgConfigService.findByOrgAndAppType(accessOrg.getOrg().getId(), type);
+        if (config == null || config.getLeftCount() <= 0) {
+            throw new ForbiddenException(
+                    "Chat api is disabled or exhausted for org=" + accessOrg.getOrg().getCode() + ", app_type=" + type);
+        }
+        LlmPromptTemplate llmPromptTemplate = llmPromptTemplateService.findById(config.getPromptId());
+        if (llmPromptTemplate == null) {
+            throw new NotFoundException(
+                    "Chat prompt template not found for app_type=" + type + ", modelId=" + config.getModelId());
+        }
+        ChatRequest request = new ChatRequest();
+        String systemMessage = FreemarkerUtil.getValue(llmPromptTemplate.getSystem(), param, null);
+        String userMessage = FreemarkerUtil.getValue(llmPromptTemplate.getUser(), param, null);
+        if (StringUtils.isNotBlank(systemMessage)) {
+            request.addMessage(ChatRole.system, systemMessage);
+        }
+        if (StringUtils.isNotBlank(userMessage)) {
+            request.addMessage(ChatRole.user, userMessage);
+        }
+        request.setStream(true);//todo
+
+        return llmClientService.chatEndpoint(request, config.getModelId(), type);
+    }
+
+
     @PostMapping(AiConstants.LLM_CHAT_PATH)
     public ChatResult chat(@RequestAttribute AccessOrg accessOrg,
-            @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type,
-            @RequestBody @Validated ChatRequest request) throws Exception {
+                           @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type,
+                           @RequestBody @Validated ChatRequest request) throws Exception {
         LlmOrgConfig config = llmOrgConfigService.findByOrgAndAppType(accessOrg.getOrg().getId(), type);
         if (config == null || config.getLeftCount() <= 0) {
             throw new ForbiddenException(
@@ -76,7 +106,7 @@ public class LlmController {
 
     @PostMapping(AiConstants.LLM_BALANCE_PATH)
     public LlmAppBalance balance(@RequestAttribute AccessOrg accessOrg,
-            @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type) {
+                                 @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type) {
         LlmAppBalance balance = new LlmAppBalance();
         LlmOrgConfig config = llmOrgConfigService.findByOrgAndAppType(accessOrg.getOrg().getId(), type);
         if (config != null) {
@@ -88,7 +118,7 @@ public class LlmController {
 
     @PostMapping(AiConstants.LLM_PROMPT_TEMPLATE_PATH)
     public PromptTemplate getPromptTemplate(@RequestAttribute AccessOrg accessOrg,
-            @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type) {
+                                            @RequestHeader(AiConstants.LLM_APP_TYPE) LlmAppType type) {
         PromptTemplate template = new PromptTemplate();
         LlmOrgConfig config = llmOrgConfigService.findByOrgAndAppType(accessOrg.getOrg().getId(), type);
         if (config != null) {
@@ -100,4 +130,5 @@ public class LlmController {
         }
         return template;
     }
+
 }

+ 3 - 0
src/main/java/com/qmth/ops/biz/ai/client/ChatApiClient.java

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.qmth.boot.core.ai.model.llm.ChatRequest;
 import com.qmth.boot.core.ai.model.llm.ChatResult;
 import com.qmth.boot.core.ai.model.llm.LlmAppType;
+import com.qmth.boot.core.ai.model.llm.endpoint.ChatEndpoint;
 import com.qmth.boot.core.rateLimit.service.RateLimiter;
 import com.qmth.boot.core.rateLimit.service.impl.MemoryRateLimiter;
 import com.qmth.ops.biz.ai.exception.ChatRateLimitExceeded;
@@ -44,6 +45,8 @@ public abstract class ChatApiClient {
         return config;
     }
 
+    public abstract ChatEndpoint buildEndpoint(ChatRequest request, LlmAppType appType);
+
     protected abstract Headers buildHeader(Headers.Builder headerBuilder, LlmAppType appType);
 
     protected abstract Object buildRequest(ChatRequest request, LlmAppType appType);

+ 36 - 6
src/main/java/com/qmth/ops/biz/ai/client/aliyun/llm/AliyunChatClient.java

@@ -1,10 +1,12 @@
 package com.qmth.ops.biz.ai.client.aliyun.llm;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.qmth.boot.core.ai.model.llm.ChatRequest;
 import com.qmth.boot.core.ai.model.llm.ChatResult;
 import com.qmth.boot.core.ai.model.llm.ChatRole;
 import com.qmth.boot.core.ai.model.llm.LlmAppType;
+import com.qmth.boot.core.ai.model.llm.endpoint.ChatEndpoint;
 import com.qmth.boot.core.exception.ReentrantException;
 import com.qmth.boot.core.exception.StatusException;
 import com.qmth.ops.biz.ai.client.ChatApiClient;
@@ -14,6 +16,8 @@ import com.qmth.ops.biz.ai.exception.ChatRequestError;
 import okhttp3.Headers;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 public class AliyunChatClient extends ChatApiClient {
 
@@ -25,6 +29,31 @@ public class AliyunChatClient extends ChatApiClient {
         super(config);
     }
 
+    @Override
+    public ChatEndpoint buildEndpoint(ChatRequest request, LlmAppType appType) {
+        ChatEndpoint endpoint = new ChatEndpoint();
+        // endpoint.setUrl(getConfig().getUrl());//todo
+        endpoint.setUrl("https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions");
+        endpoint.setMethod("POST");
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put(AUTH_HEADER_NAME, AUTH_HEADER_VALUE + getConfig().getSecret());
+        headers.put("X-DashScope-SSE", "enable");
+        endpoint.setHeaders(headers);
+
+        request.setModel(getConfig().getModel());
+
+        byte[] json;
+        try {
+            json = new ObjectMapper().writeValueAsBytes(request);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+        endpoint.setRequestBody(json);
+
+        return endpoint;
+    }
+
     @Override
     protected Headers buildHeader(Headers.Builder headerBuilder, LlmAppType appType) {
         headerBuilder.add(AUTH_HEADER_NAME, AUTH_HEADER_VALUE + getConfig().getSecret());
@@ -60,12 +89,12 @@ public class AliyunChatClient extends ChatApiClient {
             }
         }
         switch (statusCode) {
-        case 400:
-            throw new ChatRequestError(error != null ? error.getMessage() : "chat request error");
-        case 429:
-            throw new ReentrantException(error != null ? error.getMessage() : "chat model rate limit exceeded");
-        default:
-            throw new StatusException(error != null ? error.getMessage() : "chat model error");
+            case 400:
+                throw new ChatRequestError(error != null ? error.getMessage() : "chat request error");
+            case 429:
+                throw new ReentrantException(error != null ? error.getMessage() : "chat model rate limit exceeded");
+            default:
+                throw new StatusException(error != null ? error.getMessage() : "chat model error");
         }
     }
 
@@ -85,4 +114,5 @@ public class AliyunChatClient extends ChatApiClient {
         System.out.println(
                 new ObjectMapper().writeValueAsString(client.call(request, LlmAppType.AUTO_GENERATE_QUESTION)));
     }
+
 }

+ 8 - 0
src/main/java/com/qmth/ops/biz/ai/client/azure/llm/AzureChatClient.java

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.qmth.boot.core.ai.model.llm.ChatRequest;
 import com.qmth.boot.core.ai.model.llm.ChatResult;
 import com.qmth.boot.core.ai.model.llm.LlmAppType;
+import com.qmth.boot.core.ai.model.llm.endpoint.ChatEndpoint;
 import com.qmth.boot.core.exception.NotFoundException;
 import com.qmth.boot.core.exception.StatusException;
 import com.qmth.ops.biz.ai.client.ChatApiClient;
@@ -25,6 +26,13 @@ public class AzureChatClient extends ChatApiClient {
         config.setUrl(config.getUrl().replace(MODEL_PLACEHOLDER, config.getModel()));
     }
 
+    @Override
+    public ChatEndpoint buildEndpoint(ChatRequest request, LlmAppType appType) {
+        ChatEndpoint endpoint = new ChatEndpoint();
+        // todo
+        return endpoint;
+    }
+
     @Override
     protected Headers buildHeader(Headers.Builder headerBuilder, LlmAppType appType) {
         return headerBuilder.add(AUTH_HEADER_NAME, getConfig().getSecret()).build();

+ 11 - 0
src/main/java/com/qmth/ops/biz/service/LlmClientService.java

@@ -3,6 +3,7 @@ package com.qmth.ops.biz.service;
 import com.qmth.boot.core.ai.model.llm.ChatRequest;
 import com.qmth.boot.core.ai.model.llm.ChatResult;
 import com.qmth.boot.core.ai.model.llm.LlmAppType;
+import com.qmth.boot.core.ai.model.llm.endpoint.ChatEndpoint;
 import com.qmth.ops.biz.ai.client.ChatApiClient;
 import com.qmth.ops.biz.ai.client.ChatApiConfig;
 import com.qmth.ops.biz.ai.exception.ChatClientNotFound;
@@ -73,4 +74,14 @@ public class LlmClientService {
         }
         return client.call(request, appType);
     }
+
+    public ChatEndpoint chatEndpoint(ChatRequest request, Long modelId, LlmAppType appType) throws Exception {
+        ChatApiClient client = chatApiClientMap.get(modelId);
+        if (client == null) {
+            throw new ChatClientNotFound(modelId);
+        }
+
+        return client.buildEndpoint(request, appType);
+    }
+
 }