新增腾讯混元大模型的支持
This commit is contained in:
parent
db0402e32e
commit
3a1a025c63
|
|
@ -31,3 +31,7 @@ build/
|
|||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
info.text
|
||||
|
||||
conf
|
||||
16
README.md
16
README.md
|
|
@ -1,8 +1,16 @@
|
|||
# AiCoder
|
||||
|
||||
Ai模型
|
||||
Ai大模型
|
||||
|
||||
- 通义千问-MAX
|
||||
- ollama
|
||||
**在线大模型**
|
||||
|
||||
使用建议将AiExecutor中的ApiKey改为你在阿里云上申请的token
|
||||
_apiKey需要在对应的平台进行申请_
|
||||
|
||||
- 阿里云
|
||||
- 通义千问大模型(qwen-max、qwen-long)
|
||||
- 腾讯云
|
||||
- 混元大模型(hunyuan-lite)
|
||||
|
||||
**本地大模型**
|
||||
|
||||
- ollama大模型(llama3)
|
||||
|
|
|
|||
58
pom.xml
58
pom.xml
|
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.shockkid</groupId>
|
||||
<artifactId>AiCoder</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<version>0.0.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>AiCoder</name>
|
||||
|
|
@ -45,6 +45,62 @@
|
|||
<artifactId>commonmark</artifactId>
|
||||
<version>0.19.0</version>
|
||||
</dependency>
|
||||
<!--引入Knife4j的官方start包,该指南选择Spring Boot版本<3.0,开发者需要注意-->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
|
||||
<version>4.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.9.1</version>
|
||||
<!-- <scope>runtime</scope>-->
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库导出文档 -->
|
||||
<!-- https://mvnrepository.com/artifact/cn.smallbun.screw/screw-core -->
|
||||
<dependency>
|
||||
<groupId>cn.smallbun.screw</groupId>
|
||||
<artifactId>screw-core</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud.screw</groupId>
|
||||
<artifactId>screw-extension</artifactId>
|
||||
<version>0.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jdbc</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!--循环重试-->
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jol</groupId>
|
||||
<artifactId>jol-core</artifactId>
|
||||
<version>0.16</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
// }
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<PaymentRequest> 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";
|
||||
}
|
||||
}
|
||||
|
|
@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
/**
|
||||
* 通义大模型模型链接
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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<RoleContentModel> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 "请求失败";
|
||||
}
|
||||
}
|
||||
|
|
@ -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<RoleContentModel> 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 "请求失败";
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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<RoleContentModel> messages;
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String> ignoreTableName = new ArrayList<>();
|
||||
ignoreTableName.add("test_user");
|
||||
ignoreTableName.add("test_group");
|
||||
//忽略表前缀
|
||||
ArrayList<String> ignorePrefix = new ArrayList<>();
|
||||
ignorePrefix.add("test_");
|
||||
//忽略表后缀
|
||||
ArrayList<String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1 +1,15 @@
|
|||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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|
|
||||
+-+-+-+-+-+-+-+
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue