zyx vor 2 Jahren
Ursprung
Commit
977f2c13bd

+ 1 - 0
build.gradle

@@ -19,6 +19,7 @@ repositories {
 }
 
 dependencies {
+    implementation 'com.aliyun.openservices:aliyun-log-producer:0.3.11'
     implementation 'org.apache.httpcomponents.client5:httpclient5:5.2.1'
     implementation 'org.apache.httpcomponents.client5:httpclient5-fluent:5.2.1'
     implementation 'org.springframework.boot:spring-boot-starter-data-redis'

+ 1 - 1
src/main/java/com/sxtvs/chatgpt/ChatgptApplication.java → src/main/java/com/sxtvs/ChatgptApplication.java

@@ -1,4 +1,4 @@
-package com.sxtvs.chatgpt;
+package com.sxtvs;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;

+ 32 - 0
src/main/java/com/sxtvs/api/chatgpt/controller/ChatGptController.java

@@ -0,0 +1,32 @@
+package com.sxtvs.api.chatgpt.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.sxtvs.api.chatgpt.dto.CompletionsParamsDto;
+import com.sxtvs.api.chatgpt.dto.CompletionsRequestDto;
+import lombok.SneakyThrows;
+import org.apache.hc.client5.http.fluent.Request;
+import org.apache.hc.core5.http.ContentType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class ChatGptController {
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @SneakyThrows
+    @RequestMapping("completions")
+    public String completions(CompletionsRequestDto dto) {
+        var paramsDto = new CompletionsParamsDto(dto.getPrompt());
+        var response = Request.post("https://api.openai.com/v1/completions")
+                .setHeader("Authorization", "Bearer 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")
+                .bodyString(objectMapper.writeValueAsString(paramsDto), ContentType.APPLICATION_JSON)
+                .execute()
+                .returnContent()
+                .toString();
+        return response;
+    }
+
+}

+ 28 - 0
src/main/java/com/sxtvs/api/chatgpt/dto/CompletionsParamsDto.java

@@ -0,0 +1,28 @@
+package com.sxtvs.api.chatgpt.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@Data
+public class CompletionsParamsDto {
+
+    @JsonProperty("model")
+    private String model;
+    @JsonProperty("prompt")
+    private String prompt;
+    @JsonProperty("max_tokens")
+    private Integer maxTokens;
+    @JsonProperty("temperature")
+    private Integer temperature;
+    @JsonProperty("stream")
+    private Boolean stream;
+
+    public CompletionsParamsDto(String prompt) {
+        this.prompt = prompt;
+        this.model = "text-davinci-003";
+        this.maxTokens = 4000;
+        this.temperature = 1;
+    }
+}

+ 8 - 0
src/main/java/com/sxtvs/api/chatgpt/dto/CompletionsRequestDto.java

@@ -0,0 +1,8 @@
+package com.sxtvs.api.chatgpt.dto;
+
+import lombok.Data;
+
+@Data
+public class CompletionsRequestDto {
+    private String prompt;
+}

+ 0 - 31
src/main/java/com/sxtvs/chatgpt/api/chatgpt/controller/ChatGptController.java

@@ -1,31 +0,0 @@
-package com.sxtvs.chatgpt.api.chatgpt.controller;
-
-import lombok.SneakyThrows;
-import org.apache.hc.client5.http.fluent.Request;
-import org.apache.hc.core5.http.ContentType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class ChatGptController {
-
-    @SneakyThrows
-    @RequestMapping("hello")
-    public void hello() {
-        var response = Request.post("https://api.openai.com/v1/completions")
-                .setHeader("Authorization", "Bearer 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")
-                .bodyString("""
-                        {
-                          "model": "text-davinci-003",
-                          "prompt": "Say this is a test",
-                          "max_tokens": 7,
-                          "temperature": 0
-                        }
-                        """, ContentType.APPLICATION_JSON)
-                .execute()
-                .returnContent()
-                .toString();
-        System.out.println(response);
-    }
-
-}

+ 109 - 0
src/main/java/com/sxtvs/core/sls/AliyunLogger.java

@@ -0,0 +1,109 @@
+package com.sxtvs.core.sls;
+
+import com.aliyun.openservices.aliyun.log.producer.LogProducer;
+import com.aliyun.openservices.aliyun.log.producer.Producer;
+import com.aliyun.openservices.aliyun.log.producer.ProducerConfig;
+import com.aliyun.openservices.aliyun.log.producer.ProjectConfig;
+import com.aliyun.openservices.aliyun.log.producer.errors.ProducerException;
+import com.aliyun.openservices.log.common.LogItem;
+import jakarta.annotation.PostConstruct;
+import org.springframework.stereotype.Component;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@Component
+public class AliyunLogger {
+    private Producer producer;
+    private final String logStore = "java-log";
+    private final String project = "k8s-log-c4d23a31b8c6c4ed49e7fc1473dfd0c57";
+
+    @PostConstruct
+    public void init() {
+
+        ProducerConfig producerConfig = new ProducerConfig();
+        producerConfig.setBatchSizeThresholdInBytes(3 * 1024 * 1024);
+        producerConfig.setBatchCountThreshold(40960);
+
+        producer = new LogProducer(producerConfig);
+        producer.putProjectConfig(new ProjectConfig(project,
+                "cn-chengdu.log.aliyuncs.com",
+                "LTAI5tCb5r8efPipWaKSeCkE", "BsKtHRePUFBrfF9aA8b8sDTrox23cU"));
+
+        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
+    }
+
+    public void info(Object... kv) {
+        try {
+            LogItem item = log(kv);
+            item.PushBack("level", "info");
+            producer.send(project, logStore, item);
+        } catch (InterruptedException | ProducerException ignored) {
+        }
+    }
+
+    public void error(Object... kv) {
+        try {
+            LogItem item = log(kv);
+            item.PushBack("level", "error");
+            producer.send(project, logStore, item);
+        } catch (InterruptedException | ProducerException ignored) {
+        }
+    }
+
+    public void warn(Object... kv) {
+        try {
+            LogItem item = log(kv);
+            item.PushBack("level", "warn");
+            producer.send(project, logStore, item);
+        } catch (InterruptedException | ProducerException ignored) {
+        }
+    }
+
+    private LogItem log(Object... kv) {
+        LogItem item = new LogItem();
+        item.PushBack("app", "chatgpt");
+        int length = kv.length;
+        if (length % 2 != 0) {
+            return item;
+        }
+        for (int i = 0; i < kv.length; i += 2) {
+            if (kv[i] == null) {
+                continue;
+            }
+            item.PushBack(kv[i].toString(), format(kv[i + 1]));
+        }
+        return item;
+    }
+
+    private String format(Object obj) {
+        if (obj == null) {
+            return "";
+        }
+        if (obj instanceof Throwable err) {
+            StringWriter sw = new StringWriter();
+            err.printStackTrace(new PrintWriter(sw, true));
+            return sw.getBuffer().toString();
+        }
+        return obj.toString();
+    }
+
+
+    private void close() {
+        try {
+            producer.close();
+        } catch (InterruptedException | ProducerException ignored) {
+        }
+    }
+
+    public static void main(String[] args) {
+        AliyunLogger aliyunLogger = new AliyunLogger();
+        aliyunLogger.init();
+
+        aliyunLogger.info("msg", "123");
+        aliyunLogger.info("msg", 1);
+        aliyunLogger.info("msg", new RuntimeException("what"));
+
+        aliyunLogger.close();
+    }
+}

+ 13 - 0
src/main/java/com/sxtvs/core/sls/advice/APINoDataResponse.java

@@ -0,0 +1,13 @@
+package com.sxtvs.core.sls.advice;
+
+import lombok.Data;
+
+@Data
+public class APINoDataResponse  {
+
+    private String message;
+
+    private Integer code;
+
+
+}

+ 13 - 0
src/main/java/com/sxtvs/core/sls/advice/APIResponse.java

@@ -0,0 +1,13 @@
+package com.sxtvs.core.sls.advice;
+
+import lombok.Data;
+
+@Data
+public class APIResponse {
+
+    private String message;
+
+    private Integer code;
+
+    private Object data;
+}

+ 141 - 0
src/main/java/com/sxtvs/core/sls/advice/APIResponseAdvice.java

@@ -0,0 +1,141 @@
+package com.sxtvs.core.sls.advice;
+
+import com.sxtvs.core.sls.AliyunLogger;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.multipart.MaxUploadSizeExceededException;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+@RestControllerAdvice
+@Slf4j
+public class APIResponseAdvice implements ResponseBodyAdvice<Object> {
+
+    @Autowired
+    private AliyunLogger logger;
+
+    //自动处理APINoDataResponse,包装为APINoDataResponse
+
+
+    @ExceptionHandler(BizException.class)
+    public APINoDataResponse handleBizException(HttpServletRequest request, BizException ex, HttpServletResponse response) {
+        APINoDataResponse apiNoDataResponse = new APINoDataResponse();
+        apiNoDataResponse.setCode(ex.getErrorCode());
+        apiNoDataResponse.setMessage(ex.getErrorMessage());
+        return apiNoDataResponse;
+    }
+
+    @ExceptionHandler(MaxUploadSizeExceededException.class)
+    public APINoDataResponse handleException(HttpServletRequest request, MaxUploadSizeExceededException ex, HttpServletResponse response) {
+        logger.error("error", ex);
+        APINoDataResponse apiResponse = new APINoDataResponse();
+        apiResponse.setCode(-1);
+        apiResponse.setMessage("文件长度过长");
+        return apiResponse;
+    }
+
+    /**
+     * 拦截未知的运行时异常
+     *
+     * @author fengshuonan
+     * @date 2020/12/16 15:12
+     */
+    @ExceptionHandler(Throwable.class)
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    public APINoDataResponse serverError(Throwable ex) {
+        logger.error("error", ex);
+        APINoDataResponse apiResponse = new APINoDataResponse();
+        apiResponse.setCode(-1);
+        apiResponse.setMessage("服务器运行异常");
+        return apiResponse;
+    }
+
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public APINoDataResponse validationBodyException(MethodArgumentNotValidException exception) {
+
+        BindingResult result = exception.getBindingResult();
+        if (result.hasErrors()) {
+
+            List<ObjectError> errors = result.getAllErrors();
+
+            errors.forEach(p -> {
+
+                FieldError fieldError = (FieldError) p;
+                log.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
+                        "},errorMessage{" + fieldError.getDefaultMessage() + "}");
+
+            });
+
+        }
+        APINoDataResponse apiResponse = new APINoDataResponse();
+        apiResponse.setCode(-1);
+        apiResponse.setMessage("请填写正确信息");
+        return apiResponse;
+    }
+
+
+    //仅当方法或类没有标记@NoAPIResponse才自动包装
+    @Override
+    public boolean supports(MethodParameter returnType, Class converterType) {
+        for (Annotation methodAnnotation : returnType.getMethodAnnotations()) {
+            if (methodAnnotation.annotationType() == NoAPIResponse.class) {
+                return false;
+            }
+        }
+        return returnType.getParameterType() != APIResponse.class && returnType.getParameterType() != APINoDataResponse.class
+                && AnnotationUtils.findAnnotation(returnType.getDeclaringClass(), NoAPIResponse.class) == null;
+    }
+
+    //自动包装外层APIResposne响应
+    @Override
+    public Object beforeBodyWrite(Object body,
+                                  MethodParameter returnType,
+                                  MediaType selectedContentType,
+                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
+                                  ServerHttpRequest request, ServerHttpResponse response) {
+
+
+        ResponseMsg responseMsg = returnType.getMethodAnnotation(ResponseMsg.class);
+        String msg = "OK";
+
+        if (null != responseMsg) {
+            msg = responseMsg.value();
+        }
+
+        if (null == body) {
+            APINoDataResponse apiResponse = new APINoDataResponse();
+            apiResponse.setCode(0);
+
+            apiResponse.setMessage(msg);
+            return apiResponse;
+        } else {
+            APIResponse apiResponse = new APIResponse();
+
+            apiResponse.setCode(0);
+            apiResponse.setMessage(msg);
+            apiResponse.setData(body);
+            return apiResponse;
+        }
+
+    }
+
+}

+ 31 - 0
src/main/java/com/sxtvs/core/sls/advice/BizException.java

@@ -0,0 +1,31 @@
+package com.sxtvs.core.sls.advice;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class BizException extends RuntimeException {
+
+    private int errorCode;
+
+    private String errorMessage;
+
+    public BizException(String errorMessage) {
+        super(errorMessage);
+        this.errorCode = -1;
+        this.errorMessage = errorMessage;
+    }
+
+    public BizException(int errorCode, String errorMessage) {
+        super(errorMessage);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+
+    public BizException(Throwable cause, int errorCode, String errorMessage) {
+        super(errorMessage, cause);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+}

+ 11 - 0
src/main/java/com/sxtvs/core/sls/advice/NoAPIResponse.java

@@ -0,0 +1,11 @@
+package com.sxtvs.core.sls.advice;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NoAPIResponse {
+}

+ 13 - 0
src/main/java/com/sxtvs/core/sls/advice/ResponseMsg.java

@@ -0,0 +1,13 @@
+package com.sxtvs.core.sls.advice;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ResponseMsg {
+    String value() default "OK";
+}

+ 1 - 1
src/test/java/com/sxtvs/chatgpt/ChatgptApplicationTests.java → src/test/java/com/sxtvs/ChatgptApplicationTests.java

@@ -1,4 +1,4 @@
-package com.sxtvs.chatgpt;
+package com.sxtvs;
 
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;