From 3a1a025c633a01f520115a69bca56ca3dac34693 Mon Sep 17 00:00:00 2001
From: lisang <1186733841@qq.com>
Date: Thu, 28 Nov 2024 23:49:15 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=85=BE=E8=AE=AF=E6=B7=B7?=
=?UTF-8?q?=E5=85=83=E5=A4=A7=E6=A8=A1=E5=9E=8B=E7=9A=84=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 +
README.md | 16 ++-
pom.xml | 58 +++++++-
.../shockkid/aicoder/AiCoderApplication.java | 3 +
.../aicoder/annotation/MethodExporter.java | 19 +++
.../aicoder/aspect/MethodExporterAspect.java | 40 ++++++
.../aicoder/config/HunYuanProperties.java | 44 +++++++
.../aicoder/config/Knife4jConfiguration.java | 31 +++++
.../aicoder/config/ShockKidAiProperties.java | 43 ++++++
.../aicoder/constant/ModelConstant.java | 1 +
.../aicoder/controller/AiController.java | 19 ++-
.../example/pay/AsyncPaymentService.java | 55 ++++++++
.../aicoder/example/pay/PaymentRequest.java | 44 +++++++
.../aicoder/example/pay/PaymentService.java | 23 ++++
.../aicoder/example/pay/PaymentTestMain.java | 21 +++
.../shockkid/aicoder/executor/AiExecutor.java | 2 +-
.../aicoder/executor/AiHunYuanExecutor.java | 92 +++++++++++++
.../aicoder/executor/AiOllmaExecutor.java | 108 +++++++++++++++
.../aicoder/executor/AiTongYiExecutor.java | 124 ++++++++++++++++++
.../aicoder/factory/AiExecutorFactory.java | 13 ++
.../shockkid/aicoder/model/OpenAiModel.java | 17 +++
.../com/shockkid/aicoder/util/BatchUtils.java | 26 ++++
.../shockkid/aicoder/util/DataExportUtil.java | 95 ++++++++++++++
.../shockkid/aicoder/util/MakePojoUtil.java | 66 ++++++++++
src/main/resources/application.properties | 16 ++-
src/main/resources/application.yml | 44 +++++++
src/main/resources/banner.txt | 6 +
.../aicoder/AiCoderApplicationTests.java | 3 +
28 files changed, 1024 insertions(+), 9 deletions(-)
create mode 100644 src/main/java/com/shockkid/aicoder/annotation/MethodExporter.java
create mode 100644 src/main/java/com/shockkid/aicoder/aspect/MethodExporterAspect.java
create mode 100644 src/main/java/com/shockkid/aicoder/config/HunYuanProperties.java
create mode 100644 src/main/java/com/shockkid/aicoder/config/Knife4jConfiguration.java
create mode 100644 src/main/java/com/shockkid/aicoder/config/ShockKidAiProperties.java
create mode 100644 src/main/java/com/shockkid/aicoder/example/pay/AsyncPaymentService.java
create mode 100644 src/main/java/com/shockkid/aicoder/example/pay/PaymentRequest.java
create mode 100644 src/main/java/com/shockkid/aicoder/example/pay/PaymentService.java
create mode 100644 src/main/java/com/shockkid/aicoder/example/pay/PaymentTestMain.java
create mode 100644 src/main/java/com/shockkid/aicoder/executor/AiHunYuanExecutor.java
create mode 100644 src/main/java/com/shockkid/aicoder/executor/AiOllmaExecutor.java
create mode 100644 src/main/java/com/shockkid/aicoder/executor/AiTongYiExecutor.java
create mode 100644 src/main/java/com/shockkid/aicoder/factory/AiExecutorFactory.java
create mode 100644 src/main/java/com/shockkid/aicoder/model/OpenAiModel.java
create mode 100644 src/main/java/com/shockkid/aicoder/util/BatchUtils.java
create mode 100644 src/main/java/com/shockkid/aicoder/util/DataExportUtil.java
create mode 100644 src/main/java/com/shockkid/aicoder/util/MakePojoUtil.java
create mode 100644 src/main/resources/application.yml
create mode 100644 src/main/resources/banner.txt
diff --git a/.gitignore b/.gitignore
index 549e00a..a85c9d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,7 @@ build/
### VS Code ###
.vscode/
+
+info.text
+
+conf
\ No newline at end of file
diff --git a/README.md b/README.md
index 285c2ee..43aea4c 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,16 @@
# AiCoder
-Ai模型
+Ai大模型
-- 通义千问-MAX
-- ollama
+**在线大模型**
-使用建议将AiExecutor中的ApiKey改为你在阿里云上申请的token
\ No newline at end of file
+_apiKey需要在对应的平台进行申请_
+
+- 阿里云
+ - 通义千问大模型(qwen-max、qwen-long)
+- 腾讯云
+ - 混元大模型(hunyuan-lite)
+
+**本地大模型**
+
+- ollama大模型(llama3)
diff --git a/pom.xml b/pom.xml
index a551955..d113065 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.shockkid
AiCoder
- 0.0.1-SNAPSHOT
+ 0.0.1
jar
AiCoder
@@ -45,6 +45,62 @@
commonmark
0.19.0
+
+
+ com.github.xiaoymin
+ knife4j-openapi2-spring-boot-starter
+ 4.4.0
+
+
+
+
+ org.aspectj
+ aspectjweaver
+ 1.9.9.1
+
+
+
+
+
+
+ cn.smallbun.screw
+ screw-core
+ 1.0.5
+
+
+ com.pig4cloud.screw
+ screw-extension
+ 0.0.2
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jdbc
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.5.1
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+
+
+ org.springframework.retry
+ spring-retry
+ 1.3.2
+
+
+
+ org.openjdk.jol
+ jol-core
+ 0.16
+
org.springframework.boot
diff --git a/src/main/java/com/shockkid/aicoder/AiCoderApplication.java b/src/main/java/com/shockkid/aicoder/AiCoderApplication.java
index b088290..eff1066 100644
--- a/src/main/java/com/shockkid/aicoder/AiCoderApplication.java
+++ b/src/main/java/com/shockkid/aicoder/AiCoderApplication.java
@@ -3,6 +3,9 @@ package com.shockkid.aicoder;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+// @ComponentScan(value = "com.shockkid.aicoder",
+// excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,
+// value = {Controller.class, RestController.class})})
@SpringBootApplication
public class AiCoderApplication {
diff --git a/src/main/java/com/shockkid/aicoder/annotation/MethodExporter.java b/src/main/java/com/shockkid/aicoder/annotation/MethodExporter.java
new file mode 100644
index 0000000..a856c77
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/annotation/MethodExporter.java
@@ -0,0 +1,19 @@
+package com.shockkid.aicoder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @Author lisang
+ * @Date 2022/4/10 23:53
+ * @Description 方法记录
+ * @Version 1.0
+ */
+//注解用在方法上
+@Target(ElementType.METHOD)
+//注解保留多久,RUNTIME运行时
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MethodExporter {
+}
diff --git a/src/main/java/com/shockkid/aicoder/aspect/MethodExporterAspect.java b/src/main/java/com/shockkid/aicoder/aspect/MethodExporterAspect.java
new file mode 100644
index 0000000..24f3aec
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/aspect/MethodExporterAspect.java
@@ -0,0 +1,40 @@
+package com.shockkid.aicoder.aspect;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+import java.time.Instant;
+
+/**
+ * @Author lisang
+ * @Date 2022/4/10 23:55
+ * @Description
+ * @Version 1.0
+ */
+@Aspect
+@Component
+@Slf4j
+public class MethodExporterAspect {
+
+ @Around("@annotation(com.shockkid.aicoder.annotation.MethodExporter)")
+ public Object methodExporter(ProceedingJoinPoint joinPoint) throws Throwable {
+ long st = Instant.now().toEpochMilli();
+ Object proceed = joinPoint.proceed();
+ long et = Instant.now().toEpochMilli();
+ ObjectMapper mapper = new ObjectMapper();
+ String jsonParam = mapper.writeValueAsString(joinPoint.getArgs());
+ String jsonResult = null;
+ jsonResult = proceed != null ? mapper.writeValueAsString(proceed) : "null";
+ log.info("正在上报服务调用过程:\ntarget{}.{}\nexecution:{}ms,\nparameter:{}\nresult:{}"
+ , joinPoint.getTarget().getClass().getSimpleName()
+ , joinPoint.getSignature().getName()
+ , (et - st)
+ , jsonParam
+ , jsonResult);
+ return proceed;
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/config/HunYuanProperties.java b/src/main/java/com/shockkid/aicoder/config/HunYuanProperties.java
new file mode 100644
index 0000000..4d420db
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/config/HunYuanProperties.java
@@ -0,0 +1,44 @@
+package com.shockkid.aicoder.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 18:18
+ * @Description:
+ * @Version 1.0
+ **/
+@Configuration
+@ConfigurationProperties(prefix = "shockkid.ai.hunyuan")
+public class HunYuanProperties {
+ private String url;
+
+ private String apiKey;
+
+ private String model;
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/config/Knife4jConfiguration.java b/src/main/java/com/shockkid/aicoder/config/Knife4jConfiguration.java
new file mode 100644
index 0000000..7e80ce4
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/config/Knife4jConfiguration.java
@@ -0,0 +1,31 @@
+package com.shockkid.aicoder.config;
+
+/**
+ * @auther lisang
+ * @date 2024/8/6 13:19
+ **/
+// @Configuration
+// @EnableSwagger2WebMvc
+public class Knife4jConfiguration {
+
+ // @Bean(value = "dockerBean")
+ // public Docket dockerBean() {
+ // //指定使用Swagger2规范
+ // Docket docket=new Docket(DocumentationType.SWAGGER_2)
+ // .apiInfo(new ApiInfoBuilder()
+ // //描述字段支持Markdown语法
+ // .description("# Knife4j RESTful APIs")
+ // .termsOfServiceUrl("https://mlisan.com/")
+ // .contact("lisang_chn@163.com")
+ // .version("1.0")
+ // .build())
+ // //分组名称
+ // .groupName("AI服务")
+ // .select()
+ // //这里指定Controller扫描包路径
+ // .apis(RequestHandlerSelectors.basePackage("com.shockkid.aicoder.controller"))
+ // .paths(PathSelectors.any())
+ // .build();
+ // return docket;
+ // }
+}
\ No newline at end of file
diff --git a/src/main/java/com/shockkid/aicoder/config/ShockKidAiProperties.java b/src/main/java/com/shockkid/aicoder/config/ShockKidAiProperties.java
new file mode 100644
index 0000000..4f2a596
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/config/ShockKidAiProperties.java
@@ -0,0 +1,43 @@
+package com.shockkid.aicoder.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 22:03
+ * @Description: AI 配置类
+ * @Version 1.0
+ **/
+@Configuration
+@ConfigurationProperties(prefix = "shockkid.ai")
+@Data
+public class ShockKidAiProperties {
+ private AliyunTongYiPropertis tongyi;
+ private TencentHunYuanPropertis hunyuan;
+ private OllmaPropertis ollma;
+
+ @Data
+ public static class AliyunTongYiPropertis {
+ private boolean enable;
+ private String url;
+ private String apiKey;
+ private String model;
+ }
+
+ @Data
+ public static class TencentHunYuanPropertis {
+ private boolean enable;
+ private String url;
+ private String apiKey;
+ private String model;
+ }
+
+ @Data
+ public static class OllmaPropertis {
+ private boolean enable;
+ private String url;
+ private String model;
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/constant/ModelConstant.java b/src/main/java/com/shockkid/aicoder/constant/ModelConstant.java
index aa9cb8c..a463628 100644
--- a/src/main/java/com/shockkid/aicoder/constant/ModelConstant.java
+++ b/src/main/java/com/shockkid/aicoder/constant/ModelConstant.java
@@ -15,4 +15,5 @@ public class ModelConstant {
public static final String ASSISTANT_ROLE = "assistant";
public static final String MESSAGE = "message";
public static final String CONTENT = "content";
+ public static final String HUNYUAN_LITE = "hunyuan-lite";
}
diff --git a/src/main/java/com/shockkid/aicoder/controller/AiController.java b/src/main/java/com/shockkid/aicoder/controller/AiController.java
index 85562d8..996eb6c 100644
--- a/src/main/java/com/shockkid/aicoder/controller/AiController.java
+++ b/src/main/java/com/shockkid/aicoder/controller/AiController.java
@@ -1,7 +1,13 @@
package com.shockkid.aicoder.controller;
import com.shockkid.aicoder.executor.AiExecutor;
+import com.shockkid.aicoder.factory.AiExecutorFactory;
import com.shockkid.aicoder.storage.MessageHistoryStorage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -9,16 +15,25 @@ import org.springframework.web.bind.annotation.RestController;
* @auther lisang
* @date 2024/5/22 23:43
**/
+@Api(tags = "AI模块")
@RestController
public class AiController {
+ @Autowired@Qualifier("aiHunYuanExecutor")
+ private AiExecutorFactory aiExecutor;
+
+ @ApiImplicitParam(name = "text", value = "请求文本", required = true)
+ @ApiOperation(value = "AI反馈结果")
@PostMapping("/aiChat")
public String aiChat(String text) {
- AiExecutor aiExecutor = new AiExecutor();
- String result = aiExecutor.getChatMessageByTongYi(text);
+ /*AiExecutor aiExecutor = new AiExecutor();
+ String result = aiExecutor.getChatMessageByTongYi(text);*/
+ String result = aiExecutor.getChatMessage(text);
return result;
}
+ @ApiImplicitParam(name = "text", value = "请求文本含历史记录", required = true)
+ @ApiOperation(value = "AI反馈结果")
@PostMapping("/aiChatHistory")
public String aiChatHistory(String text) {
AiExecutor aiExecutor = new AiExecutor();
diff --git a/src/main/java/com/shockkid/aicoder/example/pay/AsyncPaymentService.java b/src/main/java/com/shockkid/aicoder/example/pay/AsyncPaymentService.java
new file mode 100644
index 0000000..697d6fb
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/example/pay/AsyncPaymentService.java
@@ -0,0 +1,55 @@
+package com.shockkid.aicoder.example.pay;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @auther lisang
+ * @date 2024/6/25 10:49
+ **/
+public class AsyncPaymentService {
+ // 创建线程池
+ private final ExecutorService single = Executors.newSingleThreadExecutor();
+
+ // 阻塞队列 -> 可以替换成分布式队列
+ ArrayBlockingQueue taskQueue = new ArrayBlockingQueue(10);
+
+ // 标识
+ private volatile boolean isRunning = true;
+
+ {
+ init();
+ }
+
+ // 异步处理
+ public void init() {
+ single.execute(()->{
+ while (isRunning) {
+ try {
+ PaymentRequest paymentRequest = taskQueue.take();// 阻塞方式拿到支付任务
+ doPay(paymentRequest);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ public String submitPay(PaymentRequest paymentRequest) {
+ System.out.println("开始校验请求参数:" + paymentRequest);
+ taskQueue.add(paymentRequest); // 添加到队列
+ return "processing"; // 返回支付处理成功 -> 可能变成失败
+ }
+
+ public String doPay(PaymentRequest paymentRequest) {
+ try {
+ System.out.println("开始处理支付请求:" + paymentRequest);
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("支付处理结束:" + paymentRequest);
+ return "success";
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/example/pay/PaymentRequest.java b/src/main/java/com/shockkid/aicoder/example/pay/PaymentRequest.java
new file mode 100644
index 0000000..2bab555
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/example/pay/PaymentRequest.java
@@ -0,0 +1,44 @@
+package com.shockkid.aicoder.example.pay;
+
+/**
+ * @auther lisang
+ * @date 2024/6/25 10:41
+ **/
+public class PaymentRequest {
+ public int payMethod;
+ public int totalFee;
+ public String returnUrl;
+
+ public int getPayMethod() {
+ return payMethod;
+ }
+
+ public void setPayMethod(int payMethod) {
+ this.payMethod = payMethod;
+ }
+
+ public int getTotalFee() {
+ return totalFee;
+ }
+
+ public void setTotalFee(int totalFee) {
+ this.totalFee = totalFee;
+ }
+
+ public String getReturnUrl() {
+ return returnUrl;
+ }
+
+ public void setReturnUrl(String returnUrl) {
+ this.returnUrl = returnUrl;
+ }
+
+ @Override
+ public String toString() {
+ return "PaymentRequest{" +
+ "payMethod=" + payMethod +
+ ", totalFee=" + totalFee +
+ ", returnUrl='" + returnUrl + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/example/pay/PaymentService.java b/src/main/java/com/shockkid/aicoder/example/pay/PaymentService.java
new file mode 100644
index 0000000..396ffc4
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/example/pay/PaymentService.java
@@ -0,0 +1,23 @@
+package com.shockkid.aicoder.example.pay;
+
+/**
+ * @auther lisang
+ * @date 2024/6/25 10:41
+ **/
+public class PaymentService {
+ public String submitPay(PaymentRequest paymentRequest) {
+ System.out.println("开始校验请求参数:" + paymentRequest);
+ return doPay(paymentRequest);
+ }
+
+ public String doPay(PaymentRequest paymentRequest) {
+ try {
+ System.out.println("开始处理支付请求:" + paymentRequest);
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("支付处理结束:" + paymentRequest);
+ return "success";
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/example/pay/PaymentTestMain.java b/src/main/java/com/shockkid/aicoder/example/pay/PaymentTestMain.java
new file mode 100644
index 0000000..d6d5909
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/example/pay/PaymentTestMain.java
@@ -0,0 +1,21 @@
+package com.shockkid.aicoder.example.pay;
+
+import java.io.IOException;
+
+/**
+ * @auther lisang
+ * @date 2024/6/25 10:41
+ **/
+public class PaymentTestMain {
+ public static void main(String[] args) throws IOException {
+ long start = System.currentTimeMillis();
+ PaymentRequest request = new PaymentRequest();
+ request.setPayMethod(1);
+ request.setTotalFee(100);
+ request.setReturnUrl("http://www.baidu.com");
+ String result = new AsyncPaymentService().submitPay(request);
+ long end = System.currentTimeMillis() - start;
+ System.out.println("支付处理结果:"+result+"->总处理时间:"+end);
+ //System.in.read();
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/executor/AiExecutor.java b/src/main/java/com/shockkid/aicoder/executor/AiExecutor.java
index 99fa6fa..eac81ca 100644
--- a/src/main/java/com/shockkid/aicoder/executor/AiExecutor.java
+++ b/src/main/java/com/shockkid/aicoder/executor/AiExecutor.java
@@ -23,7 +23,7 @@ import static com.shockkid.aicoder.constant.ModelConstant.*;
public class AiExecutor {
private String generateUrl = "http://127.0.0.1:11434/api/generate";
private String chatUrl = "http://127.0.0.1:11434/api/chat";
- private String ApiKey = "Bearer 你的TOKEN";
+ private String ApiKey = "Bearer 通义千问TOKEN";
/**
* 通义大模型模型链接
*/
diff --git a/src/main/java/com/shockkid/aicoder/executor/AiHunYuanExecutor.java b/src/main/java/com/shockkid/aicoder/executor/AiHunYuanExecutor.java
new file mode 100644
index 0000000..453a193
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/executor/AiHunYuanExecutor.java
@@ -0,0 +1,92 @@
+package com.shockkid.aicoder.executor;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.shockkid.aicoder.config.HunYuanProperties;
+import com.shockkid.aicoder.config.OkHttpClientSingleton;
+import com.shockkid.aicoder.factory.AiExecutorFactory;
+import com.shockkid.aicoder.model.InputModel;
+import com.shockkid.aicoder.model.OpenAiModel;
+import com.shockkid.aicoder.model.RoleContentModel;
+import okhttp3.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.shockkid.aicoder.constant.ModelConstant.HUNYUAN_LITE;
+import static com.shockkid.aicoder.constant.ModelConstant.USER_ROLE;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 18:25
+ * @Description: 腾讯混元大模型
+ * @Version 1.0
+ **/
+@Service
+public class AiHunYuanExecutor implements AiExecutorFactory {
+ private static final Logger log = LoggerFactory.getLogger(AiHunYuanExecutor.class);
+
+ @Autowired
+ private HunYuanProperties hunYuanConfig;
+
+ /**
+ * 基于腾讯混元大模型API获取返回结果
+ *
+ * @param prompt
+ * @return
+ */
+ public String getChatMessage(String prompt) {
+ OkHttpClient client = OkHttpClientSingleton.getInstance();
+ // 构建入参
+ OpenAiModel model = new OpenAiModel();
+ model.setModel(HUNYUAN_LITE);
+ InputModel inputModel = new InputModel();
+ List messages = new ArrayList<>();
+ RoleContentModel roleContentModel = new RoleContentModel();
+ roleContentModel.setRole(USER_ROLE);
+ roleContentModel.setContent(prompt);
+ messages.add(roleContentModel);
+ model.setMessages(messages);
+ // 发起请求
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(model));
+ log.info("" + JSON.toJSONString(model));
+ Request request = new Request.Builder()
+ .header("Authorization", "Bearer " + hunYuanConfig.getApiKey())
+ .url(hunYuanConfig.getUrl())
+ .post(requestBody)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ // 处理响应
+ if (response.isSuccessful()) {
+ // 请求成功
+ ResponseBody responseBody = response.body();
+ String string = responseBody.string();
+ JSONObject jsonObject = JSON.parseObject(string);
+ // 处理响应体
+ List choices = jsonObject.getObject("choices", List.class);
+ if (choices.size() > 0) {
+ JSONObject jsonObject2 = JSON.parseObject(jsonObject.getObject("choices", List.class).get(0).toString());
+ return jsonObject2.getJSONObject("message").getString("content");
+ }
+ return "模型未给出相关回答";
+ } else {
+ // 请求失败
+ return "请求失败,响应码: " + response.code();
+ }
+ } catch (IOException e) {
+ // 发生异常
+ e.printStackTrace();
+ }
+ return "请求失败";
+ }
+
+ @Override
+ public String getChatHistory(String prompt) {
+ return null;
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/executor/AiOllmaExecutor.java b/src/main/java/com/shockkid/aicoder/executor/AiOllmaExecutor.java
new file mode 100644
index 0000000..5557efe
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/executor/AiOllmaExecutor.java
@@ -0,0 +1,108 @@
+package com.shockkid.aicoder.executor;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.shockkid.aicoder.config.OkHttpClientSingleton;
+import com.shockkid.aicoder.config.ShockKidAiProperties;
+import com.shockkid.aicoder.factory.AiExecutorFactory;
+import com.shockkid.aicoder.model.ChatModel;
+import com.shockkid.aicoder.model.ChatRoleModel;
+import com.shockkid.aicoder.storage.MessageHistoryStorage;
+import okhttp3.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+import static com.shockkid.aicoder.constant.ModelConstant.*;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 18:25
+ * @Description: ollma大模型
+ * @Version 1.0
+ **/
+@Service
+public class AiOllmaExecutor implements AiExecutorFactory {
+ private static final Logger log = LoggerFactory.getLogger(AiOllmaExecutor.class);
+
+ @Autowired
+ private ShockKidAiProperties aiConf;
+
+ /**
+ * 基于ollma大模型API获取返回结果
+ *
+ * @param prompt
+ * @return
+ */
+ public String getChatMessage(String prompt) {
+ if (!aiConf.getOllma().isEnable()){
+ return "llama接口尚未接入";
+ }
+ OkHttpClient client = OkHttpClientSingleton.getInstance();
+ ChatModel chatModel = new ChatModel();
+ chatModel.setModel(aiConf.getOllma().getModel());
+ chatModel.setPrompt(prompt);
+ chatModel.setStream(false);
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(chatModel));
+ Request request = new Request.Builder()
+ .url(aiConf.getOllma().getUrl())
+ .post(requestBody)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ // 处理响应
+ if (response.isSuccessful()) {
+ // 请求成功
+ ResponseBody responseBody = response.body();
+ String string = responseBody.string();
+ JSONObject jsonObject = JSON.parseObject(string);
+ // 处理响应体
+ return jsonObject.getString(RESPONSE);
+ } else {
+ // 请求失败
+ return "请求失败,响应码: " + response.code();
+ }
+ } catch (IOException e) {
+ // 发生异常
+ e.printStackTrace();
+ }
+ return "请求失败";
+ }
+
+ @Override
+ public String getChatHistory(String prompt) {
+ if (!aiConf.getOllma().isEnable()){
+ return "llama尚未开启";
+ }
+ OkHttpClient client = OkHttpClientSingleton.getInstance();
+ ChatRoleModel chatRoleModel = new ChatRoleModel();
+ chatRoleModel.setModel(aiConf.getOllma().getModel());
+ chatRoleModel.setStream(false);
+ chatRoleModel.setMessages(MessageHistoryStorage.buildRoleContentModel(prompt));
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(chatRoleModel));
+ Request request = new Request.Builder()
+ .url(aiConf.getOllma().getUrl())
+ .post(requestBody)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ // 处理响应
+ if (response.isSuccessful()) {
+ ResponseBody responseBody = response.body();
+ String string = responseBody.string();
+ JSONObject jsonObject = JSON.parseObject(string);
+ JSONObject messageJson = jsonObject.getJSONObject(MESSAGE);
+ return messageJson.getString(CONTENT);
+ } else {
+ // 请求失败
+ System.out.println("请求失败,响应码: " + response.code());
+ return "请求失败,响应码: " + response.code();
+ }
+ } catch (IOException e) {
+ // 发生异常
+ e.printStackTrace();
+ }
+ return "请求失败";
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/executor/AiTongYiExecutor.java b/src/main/java/com/shockkid/aicoder/executor/AiTongYiExecutor.java
new file mode 100644
index 0000000..0cb1690
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/executor/AiTongYiExecutor.java
@@ -0,0 +1,124 @@
+package com.shockkid.aicoder.executor;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.shockkid.aicoder.config.OkHttpClientSingleton;
+import com.shockkid.aicoder.config.ShockKidAiProperties;
+import com.shockkid.aicoder.factory.AiExecutorFactory;
+import com.shockkid.aicoder.model.InputModel;
+import com.shockkid.aicoder.model.RoleContentModel;
+import com.shockkid.aicoder.model.TongYiModel;
+import com.shockkid.aicoder.storage.MessageHistoryStorage;
+import okhttp3.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.shockkid.aicoder.constant.ModelConstant.*;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 18:25
+ * @Description: 阿里通义千问大模型
+ * @Version 1.0
+ **/
+@Service
+public class AiTongYiExecutor implements AiExecutorFactory {
+ private static final Logger log = LoggerFactory.getLogger(AiTongYiExecutor.class);
+
+ @Autowired
+ private ShockKidAiProperties aiConf;
+
+ /**
+ * 基于阿里通义千问大模型API获取返回结果
+ *
+ * @param prompt
+ * @return
+ */
+ public String getChatMessage(String prompt) {
+ if (!aiConf.getTongyi().isEnable()){
+ return "通义千问接口尚未接入";
+ }
+ OkHttpClient client = OkHttpClientSingleton.getInstance();
+ // 构建入参
+ TongYiModel model = new TongYiModel();
+ model.setModel(aiConf.getTongyi().getModel());
+ InputModel inputModel = new InputModel();
+ List messages = new ArrayList<>();
+ RoleContentModel roleContentModel = new RoleContentModel();
+ roleContentModel.setRole(USER_ROLE);
+ roleContentModel.setContent(prompt);
+ messages.add(roleContentModel);
+ inputModel.setMessages(messages);
+ model.setInput(inputModel);
+ // 发起请求
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(model));
+ Request request = new Request.Builder()
+ .header("Authorization","Bearer "+ aiConf.getTongyi().getApiKey())
+ .url(aiConf.getTongyi().getUrl())
+ .post(requestBody)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ // 处理响应
+ if (response.isSuccessful()) {
+ // 请求成功
+ ResponseBody responseBody = response.body();
+ String string = responseBody.string();
+ JSONObject jsonObject = JSON.parseObject(string);
+ // 处理响应体
+ JSONObject outputJson = jsonObject.getJSONObject(OUTPUT);
+ return outputJson.getString(TEXT);
+ } else {
+ // 请求失败
+ return "请求失败,响应码: " + response.code();
+ }
+ } catch (IOException e) {
+ // 发生异常
+ e.printStackTrace();
+ }
+ return "请求失败";
+ }
+
+ @Override
+ public String getChatHistory(String prompt) {
+ OkHttpClient client = OkHttpClientSingleton.getInstance();
+ // 构建入参
+ TongYiModel model = new TongYiModel();
+ model.setModel(aiConf.getTongyi().getModel());
+ InputModel inputModel = new InputModel();
+ // 构建上下文入参
+ inputModel.setMessages(MessageHistoryStorage.buildRoleContentModel(prompt));
+ model.setInput(inputModel);
+ // 发起请求
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(model));
+ Request request = new Request.Builder()
+ .header("Authorization","Bearer "+ aiConf.getTongyi().getApiKey())
+ .url(aiConf.getTongyi().getUrl())
+ .post(requestBody)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ // 处理响应
+ if (response.isSuccessful()) {
+ // 请求成功
+ ResponseBody responseBody = response.body();
+ String string = responseBody.string();
+ JSONObject jsonObject = JSON.parseObject(string);
+ // 处理响应体
+ JSONObject outputJson = jsonObject.getJSONObject(OUTPUT);
+ return outputJson.getString(TEXT);
+ } else {
+ // 请求失败
+ return "请求失败,响应码: " + response.code();
+ }
+ } catch (IOException e) {
+ // 发生异常
+ e.printStackTrace();
+ }
+ return "请求失败";
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/factory/AiExecutorFactory.java b/src/main/java/com/shockkid/aicoder/factory/AiExecutorFactory.java
new file mode 100644
index 0000000..fc7b16e
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/factory/AiExecutorFactory.java
@@ -0,0 +1,13 @@
+package com.shockkid.aicoder.factory;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 20:05
+ * @Description:
+ * @Version 1.0
+ **/
+public interface AiExecutorFactory {
+ public String getChatMessage(String prompt);
+
+ public String getChatHistory(String prompt);
+}
diff --git a/src/main/java/com/shockkid/aicoder/model/OpenAiModel.java b/src/main/java/com/shockkid/aicoder/model/OpenAiModel.java
new file mode 100644
index 0000000..672b077
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/model/OpenAiModel.java
@@ -0,0 +1,17 @@
+package com.shockkid.aicoder.model;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author lisang
+ * @Date 2024/11/28 18:41
+ * @Description: OpenAi通用模型参数
+ * @Version 1.0
+ **/
+@Data
+public class OpenAiModel {
+ private String model;
+ private List messages;
+}
diff --git a/src/main/java/com/shockkid/aicoder/util/BatchUtils.java b/src/main/java/com/shockkid/aicoder/util/BatchUtils.java
new file mode 100644
index 0000000..c67e6e0
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/util/BatchUtils.java
@@ -0,0 +1,26 @@
+package com.shockkid.aicoder.util;
+
+import java.util.Random;
+
+/**
+ * 批量生成工具
+ *
+ * @auther lisang
+ * @date 2024/11/7 0:44
+ **/
+public class BatchUtils {
+ public String autoBuildAcount() {
+ long t = System.currentTimeMillis();
+ Random random = new Random();
+ int i = random.nextInt(900000) + 100000;
+ int checksum = (int) ((t + i) % 10);
+ return String.format("%d%d%d", t, i, checksum);
+ }
+
+ public static void main(String[] args) {
+ BatchUtils batchUtils = new BatchUtils();
+ for (int i = 0; i < 10; i++) {
+ System.out.println(batchUtils.autoBuildAcount());
+ }
+ }
+}
diff --git a/src/main/java/com/shockkid/aicoder/util/DataExportUtil.java b/src/main/java/com/shockkid/aicoder/util/DataExportUtil.java
new file mode 100644
index 0000000..f011754
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/util/DataExportUtil.java
@@ -0,0 +1,95 @@
+package com.shockkid.aicoder.util;
+
+import cn.smallbun.screw.core.Configuration;
+import cn.smallbun.screw.core.engine.EngineConfig;
+import cn.smallbun.screw.core.engine.EngineFileType;
+import cn.smallbun.screw.core.engine.EngineTemplateType;
+import cn.smallbun.screw.core.execute.DocumentationExecute;
+import cn.smallbun.screw.core.process.ProcessConfig;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+import javax.sql.DataSource;
+import java.time.Instant;
+import java.util.ArrayList;
+
+/**
+ * @Author lisang
+ * @Date 2022/4/11 9:04
+ * @Description 数据库结构文档导出工具
+ * @Version 1.0
+ */
+public class DataExportUtil {
+ String FILE_OUT_PUT_DIR = "E:\\test";
+
+ /**
+ * 文档生成
+ */
+ public void documentGeneration() {
+ //数据源
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
+ hikariConfig.setJdbcUrl("jdbc:mysql://49.232.23.130:13306/onlinegit");
+ hikariConfig.setUsername("root");
+ hikariConfig.setPassword("sz@ongit123");
+ //设置可以获取tables remarks信息
+ hikariConfig.addDataSourceProperty("useInformationSchema", "true");
+ hikariConfig.setMinimumIdle(2);
+ hikariConfig.setMaximumPoolSize(5);
+ DataSource dataSource = new HikariDataSource(hikariConfig);
+ //生成配置
+ EngineConfig engineConfig = EngineConfig.builder()
+ //生成文件路径
+ .fileOutputDir(FILE_OUT_PUT_DIR)
+ //打开目录
+ .openOutputDir(true)
+ //文件类型
+ .fileType(EngineFileType.HTML)
+ //生成模板实现
+ .produceType(EngineTemplateType.freemarker)
+ //自定义文件名称
+ .fileName("onlinegit").build();
+
+ //忽略表
+ ArrayList ignoreTableName = new ArrayList<>();
+ ignoreTableName.add("test_user");
+ ignoreTableName.add("test_group");
+ //忽略表前缀
+ ArrayList ignorePrefix = new ArrayList<>();
+ ignorePrefix.add("test_");
+ //忽略表后缀
+ ArrayList ignoreSuffix = new ArrayList<>();
+ ignoreSuffix.add("_test");
+ ProcessConfig processConfig = ProcessConfig.builder()
+ //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
+ //根据名称指定表生成
+ .designatedTableName(new ArrayList<>())
+ //根据表前缀生成
+ .designatedTablePrefix(new ArrayList<>())
+ //根据表后缀生成
+ .designatedTableSuffix(new ArrayList<>())
+ //忽略表名
+ .ignoreTableName(ignoreTableName)
+ //忽略表前缀
+ .ignoreTablePrefix(ignorePrefix)
+ //忽略表后缀
+ .ignoreTableSuffix(ignoreSuffix).build();
+ //配置
+ Configuration config = Configuration.builder()
+ .title("在线课堂设计文档")
+ //版本
+ .version("1.0.0")
+ //描述
+ .description("在线课堂数据库设计文档\n时间:" + Instant.now())
+ //数据源
+ .dataSource(dataSource)
+ //生成配置
+ .engineConfig(engineConfig)
+ //生成配置
+ .produceConfig(processConfig)
+ .build();
+ //执行生成
+ new DocumentationExecute(config).execute();
+ }
+
+}
diff --git a/src/main/java/com/shockkid/aicoder/util/MakePojoUtil.java b/src/main/java/com/shockkid/aicoder/util/MakePojoUtil.java
new file mode 100644
index 0000000..5b2f05e
--- /dev/null
+++ b/src/main/java/com/shockkid/aicoder/util/MakePojoUtil.java
@@ -0,0 +1,66 @@
+package com.shockkid.aicoder.util;
+
+import cn.smallbun.screw.core.process.ProcessConfig;
+import cn.smallbun.screw.extension.pojo.PojoConfiguration;
+import cn.smallbun.screw.extension.pojo.execute.PojoExecute;
+import cn.smallbun.screw.extension.pojo.strategy.HumpNameStrategy;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+
+/**
+ * @Author lisang
+ * @Date 2022/4/11 12:07
+ * @Description 生成实体类
+ * @Version 1.0
+ */
+public class MakePojoUtil {
+ final String POJOFILE_PATH = "E:\\wk\\idea\\AiCoder\\src\\main\\java\\com\\shockkid\\aicoder\\pojo";
+ final String PACKAGE_NAME = "com.shockkid.aicoder.pojo";
+
+ /**
+ * pojo生成
+ */
+ public void pojoGeneration() {
+ //数据源
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
+ hikariConfig.setJdbcUrl("jdbc:mysql://192.168.56.204:3306/onlinegit");
+ hikariConfig.setUsername("root");
+ hikariConfig.setPassword("123456");
+ //设置可以获取tables remarks信息
+ hikariConfig.addDataSourceProperty("useInformationSchema", "true");
+ hikariConfig.setMinimumIdle(2);
+ hikariConfig.setMaximumPoolSize(5);
+ DataSource dataSource = new HikariDataSource(hikariConfig);
+
+ ProcessConfig processConfig = ProcessConfig.builder()
+ //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
+ //根据名称指定表生成
+ .designatedTableName(new ArrayList<>())
+ //根据表前缀生成
+ .designatedTablePrefix(new ArrayList<>())
+ //根据表后缀生成
+ .designatedTableSuffix(new ArrayList<>()).build();
+
+ //设置生成pojo相关配置
+ PojoConfiguration config = new PojoConfiguration();
+ //设置文件存放路径
+ config.setPath(POJOFILE_PATH);
+ //设置包名
+ config.setPackageName(PACKAGE_NAME);
+ //设置是否使用lombok
+ config.setUseLombok(false);
+ //设置数据源
+ config.setDataSource(dataSource);
+ //设置命名策略
+ config.setNameStrategy(new HumpNameStrategy());
+ //设置表过滤逻辑
+ config.setProcessConfig(processConfig);
+ //执行生成
+ new PojoExecute(config).execute();
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 11152c6..46ed550 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,15 @@
-server.port=8520
\ No newline at end of file
+server.port=8520
+
+# \u914D\u7F6E\u57FA\u7840\u7684\u6570\u636E\u6E90
+#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/aicoder
+#spring.datasource.username=root
+#spring.datasource.password=123456
+#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+# \u6253\u5F00\u9A7C\u5CF0\u547D\u540D
+mybatis-plus.configuration.map-underscore-to-camel-case=true
+
+# \u63A7\u5236\u53F0\u6253\u5370SQL
+#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+# \u65E5\u5FD7\u65B9\u5F0F\u6253\u5370SQL
+logging.level.com.lisang.boot.swagger.service=debug
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..56ea0c6
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,44 @@
+spring:
+ application:
+ # 应用名称
+ name: AiCoder
+ # 配置基础的数据源
+ datasource:
+ url: jdbc:mysql://127.0.0.1:3306/aicoder
+ username: root
+ password: 123456
+ driver-class-name: com.mysql.cj.jdbc.Driver
+
+knife4j:
+ enable: true
+ openapi:
+ title: AI模块
+ description: "AI模块相关接口"
+ concat: ShockKid
+ version: v1.0
+ terms-of-service-url: https://mlisan.com
+ group:
+ default:
+ group-name: 默认分组
+ api-rule: package
+ api-rule-resources:
+ - com.shockkid.aicoder.controller
+
+shockkid:
+ ai:
+ hunyuan:
+ enable: true
+ url: "https://api.hunyuan.cloud.tencent.com/v1/chat/completions"
+ apiKey: "xxxx"
+ model: "hunyuan-lite"
+ tongyi:
+ enable: false
+ url: "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
+ apiKey: "xxxx"
+ model: "qwen-max"
+ ollama:
+ enable: false
+ url: "http://127.0.0.1:11434/api/generate"
+ model: "llama3"
+ info:
+ version: 0.0.1
\ No newline at end of file
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 0000000..3cff2ef
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,6 @@
+Application Name: ${spring.application.name}
+Application Version: ${shockkid.info.version}
+Spring Boot Version: ${spring-boot.version}
++-+-+-+-+-+-+-+
+|A|i|C|o|d|e|r|
++-+-+-+-+-+-+-+
diff --git a/src/test/java/com/shockkid/aicoder/AiCoderApplicationTests.java b/src/test/java/com/shockkid/aicoder/AiCoderApplicationTests.java
index 2552b79..ae157b5 100644
--- a/src/test/java/com/shockkid/aicoder/AiCoderApplicationTests.java
+++ b/src/test/java/com/shockkid/aicoder/AiCoderApplicationTests.java
@@ -1,5 +1,6 @@
package com.shockkid.aicoder;
+import com.shockkid.aicoder.util.MakePojoUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@@ -8,6 +9,8 @@ class AiCoderApplicationTests {
@Test
void contextLoads() {
+ MakePojoUtil makePojoUtil = new MakePojoUtil();
+ makePojoUtil.pojoGeneration();
}
}