mirror of
https://github.com/HuLaSpark/HuLa-Server.git
synced 2026-08-29 00:03:28 +08:00
AI模块重构
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package com.hula.utils;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -7,6 +10,139 @@ import java.util.Date;
|
||||
* @author nyh
|
||||
*/
|
||||
public class DateUtil extends org.apache.commons.lang3.time.DateUtils {
|
||||
/**
|
||||
* 时区 - 默认
|
||||
*/
|
||||
public static final String TIME_ZONE_DEFAULT = "GMT+8";
|
||||
|
||||
/**
|
||||
* 秒转换成毫秒
|
||||
*/
|
||||
public static final long SECOND_MILLIS = 1000;
|
||||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
|
||||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/**
|
||||
* 将 LocalDateTime 转换成 Date
|
||||
*
|
||||
* @param date LocalDateTime
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static Date of(LocalDateTime date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
// 将此日期时间与时区相结合以创建 ZonedDateTime
|
||||
ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
|
||||
// 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
|
||||
Instant instant = zonedDateTime.toInstant();
|
||||
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Date 转换成 LocalDateTime
|
||||
*
|
||||
* @param date Date
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime of(Date date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
// 转为时间戳
|
||||
Instant instant = date.toInstant();
|
||||
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
public static Date addTime(Duration duration) {
|
||||
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||
}
|
||||
|
||||
public static boolean isExpired(LocalDateTime time) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return now.isAfter(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day) {
|
||||
return buildTime(year, mouth, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day,
|
||||
int hour, int minute, int second) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, mouth - 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
calendar.set(Calendar.MINUTE, minute);
|
||||
calendar.set(Calendar.SECOND, second);
|
||||
calendar.set(Calendar.MILLISECOND, 0); // 一般情况下,都是 0 毫秒
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static Date max(Date a, Date b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return a.compareTo(b) > 0 ? a : b;
|
||||
}
|
||||
|
||||
public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return a.isAfter(b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否今天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isToday(LocalDateTime date) {
|
||||
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否昨天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isYesterday(LocalDateTime date) {
|
||||
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now().minusDays(1));
|
||||
}
|
||||
|
||||
public static Long getEndTimeByToday() {
|
||||
Calendar instance = Calendar.getInstance();
|
||||
Date now = new Date();
|
||||
|
||||
@@ -148,6 +148,142 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- Spring AI Model 模型接入 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-stability-ai-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 通义千问 -->
|
||||
<groupId>com.alibaba.cloud.ai</groupId>
|
||||
<artifactId>spring-ai-alibaba-starter</artifactId>
|
||||
<version>${spring-ai.version}.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 文心一言 -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-qianfan-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 智谱 GLM -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-minimax-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-moonshot-spring-boot-starter</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 向量存储:https://db-engines.com/en/ranking/vector+dbms -->
|
||||
<dependency>
|
||||
<!-- Qdrant:https://qdrant.tech/ -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-qdrant-store</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- Redis:https://redis.io/docs/latest/develop/get-started/vector-database/ -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-redis-store</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- Milvus:https://milvus.io/ -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-milvus-store</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
<exclusions>
|
||||
<!-- 解决和 logback 的日志冲突 -->
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-reload4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- Tika:负责内容的解析 -->
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-tika-document-reader</artifactId>
|
||||
<version>${spring-ai.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-cloud-function-context</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>spring-cloud-function-core</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fhs-opensource</groupId>
|
||||
<artifactId>easy-trans-anno</artifactId>
|
||||
<version>${easy-trans.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.yulichang</groupId>
|
||||
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
|
||||
<version>${mybatis-plus-join.version}</version>
|
||||
</dependency>
|
||||
<!-- TinyFlow:AI 工作流 -->
|
||||
<dependency>
|
||||
<groupId>dev.tinyflow</groupId>
|
||||
<artifactId>tinyflow-java-core</artifactId>
|
||||
<version>${tinyflow.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>enjoy</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>agents-flex-store-elasticsearch</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
<!-- 解决和 logback 的日志冲突 -->
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-reload4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.hula.ai.client.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 聊天内容类型枚举类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum ChatContentEnum {
|
||||
|
||||
/**
|
||||
* TEXT
|
||||
*/
|
||||
TEXT("text", "文字"),
|
||||
|
||||
IMAGE("image", "图片"),
|
||||
|
||||
VOICE("voice", "音频"),
|
||||
|
||||
VIDEO("video", "视频"),
|
||||
|
||||
FILE("file", "文件"),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
private final String label;
|
||||
|
||||
ChatContentEnum(final String value, final String label) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ChatContentEnum getEnum(String value) {
|
||||
for (ChatContentEnum chatModelEnum : ChatContentEnum.values()) {
|
||||
if (value.equals(chatModelEnum.value)) {
|
||||
return chatModelEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.hula.ai.client.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 聊天大模型枚举类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum ChatModelEnum {
|
||||
|
||||
/**
|
||||
* CHAT_GPT
|
||||
*/
|
||||
OPENAI("ChatGPT", "ChatGPT"),
|
||||
|
||||
WENXIN("WENXIN", "文心一言"),
|
||||
|
||||
CHATGLM("ChatGLM", "智谱清言"),
|
||||
|
||||
TONGYI("QIANWEN", "通义千问"),
|
||||
|
||||
SPARK("SPARK", "讯飞星火"),
|
||||
|
||||
MOONSHOT("Moonshot", "月之暗面"),
|
||||
|
||||
DEEPSEEK("DeepSeek", "深度求索"),
|
||||
|
||||
DOUBAO("Doubao", "豆包"),
|
||||
|
||||
INTERNLM("Internlm", "书生·浦语"),
|
||||
|
||||
LOCALLM("LocalLM", "本地模型"),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
private final String label;
|
||||
|
||||
ChatModelEnum(final String value, final String label) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ChatModelEnum getEnum(String value) {
|
||||
for (ChatModelEnum chatModelEnum : ChatModelEnum.values()) {
|
||||
if (value.equals(chatModelEnum.value)) {
|
||||
return chatModelEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.hula.ai.client.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 聊天角色枚举类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum ChatRoleEnum {
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*/
|
||||
SYSTEM("system", "系统"),
|
||||
|
||||
ASSISTANT("assistant", "角色"),
|
||||
|
||||
USER("user", "用户");
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
private final String label;
|
||||
|
||||
ChatRoleEnum(final String value, final String label) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.hula.ai.client.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 审核类型枚举类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum ChatStatusEnum {
|
||||
|
||||
/**
|
||||
* 回复状态 1 回复中 2正常 3 失败
|
||||
*/
|
||||
REPLY(1, "回复中"),
|
||||
|
||||
SUCCESS(2, "成功"),
|
||||
|
||||
ERROR(3, "失败");
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final Integer value;
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
private final String label;
|
||||
|
||||
ChatStatusEnum(final Integer value, final String label) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import com.hula.ai.common.api.CommonCommand;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 对话消息对象 Command
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025-03-08
|
||||
* @version: 1.2.8
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class ChatCommand extends CommonCommand implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 聊天编号
|
||||
*/
|
||||
@NotBlank(message = "缺少对话标识")
|
||||
private String chatNumber;
|
||||
|
||||
/**
|
||||
* 对话id
|
||||
*/
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long uid;
|
||||
|
||||
/**
|
||||
* 角色模型id
|
||||
*/
|
||||
private Long assistantId;
|
||||
|
||||
/**
|
||||
* 系统提示
|
||||
*/
|
||||
private String systemPrompt;
|
||||
|
||||
/**
|
||||
* 提示
|
||||
*/
|
||||
@NotBlank(message = "缺少提示词")
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 使用模型
|
||||
*/
|
||||
@NotBlank(message = "缺少模型信息")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 使用模型版本
|
||||
*/
|
||||
private String modelVersion;
|
||||
|
||||
/**
|
||||
* 是否api请求
|
||||
*/
|
||||
private Boolean api;
|
||||
|
||||
/**
|
||||
* 聊天内容
|
||||
*/
|
||||
private List<ChatMessageCommand> messages;
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 对话消息对象 Command
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatMessageCommand implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 聊天记录id
|
||||
*/
|
||||
private Long chatId;
|
||||
|
||||
/**
|
||||
* 关联消息id
|
||||
*/
|
||||
private String parentMessageId;
|
||||
|
||||
/**
|
||||
* 第三方消息id
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 使用模型
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 使用模型版本
|
||||
*/
|
||||
private String modelVersion;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息类型 text、image
|
||||
*/
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 角色模型
|
||||
*/
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* finish_reason
|
||||
*/
|
||||
private String finishReason;
|
||||
|
||||
/**
|
||||
* status
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 调用token
|
||||
*/
|
||||
private String appKey;
|
||||
|
||||
/**
|
||||
* 使用额度
|
||||
*/
|
||||
private Long usedTokens;
|
||||
|
||||
/**
|
||||
* 响应全文
|
||||
*/
|
||||
private String response;
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CompletionsParam {
|
||||
|
||||
@Schema(description = "文件映射", required = true)
|
||||
private List<String> fileIds;
|
||||
|
||||
private String ws;
|
||||
|
||||
@Schema(description = "会话id [每次发送消息都不一样]", required = true)
|
||||
private String conversationId;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DeleteFileParam extends FileParam {
|
||||
|
||||
@NotBlank(message = "请选择文件")
|
||||
private List<String> fileIds;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
public class FileParam {
|
||||
|
||||
@NotBlank(message = "请选择解析模型")
|
||||
private String model;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.hula.ai.client.model.command;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
public class UploadParam {
|
||||
|
||||
@NotBlank(message = "缺少对话标识")
|
||||
private String chatNumber;
|
||||
|
||||
@NotBlank(message = "请选择解析模型")
|
||||
private String model;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.hula.ai.client.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 对话消息对象 DTO
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025-03-08
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatMessageDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 聊天记录id
|
||||
*/
|
||||
private Long chatId;
|
||||
|
||||
/**
|
||||
* 关联消息id
|
||||
*/
|
||||
private String parentMessageId;
|
||||
|
||||
/**
|
||||
* 消息id
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 使用模型
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 使用模型版本
|
||||
*/
|
||||
private String modelVersion;
|
||||
|
||||
/**
|
||||
* 聊天摘要
|
||||
*/
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* 聊天摘要
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息类型 text、image
|
||||
*/
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 回复状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.hula.ai.client.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 大模型信息对象 DTO
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class ModelDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private Long createdBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private String updateUser;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 模型logo
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 模型版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 本地模型类型:1、Langchian;2、ollama;3、Giteeai
|
||||
*/
|
||||
private Integer localModelType;
|
||||
|
||||
/**
|
||||
* 模型接口地址
|
||||
*/
|
||||
private String modelUrl;
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String knowledge;
|
||||
|
||||
/**
|
||||
* 状态 0 禁用 1 启用
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.hula.ai.client.service;
|
||||
|
||||
import com.hula.ai.client.model.command.ChatCommand;
|
||||
import com.hula.ai.client.model.command.ChatMessageCommand;
|
||||
import com.hula.ai.client.model.dto.ChatMessageDTO;
|
||||
import com.hula.ai.client.model.dto.ModelDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* gpt服务
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2024/5/29
|
||||
* @version: 1.0.0
|
||||
* Copyright Ⓒ 2024 Master Computer Corporation Limited All rights reserved.
|
||||
*/
|
||||
public interface GptService {
|
||||
|
||||
/**
|
||||
* 新增聊天摘要
|
||||
*
|
||||
* @param command 聊天摘要
|
||||
* @return 结果
|
||||
*/
|
||||
Long saveChat(ChatCommand command);
|
||||
|
||||
/**
|
||||
* 提问
|
||||
*
|
||||
* @param command 提问内容
|
||||
* @return 返回json
|
||||
*/
|
||||
String chatMessage(ChatCommand command);
|
||||
|
||||
/**
|
||||
* 根据对话id 获取对话内容
|
||||
*
|
||||
* @param conversationId
|
||||
* @return
|
||||
*/
|
||||
ChatMessageDTO getMessageByConverstationId(String conversationId);
|
||||
|
||||
/**
|
||||
* 根据对话id 获取上下文内容 最多10条
|
||||
*
|
||||
* @param uid 操作人
|
||||
* @param conversationId 对话id
|
||||
* @return
|
||||
*/
|
||||
List<ChatMessageDTO> listMessageByConverstationId(Long uid, String conversationId);
|
||||
|
||||
/**
|
||||
* 新增回复消息(流式输出使用)
|
||||
*
|
||||
* @param command 对话消息
|
||||
* @return 结果
|
||||
*/
|
||||
void saveChatMessage(ChatMessageCommand command);
|
||||
|
||||
/**
|
||||
* 新增对话消息(json使用)
|
||||
*
|
||||
* @param command 对话消息
|
||||
* @return 结果
|
||||
*/
|
||||
List<ChatMessageDTO> saveChatMessage(ChatCommand command, Long chatId, String messageId);
|
||||
|
||||
/**
|
||||
* 校验用户额度
|
||||
*
|
||||
* @param command
|
||||
* @return
|
||||
*/
|
||||
ChatCommand validateGptCommand(ChatCommand command);
|
||||
|
||||
/**
|
||||
* 修改对话状态
|
||||
*
|
||||
* @param messageId 消息id
|
||||
* @param status 状态
|
||||
* @return 结果
|
||||
*/
|
||||
void updateMessageStatus(String messageId, Integer status);
|
||||
|
||||
/**
|
||||
* 更新对话使用token数
|
||||
*
|
||||
* @param messageId 消息id
|
||||
* @param usedTokens 使用token数
|
||||
* @return
|
||||
*/
|
||||
void updateMessageUsedTokens(String messageId, Long usedTokens);
|
||||
|
||||
/**
|
||||
* 获取模型信息
|
||||
*
|
||||
* @param model 模型名称
|
||||
* @return
|
||||
*/
|
||||
ModelDTO getModel(String model);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.hula.ai.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Key Value 的键值对
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class KeyValue<K, V> implements Serializable {
|
||||
|
||||
private K key;
|
||||
private V value;
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.hula.ai.common.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 整个应用通用的Command
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/12/8
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class CommonCommand implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 操作人
|
||||
*/
|
||||
private Long operater;
|
||||
|
||||
/**
|
||||
* 操作人Id
|
||||
*/
|
||||
private Long operaterId;
|
||||
|
||||
/**
|
||||
* 是否需要操作人
|
||||
*/
|
||||
private boolean needsOperator;
|
||||
|
||||
/**
|
||||
* 操作ids
|
||||
*/
|
||||
private List<Long> ids;
|
||||
|
||||
/**
|
||||
* 操作id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 审核数据源id
|
||||
*/
|
||||
private Long auditId;
|
||||
|
||||
/**
|
||||
* 更新数据源id
|
||||
*/
|
||||
private Long updateId;
|
||||
|
||||
public Long getOperater() {
|
||||
return this.operater;
|
||||
}
|
||||
|
||||
public void setOperater(Long operater) {
|
||||
this.operater = operater;
|
||||
needsOperator = true;
|
||||
}
|
||||
|
||||
public void setOperaterId(Long operaterId) {
|
||||
this.operaterId = operaterId;
|
||||
needsOperator = true;
|
||||
}
|
||||
|
||||
public Long getOperaterId() {
|
||||
return this.operaterId;
|
||||
}
|
||||
|
||||
public boolean isNeedsOperator() {
|
||||
return needsOperator;
|
||||
}
|
||||
|
||||
public void setNeedsOperator(boolean needsOperator) {
|
||||
this.needsOperator = needsOperator;
|
||||
}
|
||||
|
||||
public List<Long> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void setIds(List<Long> ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getAuditId() {
|
||||
return auditId;
|
||||
}
|
||||
|
||||
public void setAuditId(Long auditId) {
|
||||
this.auditId = auditId;
|
||||
}
|
||||
|
||||
public Long getUpdateId() {
|
||||
return updateId;
|
||||
}
|
||||
|
||||
public void setUpdateId(Long updateId) {
|
||||
this.updateId = updateId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.hula.ai.common.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 应用key信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/7/27
|
||||
* @version: 3.7.2
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class Key {
|
||||
|
||||
/**
|
||||
* 密钥Key
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 密钥Key Secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
public interface AiConstants {
|
||||
|
||||
/**
|
||||
* 资源映射路径 前缀
|
||||
*/
|
||||
String RESOURCE_PREFIX = "/files";
|
||||
|
||||
/**
|
||||
* 基础信息
|
||||
*/
|
||||
String BASE_INFO = "baseInfo";
|
||||
|
||||
/**
|
||||
* 应用信息
|
||||
*/
|
||||
String APP_INFO = "appInfo";
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 阿里云oss格式
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/11/22
|
||||
* @version: 1.2.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface AliOssConstant {
|
||||
|
||||
/**
|
||||
* 查看指定大小的云图片
|
||||
* logo图标
|
||||
*/
|
||||
String STYLE_LOGO = "?x-oss-process=style/logo";
|
||||
/**
|
||||
* 查看指定大小的云图片
|
||||
* 作滚动图
|
||||
*/
|
||||
String STYLE_BIGLOGO = "?x-oss-process=style/biglogo";
|
||||
|
||||
/**
|
||||
* 查看指定大小的云图片
|
||||
* 类别图
|
||||
*/
|
||||
String STYLE_CLASS = "?x-oss-process=style/class";
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 鉴权常量
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/11/17
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
public interface AuthConstant {
|
||||
|
||||
/**
|
||||
* 登录类型
|
||||
*/
|
||||
String GRANT_TYPE = "grant_type";
|
||||
|
||||
/**
|
||||
* 授权码
|
||||
*/
|
||||
String AUTHORIZATION_CODE = "authorization_code";
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
*/
|
||||
String REFRESH_TOKEN = "refresh_token";
|
||||
|
||||
/**
|
||||
* 认证信息Http请求头
|
||||
*/
|
||||
String JWT_TOKEN_HEADER = "Authorization";
|
||||
|
||||
/**
|
||||
* 登录token
|
||||
*/
|
||||
String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* JWT令牌前缀
|
||||
*/
|
||||
String JWT_TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* JWT载体key
|
||||
*/
|
||||
String JWT_PAYLOAD_KEY = "payload";
|
||||
|
||||
/**
|
||||
* 密码加密方式
|
||||
*/
|
||||
String ENCODE = "encode";
|
||||
|
||||
/**
|
||||
* 密码加密方式
|
||||
*/
|
||||
String BCRYPT = "{bcrypt}";
|
||||
|
||||
/**
|
||||
* 密码加密方式(不加密)
|
||||
*/
|
||||
String NOOP = "{noop}";
|
||||
|
||||
/**
|
||||
* jwt客户端id
|
||||
*/
|
||||
String CLIENT_ID_KEY = "client_id";
|
||||
|
||||
/**
|
||||
* jwt客户端id
|
||||
*/
|
||||
String CLIENTID_KEY = "client-id";
|
||||
|
||||
/**
|
||||
* jwt登录用户id
|
||||
*/
|
||||
String USERID_KEY = "id";
|
||||
|
||||
/**
|
||||
* jwt登录用户名
|
||||
*/
|
||||
String USERNAME_KEY = "username";
|
||||
|
||||
/**
|
||||
* jwt登录用户名
|
||||
*/
|
||||
String PASSWORD_KEY = "password";
|
||||
|
||||
/**
|
||||
* JWT存储权限属性
|
||||
*/
|
||||
String AUTHORITY_CLAIM_NAME = "authorities";
|
||||
|
||||
/**
|
||||
* JWT存储权限前缀
|
||||
*/
|
||||
String AUTHORITY_PREFIX = "ROLE_";
|
||||
|
||||
/**
|
||||
* JWT唯一标识
|
||||
*/
|
||||
String JTI = "jti";
|
||||
|
||||
/**
|
||||
* JWT过期时间戳
|
||||
*/
|
||||
String EXP = "exp";
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* Http 常量
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/12/9
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface HttpConstant {
|
||||
|
||||
/**
|
||||
* all
|
||||
*/
|
||||
String SLASH = "/";
|
||||
|
||||
/**
|
||||
* all
|
||||
*/
|
||||
String ALL = "/**";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
String SUCCESS = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 错误
|
||||
*/
|
||||
String FAIL = "FAIL";
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
String OK = "OK";
|
||||
|
||||
/**
|
||||
* no-cache
|
||||
*/
|
||||
String NO_CACHE = "no-cache";
|
||||
|
||||
/**
|
||||
* unknown
|
||||
*/
|
||||
String UNKNOWN = "unknown";
|
||||
|
||||
/**
|
||||
* x-forwarded-for
|
||||
*/
|
||||
String X_FORWARDER_FOR = "x-forwarded-for";
|
||||
|
||||
/**
|
||||
* Proxy-Client-IP
|
||||
*/
|
||||
String PROXY_CLIENT_IP = "Proxy-Client-IP";
|
||||
|
||||
/**
|
||||
* WL-Proxy-Client-IP
|
||||
*/
|
||||
String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
|
||||
|
||||
/**
|
||||
* HTTP_CLIENT_IP
|
||||
*/
|
||||
String HTTP_CLIENT_IP = "HTTP_CLIENT_IP";
|
||||
|
||||
/**
|
||||
* HTTP_X_FORWARDED_FOR
|
||||
*/
|
||||
String HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";
|
||||
|
||||
/**
|
||||
* api
|
||||
*/
|
||||
String API = "api";
|
||||
|
||||
//header
|
||||
/**
|
||||
* 系统平台 ios、android、windows、macos
|
||||
*/
|
||||
String OS = "os";
|
||||
|
||||
/**
|
||||
* App、wechat、tiktok-cn、alipay、baidu、H5
|
||||
*/
|
||||
String PLAT_FORM = "platform";
|
||||
|
||||
/**
|
||||
* 请求token
|
||||
*/
|
||||
String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 唯一设备号
|
||||
*/
|
||||
String DEVICE = "device";
|
||||
|
||||
/**
|
||||
* 应用版本号
|
||||
*/
|
||||
String VERSION = "version";
|
||||
|
||||
/**
|
||||
* 系统版本号
|
||||
*/
|
||||
String SYSTEM_VERSION = "systemVersion";
|
||||
|
||||
/**
|
||||
* 微信版本号
|
||||
*/
|
||||
String WECHAT_VERSION = "wechatVersion";
|
||||
|
||||
/**
|
||||
* 微信版本号
|
||||
*/
|
||||
String CLIENT_ID = "client-id";
|
||||
|
||||
/**
|
||||
* key
|
||||
*/
|
||||
String APP_KEY = "appKey";
|
||||
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
String APP_SECRET = "appSecret";
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
String TIME_STAMP = "timestamp";
|
||||
|
||||
/**
|
||||
* 随机数
|
||||
*/
|
||||
String NONCE = "nonce";
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
String SIGN = "sign";
|
||||
|
||||
/**
|
||||
* 签名忽略
|
||||
*/
|
||||
String SIGN_IGNORE = "signIgnore";
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 对象存储常量类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/4/28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface OssConstant {
|
||||
|
||||
/**
|
||||
* 默认文件夹
|
||||
*/
|
||||
String DEFAULT_FILE = "default/";
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* redis常量类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/3/4
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
public interface RedisConstant {
|
||||
|
||||
/**
|
||||
* 默认redis过期时长,单位:秒 一年
|
||||
*/
|
||||
Long YEAT_EXPIRE = 12 * 30 * 24 * 3600L;
|
||||
|
||||
/**
|
||||
* 默认redis过期时长,单位:秒 一个月
|
||||
*/
|
||||
Long DEFAULT_EXPIRE = 30 * 24 * 3600L;
|
||||
|
||||
/**
|
||||
* 失效时间 单位:(秒)一周
|
||||
*/
|
||||
Long WEEK_EXPIRE = 7 * 24 * 3600L;
|
||||
|
||||
/**
|
||||
* 失效时间 单位:(秒)一天
|
||||
*/
|
||||
Long DAY_EXPIRE = 24 * 3600L;
|
||||
|
||||
/**
|
||||
* 失效时间 单位:(秒)一小时
|
||||
*/
|
||||
Long HOUR_SECONDS = 3600L;
|
||||
|
||||
/**
|
||||
* 失效时间 单位:(秒)五分钟
|
||||
*/
|
||||
Long FIVE_MINUTES = 5 * 60L;
|
||||
|
||||
/**
|
||||
* 失效时间 单位:(秒)一分钟
|
||||
*/
|
||||
Long ONE_MINUTES = 60L;
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
String RATE_LIMIT_KEY = "rate_limit:";
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class RedisConstants implements RedisConstant {
|
||||
|
||||
/**
|
||||
* 有效期7天
|
||||
*/
|
||||
public static final long EXPIRE_TIME = 7 * 24 * 3600 * 1000;
|
||||
|
||||
/**
|
||||
* 登录用户 redis key
|
||||
*/
|
||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
public static final String SYS_DICT_KEY = "sys_dict:";
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 资源常量信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface ResourceConstants {
|
||||
|
||||
/**
|
||||
* 是否菜单外链(否)
|
||||
*/
|
||||
Integer NO_FRAME = 0;
|
||||
|
||||
/**
|
||||
* 菜单类型(目录)
|
||||
*/
|
||||
Integer TYPE_DIR = 1;
|
||||
|
||||
/**
|
||||
* 菜单类型(菜单)
|
||||
*/
|
||||
Integer TYPE_MENU = 2;
|
||||
|
||||
/**
|
||||
* 菜单类型(按钮)
|
||||
*/
|
||||
Integer TYPE_BUTTON = 3;
|
||||
|
||||
/**
|
||||
* 管理员权限标识
|
||||
*/
|
||||
String ADMIN_PERMISSIONS = "*:*:*";
|
||||
|
||||
/**
|
||||
* Layout组件标识
|
||||
*/
|
||||
String LAYOUT = "Layout";
|
||||
|
||||
/**
|
||||
* ParentView组件标识
|
||||
*/
|
||||
String PARENT_VIEW = "ParentView";
|
||||
|
||||
/**
|
||||
* InnerLink组件标识
|
||||
*/
|
||||
String INNER_LINK = "InnerLink";
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 短信常量类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface SmsConstant {
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 公用常量
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/11/17
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface StringPoolConstant {
|
||||
|
||||
String AMPERSAND = "&";
|
||||
String AND = "and";
|
||||
String AT = "@";
|
||||
String ASTERISK = "*";
|
||||
String STAR = ASTERISK;
|
||||
String BACK_SLASH = "\\";
|
||||
String COLON = ":";
|
||||
String COMMA = ",";
|
||||
String DASH = "-";
|
||||
String DOLLAR = "$";
|
||||
String DOT = ".";
|
||||
String DOTDOT = "..";
|
||||
String DOT_CLASS = ".class";
|
||||
String DOT_JAVA = ".java";
|
||||
String DOT_XML = ".xml";
|
||||
String EMPTY = "";
|
||||
String EQUALS = "=";
|
||||
String FALSE = "false";
|
||||
String SLASH = "/";
|
||||
String HASH = "#";
|
||||
String HAT = "^";
|
||||
String LEFT_BRACE = "{";
|
||||
String LEFT_BRACKET = "(";
|
||||
String LEFT_CHEV = "<";
|
||||
String NEWLINE = "\n";
|
||||
String N = "n";
|
||||
String NO = "no";
|
||||
String NULL = "null";
|
||||
String OFF = "off";
|
||||
String ON = "on";
|
||||
String PERCENT = "%";
|
||||
String PIPE = "|";
|
||||
String PLUS = "+";
|
||||
String QUESTION_MARK = "?";
|
||||
String EXCLAMATION_MARK = "!";
|
||||
String QUOTE = "\"";
|
||||
String RETURN = "\r";
|
||||
String TAB = "\t";
|
||||
String RIGHT_BRACE = "}";
|
||||
String RIGHT_BRACKET = ")";
|
||||
String RIGHT_CHEV = ">";
|
||||
String SEMICOLON = ";";
|
||||
String SINGLE_QUOTE = "'";
|
||||
String BACKTICK = "`";
|
||||
String SPACE = " ";
|
||||
String TILDA = "~";
|
||||
String LEFT_SQ_BRACKET = "[";
|
||||
String RIGHT_SQ_BRACKET = "]";
|
||||
String TRUE = "true";
|
||||
String UNDERSCORE = "_";
|
||||
String Y = "y";
|
||||
String YES = "yes";
|
||||
String ONE = "1";
|
||||
String ZERO = "0";
|
||||
String DOLLAR_LEFT_BRACE = "${";
|
||||
String HASH_LEFT_BRACE = "#{";
|
||||
String CRLF = "\r\n";
|
||||
|
||||
String HTML_NBSP = " ";
|
||||
String HTML_AMP = "&";
|
||||
String HTML_QUOTE = """;
|
||||
String HTML_LT = "<";
|
||||
String HTML_GT = ">";
|
||||
|
||||
// ---------------------------------------------------------------- array
|
||||
|
||||
String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
String PAGE = "page";
|
||||
String LIMIT = "limit";
|
||||
String HTTPS = "https://";
|
||||
String SUCCESS = "SUCCESS";
|
||||
String ERROR = "ERROR";
|
||||
String APP_NAME = "appName";
|
||||
String APP_ID = "appId";
|
||||
String UNDEFINED = "undefined";
|
||||
String RSA2 = "RSA2";
|
||||
String JSON = "json";
|
||||
String CORE_PREFIX = "99";
|
||||
String MINUS_ONE = "-1";
|
||||
String MD5 = "md5";
|
||||
String KEY = "key";
|
||||
String OK = "OK";
|
||||
String RESULT_CODE = "result_code";
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.hula.ai.common.constant;
|
||||
|
||||
/**
|
||||
* 系统配置常量
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/01/31
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public interface SysConfigConstants {
|
||||
|
||||
/**
|
||||
* 验证码开关
|
||||
*/
|
||||
String CAPTCHA_ON_OFF = "sys.account.captchaOnOff";
|
||||
|
||||
/**
|
||||
* 注册开关
|
||||
*/
|
||||
String REGISTER_ON_OFF = "sys.account.registerUser";
|
||||
|
||||
/**
|
||||
* 是否开启同时登录
|
||||
*/
|
||||
String ALL_LOGIN = "sys.account.allLogin";
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.hula.ai.common.constants;
|
||||
|
||||
|
||||
import com.hula.ai.common.pojo.ErrorCode;
|
||||
|
||||
/**
|
||||
* 全局错误码枚举
|
||||
* 0-999 系统异常编码保留
|
||||
*
|
||||
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
|
||||
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
|
||||
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface GlobalErrorCodeConstants {
|
||||
|
||||
ErrorCode SUCCESS = new ErrorCode(0, "成功");
|
||||
|
||||
// ========== 客户端错误段 ==========
|
||||
|
||||
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
|
||||
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
|
||||
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
|
||||
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
|
||||
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
|
||||
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
|
||||
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
|
||||
|
||||
// ========== 服务端错误段 ==========
|
||||
|
||||
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
|
||||
ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
|
||||
|
||||
// ========== 自定义错误段 ==========
|
||||
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
|
||||
|
||||
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package com.hula.ai.common.converter;
|
||||
|
||||
import com.github.dozermapper.core.DozerConverter;
|
||||
import com.hula.ai.common.constant.StringPoolConstant;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* BigDecimal数据类型转String
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/15
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class BigDecimalToStringConverter extends DozerConverter<BigDecimal, String> {
|
||||
|
||||
public BigDecimalToStringConverter() {
|
||||
super(BigDecimal.class, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertTo(BigDecimal a1, String a2) {
|
||||
return a1 == null ? StringPoolConstant.ZERO : a1.toPlainString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal convertFrom(String a1, BigDecimal a2) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package com.hula.ai.common.converter;
|
||||
|
||||
import com.github.dozermapper.core.DozerConverter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Double数据类型转BigDecimal
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/15
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class DoubleToBigDecimalConverter extends DozerConverter<Double, BigDecimal> {
|
||||
public DoubleToBigDecimalConverter() {
|
||||
super(Double.class, BigDecimal.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal convertTo(Double a1, BigDecimal a2) {
|
||||
a1 = a1 == null ? 0.0 : a1;
|
||||
return new BigDecimal(a1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double convertFrom(BigDecimal a1, Double a2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.hula.ai.common.converter;
|
||||
|
||||
import com.github.dozermapper.core.DozerConverter;
|
||||
|
||||
/**
|
||||
* 转为数值类型处理
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/15
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
public class ToNumberConverter extends DozerConverter<Object, Object> {
|
||||
|
||||
public ToNumberConverter() {
|
||||
super(Object.class, Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertTo(Object a1, Object a2) {
|
||||
return a1 instanceof Number ? (Number) a1 : a1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertFrom(Object a1, Object a2) {
|
||||
return a1 instanceof Number ? (Number) a1 : a1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.hula.ai.common.dict;
|
||||
|
||||
|
||||
import com.hula.ai.common.dict.dto.DictDataRespDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典数据 API 接口
|
||||
*
|
||||
*/
|
||||
public interface DictDataCommonApi {
|
||||
|
||||
/**
|
||||
* 获得指定字典类型的字典数据列表
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @return 字典数据列表
|
||||
*/
|
||||
List<DictDataRespDTO> getDictDataList(String dictType);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.hula.ai.common.dict.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 字典数据 Response DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class DictDataRespDTO {
|
||||
|
||||
/**
|
||||
* 字典标签
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* 字典值
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 字典类型
|
||||
*/
|
||||
private String dictType;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link com.hula.ai.enums.CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.hula.ai.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 数字枚举
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/10/21
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum IntEnum {
|
||||
|
||||
/**
|
||||
* 数值
|
||||
*/
|
||||
MINUS_ONE(-1),
|
||||
|
||||
ZERO(0),
|
||||
|
||||
ONE(1),
|
||||
|
||||
TWO(2),
|
||||
|
||||
THREE(3),
|
||||
|
||||
FOUR(4),
|
||||
|
||||
FIVE(5),
|
||||
|
||||
SIX(6),
|
||||
|
||||
SEVEN(7),
|
||||
|
||||
EIGHT(8),
|
||||
|
||||
NINE(9),
|
||||
|
||||
TEN(10),
|
||||
|
||||
ELEVEN(11),
|
||||
|
||||
TWELVE(12),
|
||||
|
||||
THIRTEEN(13),
|
||||
|
||||
FOURTEEN(14),
|
||||
|
||||
FIFTEEN(15),
|
||||
|
||||
SIXTEEN(16),
|
||||
|
||||
SEVENTEEN(17),
|
||||
|
||||
EIGHTEEN(18),
|
||||
|
||||
NINETEEN(19),
|
||||
|
||||
TWENTY(20);
|
||||
|
||||
private final int value;
|
||||
|
||||
IntEnum(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.hula.ai.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 数字枚举
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/10/21
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum IntegerEnum {
|
||||
|
||||
/**
|
||||
* 数值
|
||||
*/
|
||||
MINUS_ONE(-1),
|
||||
|
||||
ZERO(0),
|
||||
|
||||
ONE(1),
|
||||
|
||||
TWO(2),
|
||||
|
||||
THREE(3),
|
||||
|
||||
FOUR(4),
|
||||
|
||||
FIVE(5),
|
||||
|
||||
SIX(6),
|
||||
|
||||
SEVEN(7),
|
||||
|
||||
EIGHT(8),
|
||||
|
||||
NINE(9),
|
||||
|
||||
TEN(10),
|
||||
|
||||
ELEVEN(11),
|
||||
|
||||
TWELVE(12),
|
||||
|
||||
TTHIRTEEN(13),
|
||||
|
||||
FOURTEEN(14),
|
||||
|
||||
FIFTEEN(15),
|
||||
|
||||
SIXTEEN(16),
|
||||
|
||||
SEVENTEEN(17),
|
||||
|
||||
EIGHTEEN(18),
|
||||
|
||||
NINETEEN(19),
|
||||
|
||||
TWENTY(20);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
IntegerEnum(final Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.hula.ai.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 运行操作系统枚举
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/3/22 10:27
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum OperateSystemEnum {
|
||||
|
||||
/**
|
||||
* 操作系统简称
|
||||
*/
|
||||
Any("any"),
|
||||
Linux("Linux"),
|
||||
Mac_OS("Mac OS"),
|
||||
Mac_OS_X("Mac OS X"),
|
||||
Windows("Windows"),
|
||||
OS2("OS/2"),
|
||||
Solaris("Solaris"),
|
||||
SunOS("SunOS"),
|
||||
MPEiX("MPE/iX"),
|
||||
HP_UX("HP-UX"),
|
||||
AIX("AIX"),
|
||||
OS390("OS/390"),
|
||||
FreeBSD("FreeBSD"),
|
||||
Irix("Irix"),
|
||||
Digital_Unix("Digital Unix"),
|
||||
NetWare_411("NetWare"),
|
||||
OSF1("OSF1"),
|
||||
OpenVMS("OpenVMS"),
|
||||
Others("Others");
|
||||
|
||||
private final String value;
|
||||
|
||||
private OperateSystemEnum(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.hula.ai.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 全局返回参数
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/8/6
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum ResponseEnum {
|
||||
|
||||
/**
|
||||
* 返回内容
|
||||
*/
|
||||
SUCCESS(200, "操作成功"),
|
||||
SUCCESS_NODATE(204, "操作成功"),
|
||||
BAD_REQUEST(400, "参数错误"),
|
||||
PROHIBIT_VISIT(401, "账号认证失败,请重新登录"),
|
||||
PERMISSION_DENIED(403, "权限不足,无法操作"),
|
||||
RESOURCES_ERROR(404, "访问资源丢失,请升级相应版本或检查请求路径"),
|
||||
|
||||
SING_ERROR(406, "签名验证失败"),
|
||||
REQUEST_METHOD_ERROR(407, "啊哟,请求方式错了哦,请确认API请求方式GET/POST/PUT/DELETE"),
|
||||
CONNECT_TIME_OUT(408, "连接超时啦,请稍后再试哦"),
|
||||
TOO_MANY_REQUESTS(429, "请求未受理,请降低频率后重试"),
|
||||
ERROR(500, "服务器繁忙,请稍后再试。"),
|
||||
BUSINESS_ERROR(600, "业务出错,请联系客服"),
|
||||
SYSTEM_WARNING(601, "系统预警,请及时处理"),
|
||||
|
||||
/**
|
||||
* 内部错误码
|
||||
*/
|
||||
NO_LOGIN(4011, "未登录"),
|
||||
|
||||
ACCOUNT_LOGIN_EXIST(4011, "该账号已在其他地方登录,请重新登录"),
|
||||
|
||||
ACCOUNT_NOT_EXIST(4012, "账号不存在,请先注册或联系管理员创建"),
|
||||
|
||||
ACCOUNT_IS_DISABLED(4013, "账号已被禁用,请联系管理员"),
|
||||
|
||||
NAME_IS_EXIST(4014, "账号已存在,请核对账号信息"),
|
||||
|
||||
TEL_IS_EXIST(4015, "该手机号已经注册,请直接登录"),
|
||||
|
||||
PHONE_BINDING(4016, "请先绑定手机号"),
|
||||
|
||||
PASSWORD_ERROR(4017, "账号密码错误"),
|
||||
|
||||
SMS_ERROR(4018, "验证码错误"),
|
||||
|
||||
REPEAT_REQUEST_SMS(4019, "验证码有限期为5分钟,无需重复获取"),
|
||||
|
||||
FILE_ERROR(6010, "文件处理失败,请稍后再试");
|
||||
private final Integer code;
|
||||
private final String msg;
|
||||
|
||||
ResponseEnum(final Integer code, final String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.hula.ai.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 状态枚举
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/8/6
|
||||
* @version: 1.2.8
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Getter
|
||||
public enum StatusEnum {
|
||||
|
||||
/**
|
||||
* 禁用
|
||||
*/
|
||||
DISABLED(0),
|
||||
|
||||
/**
|
||||
* 启用
|
||||
*/
|
||||
ENABLED(1);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
StatusEnum(final Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.hula.ai.common.exception;
|
||||
|
||||
import com.hula.ai.common.enums.ResponseEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文件处理异常
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/3/4
|
||||
* @version: 3.0.0
|
||||
* 得其道
|
||||
*/
|
||||
@Data
|
||||
public class FileException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
private String msg;
|
||||
|
||||
public FileException() {
|
||||
this.code = ResponseEnum.FILE_ERROR.getCode();
|
||||
this.msg = ResponseEnum.FILE_ERROR.getMsg();
|
||||
}
|
||||
|
||||
public FileException(String msg) {
|
||||
super(msg);
|
||||
this.code = ResponseEnum.FILE_ERROR.getCode();
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.hula.ai.common.exception;
|
||||
|
||||
import com.hula.ai.common.enums.ResponseEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据库更新失败手动抛出异常
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/3/4
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class UpdateFailedException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
private String msg;
|
||||
|
||||
public UpdateFailedException() {
|
||||
this.code = ResponseEnum.ERROR.getCode();
|
||||
this.msg = "数据更新失败,请稍后重新尝试";
|
||||
}
|
||||
|
||||
public UpdateFailedException(String msg) {
|
||||
super(msg);
|
||||
this.code = ResponseEnum.ERROR.getCode();
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.hula.ai.common.exception;
|
||||
|
||||
import com.hula.ai.common.enums.ResponseEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 参数验证失败异常
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/3/4
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class ValidateException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
private String msg;
|
||||
|
||||
public ValidateException() {
|
||||
this.code = ResponseEnum.BAD_REQUEST.getCode();
|
||||
this.msg = ResponseEnum.BAD_REQUEST.getMsg();
|
||||
}
|
||||
|
||||
public ValidateException(String msg) {
|
||||
super(msg);
|
||||
this.code = ResponseEnum.BAD_REQUEST.getCode();
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package com.hula.ai.common;
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.hula.ai.common.constants.GlobalErrorCodeConstants;
|
||||
import com.hula.ai.exception.ServiceException;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 通用返回
|
||||
*
|
||||
* @param <T> 数据泛型
|
||||
*/
|
||||
@Data
|
||||
public class CommonResult<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*
|
||||
* @see ErrorCode#getCode()
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T data;
|
||||
/**
|
||||
* 错误提示,用户可阅读
|
||||
*
|
||||
* @see ErrorCode#getMsg() ()
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 将传入的 result 对象,转换成另外一个泛型结果的对象
|
||||
*
|
||||
* 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
|
||||
*
|
||||
* @param result 传入的 result 对象
|
||||
* @param <T> 返回的泛型
|
||||
* @return 新的 CommonResult 对象
|
||||
*/
|
||||
public static <T> ApiResult<T> error(CommonResult<?> result) {
|
||||
return error(result.getCode(), result.getMsg());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> error(Integer code, String message) {
|
||||
return ApiResult.fail(code, message);
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> error(ErrorCode errorCode) {
|
||||
return ApiResult.fail(errorCode.getCode(), errorCode.getMsg());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> success(T data) {
|
||||
return ApiResult.success(data);
|
||||
}
|
||||
|
||||
public static boolean isSuccess(Integer code) {
|
||||
return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
|
||||
}
|
||||
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public boolean isSuccess() {
|
||||
return isSuccess(code);
|
||||
}
|
||||
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public boolean isError() {
|
||||
return !isSuccess();
|
||||
}
|
||||
|
||||
// ========= 和 Exception 异常体系集成 =========
|
||||
|
||||
/**
|
||||
* 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
|
||||
*/
|
||||
public void checkError() throws ServiceException {
|
||||
if (isSuccess()) {
|
||||
return;
|
||||
}
|
||||
// 业务异常
|
||||
throw new ServiceException(code, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
|
||||
* 如果没有,则返回 {@link #data} 数据
|
||||
*/
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public T getCheckedData() {
|
||||
checkError();
|
||||
return data;
|
||||
}
|
||||
|
||||
public static <T> ApiResult<Object> error(ServiceException serviceException) {
|
||||
return error(serviceException.getCode(), serviceException.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 错误码对象
|
||||
*
|
||||
* 全局错误码,占用 [0, 999], 参见 {@link com.hula.ai.common.constants.GlobalErrorCodeConstants}
|
||||
* 业务异常错误码,占用 [1 000 000 000, +∞),参见
|
||||
*
|
||||
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
|
||||
*/
|
||||
@Data
|
||||
public class ErrorCode {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private final Integer code;
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
public ErrorCode(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.msg = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Schema(description="分页参数")
|
||||
@Data
|
||||
public class PageParam implements Serializable {
|
||||
|
||||
private static final Integer PAGE_NO = 1;
|
||||
private static final Integer PAGE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* 每页条数 - 不分页
|
||||
*
|
||||
* 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。
|
||||
*/
|
||||
public static final Integer PAGE_SIZE_NONE = -1;
|
||||
|
||||
@Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
|
||||
@NotNull(message = "页码不能为空")
|
||||
@Min(value = 1, message = "页码最小值为 1")
|
||||
private Integer pageNo = PAGE_NO;
|
||||
|
||||
@Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
@NotNull(message = "每页条数不能为空")
|
||||
@Min(value = 1, message = "每页条数最小值为 1")
|
||||
@Max(value = 100, message = "每页条数最大值为 100")
|
||||
private Integer pageSize = PAGE_SIZE;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "分页结果")
|
||||
@Data
|
||||
public final class PageResult<T> implements Serializable {
|
||||
|
||||
@Schema(description = "数据", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<T> list;
|
||||
|
||||
@Schema(description = "总量", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long total;
|
||||
|
||||
public PageResult() {
|
||||
}
|
||||
|
||||
public PageResult(List<T> list, Long total) {
|
||||
this.list = list;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public PageResult(Long total) {
|
||||
this.list = new ArrayList<>();
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public static <T> PageResult<T> empty() {
|
||||
return new PageResult<>(0L);
|
||||
}
|
||||
|
||||
public static <T> PageResult<T> empty(Long total) {
|
||||
return new PageResult<>(total);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "可排序的分页参数")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class SortablePageParam extends PageParam {
|
||||
|
||||
@Schema(description = "排序字段")
|
||||
private List<SortingField> sortingFields;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.hula.ai.common.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 排序字段 DTO
|
||||
*
|
||||
* 类名加了 ing 的原因是,避免和 ES SortField 重名。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SortingField implements Serializable {
|
||||
|
||||
/**
|
||||
* 顺序 - 升序
|
||||
*/
|
||||
public static final String ORDER_ASC = "asc";
|
||||
/**
|
||||
* 顺序 - 降序
|
||||
*/
|
||||
public static final String ORDER_DESC = "desc";
|
||||
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
private String field;
|
||||
/**
|
||||
* 顺序
|
||||
*/
|
||||
private String order;
|
||||
|
||||
}
|
||||
@@ -1,778 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 日期工具类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2019/8/29
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
/**
|
||||
* 自定义格式化
|
||||
*/
|
||||
public static final String YEAR_MONTH_FORMATTER = "yyyy-MM";
|
||||
public static final String DATE_FORMATTER = "yyyy-MM-dd";
|
||||
public static final String TIME_MIN_FORMATTER = "HH:mm";
|
||||
public static final String TIME_FORMATTER = "HH:mm:ss";
|
||||
public static final String DATETIME_FORMATTER = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String DATETIME_ZONE_FORMATTER = "yyyy-MM-dd'T'HH:mm:ssXXX";
|
||||
|
||||
public static final String DATE_FORMATTER_SLASH = "yyyy/MM/dd";
|
||||
|
||||
public static final String DATE_FORMATTER_SHORT = "yyyyMMdd";
|
||||
public static final String YEAR_MONTH_FORMATTER_SHORT = "yyyyMM";
|
||||
public static final String TIME_FORMATTER_SHORT = "HHmmss";
|
||||
public static final String DATETIME_FORMATTER_SHORT = "yyyyMMddHHmmss";
|
||||
|
||||
public final static String YEAR_MONTH_CHINESE_FORMATTER = "yyyy年MM月";
|
||||
public final static String DATE_CHINESE_FORMATTER = "yyyy年MM月dd日";
|
||||
public final static String DATE_TIME_CHINESE_FORMATTER = "yyyy年MM月dd日 HH时mm分ss秒";
|
||||
|
||||
/**
|
||||
* Mysql 日期格式(yyyy-MM-dd)
|
||||
*/
|
||||
public final static String MYSQL_YEAR_MONTH_PATTERN = "%Y-%m";
|
||||
public final static String MYSQL_DATE_FORMATTER = "%Y-%m-%d";
|
||||
public final static String MYSQL_DATETIME_PATTERN = "%Y-%m-%d %H:%i:%S";
|
||||
|
||||
/**
|
||||
* 24小时时间正则表达式
|
||||
*/
|
||||
public static final String MATCH_TIME_24 = "(([0-1][0-9])|2[0-3]):[0-5][0-9]:[0-5][0-9]";
|
||||
/**
|
||||
* 日期正则表达式
|
||||
*/
|
||||
public static final String REGEX_DATA = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
|
||||
|
||||
/**
|
||||
* 日期格式化字符串
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String formatLocalDate(LocalDate localDate, String pattern) {
|
||||
return localDate.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式化字符串
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String formatLocalTime(LocalTime localTime, String pattern) {
|
||||
return localTime.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间格式化字符串
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String formatLocalDateTime(LocalDateTime localDateTime, String pattern) {
|
||||
return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化字符串
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @return yyyy-MM-dd
|
||||
*/
|
||||
public static String formatLocalDate(LocalDate localDate) {
|
||||
return formatLocalDate(localDate, DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化字符串
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @return yyyyMMdd
|
||||
*/
|
||||
public static String formatLocalDateShort(LocalDate localDate) {
|
||||
return formatLocalDate(localDate, DATE_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式化字符串
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @return HH:mm:ss
|
||||
*/
|
||||
public static String formatLocalTime(LocalTime localTime) {
|
||||
return formatLocalTime(localTime, TIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式化字符串
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @return HHmmss
|
||||
*/
|
||||
public static String formatLocalTimeShort(LocalTime localTime) {
|
||||
return formatLocalTime(localTime, TIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间格式化字符串
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String formatLocalDateTime(LocalDateTime localDateTime) {
|
||||
return formatLocalDateTime(localDateTime, DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间格式化字符串
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return yyyyMMddHHmmss
|
||||
*/
|
||||
public static String formatLocalDateTimeShort(LocalDateTime localDateTime) {
|
||||
return formatLocalDateTime(localDateTime, DATETIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转日期
|
||||
*
|
||||
* @param timestamp 时间戳
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String formatTimestamp(long timestamp, String pattern) {
|
||||
Instant instant = Instant.ofEpochMilli(timestamp);
|
||||
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
return formatLocalDateTime(localDateTime, pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转日期时间
|
||||
*
|
||||
* @param timestamp 时间戳
|
||||
* @return yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String formatTimestamp(long timestamp) {
|
||||
return formatTimestamp(timestamp, DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转日期时间
|
||||
*
|
||||
* @param timestamp 时间戳
|
||||
* @return yyyyMMddHHmmss
|
||||
*/
|
||||
public static String formatTimestampShort(long timestamp) {
|
||||
return formatTimestamp(timestamp, DATETIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期字符串转日期
|
||||
*
|
||||
* @param date 日期字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDate parseLocalDate(String date, String pattern) {
|
||||
return LocalDate.parse(date, DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间字符串转时间
|
||||
*
|
||||
* @param time 时间字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalTime parseLocalTime(String time, String pattern) {
|
||||
return LocalTime.parse(time, DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时间
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTime(String dateTime, String pattern) {
|
||||
return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期字符串转日期
|
||||
*
|
||||
* @param date 日期字符串
|
||||
*/
|
||||
public static LocalDate parseLocalDate(String date) {
|
||||
return LocalDate.parse(date, DateTimeFormatter.ofPattern(DATE_FORMATTER));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时间
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
*/
|
||||
public static LocalTime parseLocalTime(String time) {
|
||||
return LocalTime.parse(time, DateTimeFormatter.ofPattern(TIME_FORMATTER));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时间
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTime(String dateTime) {
|
||||
return parseLocalDateTime(dateTime, DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时间
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTimeShort(String dateTime) {
|
||||
return parseLocalDateTime(dateTime, DATETIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date转换成LocalDateTime
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTime(Date date) {
|
||||
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDate转换成Date
|
||||
*
|
||||
* @param localDate
|
||||
* @return
|
||||
*/
|
||||
public static Date parseDate(LocalDate localDate) {
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDateTime转换成Date
|
||||
*
|
||||
* @param localDateTime
|
||||
* @return
|
||||
*/
|
||||
public static Date parseDate(LocalDateTime localDateTime) {
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
Instant instant = localDateTime.atZone(zone).toInstant();
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时间
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static Date parseDate(String date, String pattern) {
|
||||
SimpleDateFormat format = new SimpleDateFormat(pattern);
|
||||
try {
|
||||
return format.parse(date);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期时间字符串转日期时
|
||||
*
|
||||
* @param dateTime 日期时间字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static Date parseDate(String date) {
|
||||
return parseDate(date, DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 时间戳转日期
|
||||
*
|
||||
* @param date 日期
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String formatDate(Date date, String pattern) {
|
||||
return formatTimestamp(date.getTime(), pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化字符串
|
||||
*
|
||||
* @param date 日期
|
||||
* @return yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String formatDate(Date date) {
|
||||
return formatDate(date, DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期转时间戳
|
||||
*
|
||||
* @param localDateTime 日期
|
||||
*/
|
||||
public static long localDateTimeToTimestamp(LocalDateTime localDateTime) {
|
||||
return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转日期
|
||||
*
|
||||
* @param timestamp 时间戳
|
||||
*/
|
||||
public static LocalDateTime timestampToLocalDateTime(long timestamp) {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public static long getTimestamp() {
|
||||
return Instant.now().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前年份
|
||||
*
|
||||
* @return yyyy
|
||||
*/
|
||||
public static int getCurrentYear() {
|
||||
return LocalDate.now().getYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期
|
||||
*
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String getCurrentDate(String pattern) {
|
||||
return formatLocalDate(LocalDate.now(), pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间
|
||||
*
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String getCurrentTime(String pattern) {
|
||||
return formatLocalTime(LocalTime.now(), pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期时间
|
||||
*
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String getCurrentDateTime(String pattern) {
|
||||
return formatLocalDateTime(LocalDateTime.now(), pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前年月
|
||||
*
|
||||
* @return yyyy-MM
|
||||
*/
|
||||
public static String getCurrentYearMonth() {
|
||||
return getCurrentDate(YEAR_MONTH_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期
|
||||
*
|
||||
* @return yyyy-MM-dd
|
||||
*/
|
||||
public static String getCurrentDate() {
|
||||
return getCurrentDate(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间
|
||||
*
|
||||
* @return HH:mm:ss
|
||||
*/
|
||||
public static String getCurrentTime() {
|
||||
return getCurrentTime(TIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期时间
|
||||
*
|
||||
* @return yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String getCurrentDateTime() {
|
||||
return getCurrentDateTime(DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前年月
|
||||
*
|
||||
* @return yyyyMM
|
||||
*/
|
||||
public static String getCurrentYearMonthShort() {
|
||||
return getCurrentDate(YEAR_MONTH_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期
|
||||
*
|
||||
* @return yyyyMMdd
|
||||
*/
|
||||
public static String getCurrentDateShort() {
|
||||
return getCurrentDate(DATE_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间
|
||||
*
|
||||
* @return HHmmss
|
||||
*/
|
||||
public static String getCurrentTimeShort() {
|
||||
return getCurrentTime(TIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期时间
|
||||
*
|
||||
* @return yyyyMMddHHmmss
|
||||
*/
|
||||
public static String getCurrentDateTimeShort() {
|
||||
return getCurrentDateTime(DATETIME_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前星期
|
||||
*
|
||||
* @return 星期一、星期二、星期三、星期四、星期五、星期六、星期日
|
||||
*/
|
||||
public static String getCurrentWeek(int week) {
|
||||
String[] strings = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};
|
||||
List<String> list = Arrays.asList(strings);
|
||||
return list.get(week - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前星期
|
||||
*
|
||||
* @return 1:星期一、2:星期二、3:星期三、4:星期四、5:星期五、6:星期六、7:星期日
|
||||
*/
|
||||
public static int getCurrentWeek() {
|
||||
return LocalDate.now().getDayOfWeek().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期的星期
|
||||
*
|
||||
* @param date 日期字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static int getWeek(String date, String pattern) {
|
||||
return parseLocalDate(date, pattern).getDayOfWeek().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前星期
|
||||
*
|
||||
* @param localDate 日期
|
||||
*/
|
||||
public static int getWeek(LocalDate localDate) {
|
||||
return localDate.getDayOfWeek().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本周第一天
|
||||
*/
|
||||
public static LocalDate getCurrentWeekFirstDate() {
|
||||
return LocalDate.now().minusWeeks(0).with(DayOfWeek.MONDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本周最后一天
|
||||
*/
|
||||
public static LocalDate getCurrentWeekLastDate() {
|
||||
return LocalDate.now().minusWeeks(0).with(DayOfWeek.SUNDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定周第一天
|
||||
*
|
||||
* @param localDate 日期
|
||||
*/
|
||||
public static LocalDate getWeekFirstDate(LocalDate localDate) {
|
||||
return localDate.minusWeeks(0).with(DayOfWeek.MONDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定周最后一天
|
||||
*
|
||||
* @param localDate 日期
|
||||
*/
|
||||
public static LocalDate getWeekLastDate(LocalDate localDate) {
|
||||
return localDate.minusWeeks(0).with(DayOfWeek.SUNDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定周第一天
|
||||
*
|
||||
* @param date 日期字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDate getWeekFirstDate(String date, String pattern) {
|
||||
return parseLocalDate(date, pattern).minusWeeks(0).with(DayOfWeek.MONDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定周最后一天
|
||||
*
|
||||
* @param date 日期字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDate getWeekLastDate(String date, String pattern) {
|
||||
return parseLocalDate(date, pattern).minusWeeks(0).with(DayOfWeek.SUNDAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本月第一天
|
||||
*/
|
||||
public static LocalDate getCurrentMonthFirstDate() {
|
||||
return LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本月最后一天
|
||||
*/
|
||||
public static LocalDate getCurrentMonthLastDate() {
|
||||
return LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定月份月第一天
|
||||
*
|
||||
* @param date 日期字符串
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static LocalDate getMonthFirstDate(String date, String pattern) {
|
||||
return parseLocalDate(date, pattern).with(TemporalAdjusters.firstDayOfMonth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定月份月第一天
|
||||
*
|
||||
* @param localDate
|
||||
*/
|
||||
public static LocalDate getMonthFirstDate(LocalDate localDate) {
|
||||
return localDate.with(TemporalAdjusters.firstDayOfMonth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一天日期
|
||||
*
|
||||
* @param pattern 格式化
|
||||
*/
|
||||
public static String getNextDate(String pattern) {
|
||||
return LocalDate.now().plusDays(1).format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一天日期
|
||||
*
|
||||
* @return yyyy-MM-dd
|
||||
*/
|
||||
public static String getNextDate() {
|
||||
return getNextDate(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一天日期
|
||||
*
|
||||
* @return yyyy-MM-dd
|
||||
*/
|
||||
public static String getNextDateShort() {
|
||||
return getNextDate(DATE_FORMATTER_SHORT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算距今天指定天数的日期
|
||||
*
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
public static String getDateAfterDays(int days) {
|
||||
Calendar date = Calendar.getInstance();
|
||||
date.add(Calendar.DATE, days);
|
||||
SimpleDateFormat simpleDate = new SimpleDateFormat(DATE_FORMATTER);
|
||||
return simpleDate.format(date.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定的日期的前几天或后几天
|
||||
*
|
||||
* @param source 源日期(yyyy-MM-dd)
|
||||
* @param days 指定的天数,正负皆可
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static String addDays(String source, int days) {
|
||||
Date date = parseDate(parseLocalDate(source, DATE_FORMATTER));
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(Calendar.DATE, days);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMATTER);
|
||||
return dateFormat.format(calendar.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期相隔天数
|
||||
*
|
||||
* @param startLocalDate 起日期
|
||||
* @param endLocalDate 止日期
|
||||
*/
|
||||
public static long intervalDays(LocalDate startLocalDate, LocalDate endLocalDate) {
|
||||
return endLocalDate.toEpochDay() - startLocalDate.toEpochDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期相隔小时
|
||||
*
|
||||
* @param startLocalDateTime 起日期时间
|
||||
* @param endLocalDateTime 止日期时间
|
||||
*/
|
||||
public static long intervalHours(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
|
||||
return Duration.between(startLocalDateTime, endLocalDateTime).toHours();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期相隔分钟
|
||||
*
|
||||
* @param startLocalDateTime 起日期时间
|
||||
* @param endLocalDateTime 止日期时间
|
||||
*/
|
||||
public static long intervalMinutes(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
|
||||
return Duration.between(startLocalDateTime, endLocalDateTime).toMinutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期相隔毫秒数
|
||||
*
|
||||
* @param startLocalDateTime 起日期时间
|
||||
* @param endLocalDateTime 止日期时间
|
||||
*/
|
||||
public static long intervalMillis(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
|
||||
return Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 相隔时间字符串
|
||||
*/
|
||||
public static String intervalTimes(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return intervalDays(startDate.toLocalDate(), endDate.toLocalDate()) + "天" + intervalHours(startDate, endDate) + "小时" + intervalMinutes(startDate, endDate) + "分钟";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此日期时间与默认时区<Asia/Shanghai>组合的时间毫秒数
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
*/
|
||||
public static Long toEpochMilli(LocalDateTime localDateTime) {
|
||||
return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此日期时间与指定时区组合的时间毫秒数
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
*/
|
||||
public static Long toSelectEpochMilli(LocalDateTime localDateTime, ZoneId zoneId) {
|
||||
return localDateTime.atZone(zoneId).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否闰年
|
||||
*/
|
||||
public static boolean isCurrentLeapYear() {
|
||||
return LocalDate.now().isLeapYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否闰年
|
||||
*/
|
||||
public static boolean isLeapYear(LocalDate localDate) {
|
||||
return localDate.isLeapYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否当天
|
||||
*
|
||||
* @param localDate 日期
|
||||
*/
|
||||
public static boolean isToday(LocalDate localDate) {
|
||||
return LocalDate.now().equals(localDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 24小时时间校验
|
||||
*
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidate24(String time) {
|
||||
Pattern p = Pattern.compile(MATCH_TIME_24);
|
||||
return p.matcher(time).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期校验
|
||||
*
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDate(String date) {
|
||||
Pattern pat = Pattern.compile(REGEX_DATA);
|
||||
Matcher mat = pat.matcher(date);
|
||||
return mat.matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前时间是否在指定时间范围
|
||||
*
|
||||
* @param from 开始时间
|
||||
* @param to 结束时间
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean between(LocalTime from, LocalTime to) {
|
||||
LocalTime now = LocalTime.now();
|
||||
return now.isAfter(from) && now.isBefore(to);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import com.github.dozermapper.core.DozerBeanMapperBuilder;
|
||||
import com.github.dozermapper.core.Mapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Java Bean 转换工具类
|
||||
* 默认转换类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/12/24
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class DozerUtil {
|
||||
/**
|
||||
* 持有Dozer单例, 避免重复创建DozerMapper消耗资源.
|
||||
*/
|
||||
private static Mapper MAPPER = DozerBeanMapperBuilder.buildDefault();
|
||||
|
||||
public static void init(Mapper mapper) {
|
||||
DozerUtil.MAPPER = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* List 实体类 转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 转换类型
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> List<T> convertor(List<S> source, Class<T> clz) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
List<T> list = new ArrayList<>();
|
||||
for (S s : source) {
|
||||
list.add(MAPPER.map(s, clz));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* List 实体类 深度转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 转换类型
|
||||
* @param mapId 自定义转换
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> List<T> convertor(List<S> source, Class<T> clz, String mapId) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
List<T> list = new ArrayList<>();
|
||||
for (S s : source) {
|
||||
list.add(MAPPER.map(s, clz, mapId));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set 实体类 转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 目标对象
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> Set<T> convertor(Set<S> source, Class<T> clz) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Set<T> set = new TreeSet<>();
|
||||
for (S s : source) {
|
||||
set.add(MAPPER.map(s, clz));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 实体类 深度转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 目标对象
|
||||
* @param mapId 自定义转换
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> Set<T> convertor(Set<S> source, Class<T> clz, String mapId) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Set<T> set = new TreeSet<>();
|
||||
for (S s : source) {
|
||||
set.add(MAPPER.map(s, clz, mapId));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类 转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 目标对象
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> T convertor(S source, Class<T> clz) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return MAPPER.map(source, clz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类 深度转换器
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param clz 目标对象
|
||||
* @param mapId 自定义转换
|
||||
* @return
|
||||
*/
|
||||
public static <T, S> T convertor(S source, Class<T> clz, String mapId) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return MAPPER.map(source, clz, mapId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类复制
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param object 目标对象
|
||||
* @return
|
||||
*/
|
||||
public static void convertor(Object source, Object object) {
|
||||
MAPPER.map(source, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类深度复制
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param object 目标对象
|
||||
* @param mapId 自定义转换
|
||||
* @return
|
||||
*/
|
||||
public static void convertor(Object source, Object object, String mapId) {
|
||||
MAPPER.map(source, object, mapId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类复制
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param object 目标对象
|
||||
* @return
|
||||
*/
|
||||
public static <T> void copyConvertor(T source, Object object) {
|
||||
MAPPER.map(source, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体类深度复制
|
||||
*
|
||||
* @param source 原数据
|
||||
* @param object 目标对象
|
||||
* @param mapId 自定义转换
|
||||
* @return
|
||||
*/
|
||||
public static <T> void copyConvertor(T source, Object object, String mapId) {
|
||||
MAPPER.map(source, object, mapId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import com.hula.ai.common.constant.StringPoolConstant;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* 错误信息处理类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/10/20
|
||||
* @version: 1.2.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
/**
|
||||
* 获取exception的详细错误信息。
|
||||
*/
|
||||
public static String getExceptionMessage(Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw, true));
|
||||
String str = sw.toString();
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String getRootErrorMessage(Exception e) {
|
||||
Throwable root = ExceptionUtils.getRootCause(e);
|
||||
root = (root == null ? e : root);
|
||||
if (root == null) {
|
||||
return StringPoolConstant.EMPTY;
|
||||
}
|
||||
String msg = root.getMessage();
|
||||
if (msg == null) {
|
||||
return StringPoolConstant.NULL;
|
||||
}
|
||||
return StringUtils.defaultString(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import com.hula.ai.common.constant.StringPoolConstant;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 填充null值数据
|
||||
*
|
||||
* @Author 葛盼
|
||||
* @date 2020/3/26 16:13
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class FillNullUtil {
|
||||
|
||||
/**
|
||||
* 要填充的实体类
|
||||
*
|
||||
* @param bean
|
||||
*/
|
||||
public static void fillNull(Object bean) {
|
||||
if (bean instanceof Map) {
|
||||
return;
|
||||
}
|
||||
if (bean instanceof List) {
|
||||
return;
|
||||
}
|
||||
List<Field> fieldList = new ArrayList<>();
|
||||
Class tempClass = bean.getClass();
|
||||
fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
|
||||
for (Field field : fieldList) {
|
||||
field.setAccessible(true);
|
||||
if ("java.lang.String".equals(field.getType().getName())) {
|
||||
setValue(StringPoolConstant.EMPTY, bean, field);
|
||||
} else if ("java.lang.Integer".equals(field.getType().getName())) {
|
||||
setValue(Integer.valueOf(0), bean, field);
|
||||
} else if ("java.lang.Double".equals(field.getType().getName())) {
|
||||
setValue(Double.valueOf(0), bean, field);
|
||||
} else if ("java.lang.Long".equals(field.getType().getName())) {
|
||||
setValue(Long.valueOf(0), bean, field);
|
||||
} else if ("java.lang.Boolean".equals(field.getType().getName())) {
|
||||
setValue(true, bean, field);
|
||||
} else if ("java.math.BigDecimal".equals(field.getType().getName())) {
|
||||
setValue(BigDecimal.ZERO, bean, field);
|
||||
} else if ("java.time.LocalDateTime".equals(field.getType().getName())) {
|
||||
setValue(LocalDateTime.now(), bean, field);
|
||||
} else if ("java.util.Date".equals(field.getType().getName())) {
|
||||
setValue(new Date(), bean, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValue(Object value, Object bean, Field field) {
|
||||
if ("id".equals(field.getName())) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object mid = field.get(bean);
|
||||
if (mid == null) {
|
||||
field.set(bean, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String nullToEmpty(Object obj) {
|
||||
if (obj == null) {
|
||||
return StringPoolConstant.EMPTY;
|
||||
}
|
||||
if (obj instanceof String) {
|
||||
return (String) obj;
|
||||
}
|
||||
return obj + StringPoolConstant.EMPTY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import com.hula.ai.common.enums.OperateSystemEnum;
|
||||
|
||||
/**
|
||||
* 获取操作系统工具类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/3/22 10:27
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class OperateSystemUtil {
|
||||
|
||||
private static String OS = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
private static OperateSystemUtil instance = new OperateSystemUtil();
|
||||
|
||||
private OperateSystemEnum platform;
|
||||
|
||||
private OperateSystemUtil() {
|
||||
}
|
||||
|
||||
public static boolean isLinux() {
|
||||
return OS.indexOf("linux") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isMacOS() {
|
||||
return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") < 0;
|
||||
}
|
||||
|
||||
public static boolean isMacOSX() {
|
||||
return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") > 0;
|
||||
}
|
||||
|
||||
public static boolean isWindows() {
|
||||
return OS.indexOf("windows") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isOS2() {
|
||||
return OS.indexOf("os/2") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isSolaris() {
|
||||
return OS.indexOf("solaris") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isSunOS() {
|
||||
return OS.indexOf("sunos") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isMPEiX() {
|
||||
return OS.indexOf("mpe/ix") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isHPUX() {
|
||||
return OS.indexOf("hp-ux") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isAix() {
|
||||
return OS.indexOf("aix") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isOS390() {
|
||||
return OS.indexOf("os/390") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isFreeBSD() {
|
||||
return OS.indexOf("freebsd") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isIrix() {
|
||||
return OS.indexOf("irix") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isDigitalUnix() {
|
||||
return OS.indexOf("digital") >= 0 && OS.indexOf("unix") > 0;
|
||||
}
|
||||
|
||||
public static boolean isNetWare() {
|
||||
return OS.indexOf("netware") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isOSF1() {
|
||||
return OS.indexOf("osf1") >= 0;
|
||||
}
|
||||
|
||||
public static boolean isOpenVMS() {
|
||||
return OS.indexOf("openvms") >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统名字
|
||||
*
|
||||
* @return 操作系统名
|
||||
*/
|
||||
public static OperateSystemEnum getOSname() {
|
||||
if (isAix()) {
|
||||
instance.platform = OperateSystemEnum.AIX;
|
||||
} else if (isDigitalUnix()) {
|
||||
instance.platform = OperateSystemEnum.Digital_Unix;
|
||||
} else if (isFreeBSD()) {
|
||||
instance.platform = OperateSystemEnum.FreeBSD;
|
||||
} else if (isHPUX()) {
|
||||
instance.platform = OperateSystemEnum.HP_UX;
|
||||
} else if (isIrix()) {
|
||||
instance.platform = OperateSystemEnum.Irix;
|
||||
} else if (isLinux()) {
|
||||
instance.platform = OperateSystemEnum.Linux;
|
||||
} else if (isMacOS()) {
|
||||
instance.platform = OperateSystemEnum.Mac_OS;
|
||||
} else if (isMacOSX()) {
|
||||
instance.platform = OperateSystemEnum.Mac_OS_X;
|
||||
} else if (isMPEiX()) {
|
||||
instance.platform = OperateSystemEnum.MPEiX;
|
||||
} else if (isNetWare()) {
|
||||
instance.platform = OperateSystemEnum.NetWare_411;
|
||||
} else if (isOpenVMS()) {
|
||||
instance.platform = OperateSystemEnum.OpenVMS;
|
||||
} else if (isOS2()) {
|
||||
instance.platform = OperateSystemEnum.OS2;
|
||||
} else if (isOS390()) {
|
||||
instance.platform = OperateSystemEnum.OS390;
|
||||
} else if (isOSF1()) {
|
||||
instance.platform = OperateSystemEnum.OSF1;
|
||||
} else if (isSolaris()) {
|
||||
instance.platform = OperateSystemEnum.Solaris;
|
||||
} else if (isSunOS()) {
|
||||
instance.platform = OperateSystemEnum.SunOS;
|
||||
} else if (isWindows()) {
|
||||
instance.platform = OperateSystemEnum.Windows;
|
||||
} else {
|
||||
instance.platform = OperateSystemEnum.Others;
|
||||
}
|
||||
return instance.platform;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,81 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.hula.ai.common.enums.IntEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
/**
|
||||
* 获取雪花算法Id
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/12/16
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Slf4j
|
||||
public class SnowFlakeUtil {
|
||||
|
||||
private static long workerId = 0;
|
||||
private static long dataCenterId = 1;
|
||||
private static int snowflakeLength = 19;
|
||||
private static Snowflake snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
|
||||
log.info("当前机器的workId: {}", workerId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("当前机器的workId获取失败", e);
|
||||
workerId = NetUtil.getLocalhostStr().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized long snowflakeId() {
|
||||
return snowflake.nextId();
|
||||
}
|
||||
|
||||
public static synchronized long snowflakeId(int length) {
|
||||
long snowflakeId = snowflakeId();
|
||||
if (length <= IntEnum.ZERO.getValue()) {
|
||||
return snowflakeId;
|
||||
}
|
||||
return Long.valueOf(String.valueOf(snowflakeId).substring(snowflakeLength - length));
|
||||
}
|
||||
|
||||
public static synchronized long snowflakeId(long workerId, long dataCenterId) {
|
||||
Snowflake snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
|
||||
return snowflake.nextId();
|
||||
}
|
||||
|
||||
public static synchronized long snowflakeId(long workerId, long dataCenterId, int length) {
|
||||
long snowflakeId = snowflakeId(workerId, dataCenterId);
|
||||
if (length <= IntEnum.ZERO.getValue()) {
|
||||
return snowflakeId;
|
||||
}
|
||||
return Long.valueOf(String.valueOf(snowflakeId).substring(snowflakeLength - length));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(5);
|
||||
Stream.iterate(0, x -> x + 1).limit(20).
|
||||
forEach(x -> {
|
||||
executorService.submit(() -> {
|
||||
long id = snowflakeId(13);
|
||||
System.out.println(id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import com.hula.ai.common.constant.HttpConstant;
|
||||
import com.hula.ai.common.constant.StringPoolConstant;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2020/12/30
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
public class StringUtil extends StringUtils {
|
||||
|
||||
/**
|
||||
* 是否为http(s)://开头
|
||||
*
|
||||
* @param link 链接
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean ishttp(String link) {
|
||||
return StringUtils.startsWithAny(link, HttpConstant.HTTP, HttpConstant.HTTPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线命名
|
||||
*/
|
||||
public static String toUnderScoreCase(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 前置字符是否大写
|
||||
boolean preCharIsUpperCase;
|
||||
// 当前字符是否大写
|
||||
boolean curreCharIsUpperCase;
|
||||
// 下一字符是否大写
|
||||
boolean nexteCharIsUpperCase = true;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (i > 0) {
|
||||
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
|
||||
} else {
|
||||
preCharIsUpperCase = false;
|
||||
}
|
||||
|
||||
curreCharIsUpperCase = Character.isUpperCase(c);
|
||||
|
||||
if (i < (str.length() - 1)) {
|
||||
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
|
||||
}
|
||||
|
||||
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
|
||||
sb.append(StringPoolConstant.UNDERSCORE);
|
||||
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
|
||||
sb.append(StringPoolConstant.UNDERSCORE);
|
||||
}
|
||||
sb.append(Character.toLowerCase(c));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
|
||||
*
|
||||
* @param name 转换前的下划线大写方式命名的字符串
|
||||
* @return 转换后的驼峰式命名的字符串
|
||||
*/
|
||||
public static String convertToCamelCase(String name) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
// 快速检查
|
||||
if (name == null || name.isEmpty()) {
|
||||
// 没必要转换
|
||||
return StringPoolConstant.EMPTY;
|
||||
} else if (!name.contains(StringPoolConstant.UNDERSCORE)) {
|
||||
// 不含下划线,仅将首字母大写
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
// 用下划线将原始字符串分割
|
||||
String[] camels = name.split(StringPoolConstant.UNDERSCORE);
|
||||
for (String camel : camels) {
|
||||
// 跳过原始字符串中开头、结尾的下换线或双重下划线
|
||||
if (camel.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// 首字母大写
|
||||
result.append(camel.substring(0, 1).toUpperCase());
|
||||
result.append(camel.substring(1).toLowerCase());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰式命名法 例如:user_name->userName
|
||||
*/
|
||||
public static String toCamelCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
s = s.toLowerCase();
|
||||
StringBuilder sb = new StringBuilder(s.length());
|
||||
boolean upperCase = false;
|
||||
char under = '_';
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (c == under) {
|
||||
upperCase = true;
|
||||
} else if (upperCase) {
|
||||
sb.append(Character.toUpperCase(c));
|
||||
upperCase = false;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.hula.ai.common.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 线程相关工具类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2019/11/9
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Slf4j
|
||||
public class Threadsutil {
|
||||
|
||||
/**
|
||||
* sleep等待,单位为毫秒
|
||||
*/
|
||||
public static void sleep(long milliseconds) {
|
||||
try {
|
||||
Thread.sleep(milliseconds);
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止线程池
|
||||
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
|
||||
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
|
||||
* 如果仍人超時,則強制退出.
|
||||
* 另对在shutdown时线程本身被调用中断做了处理.
|
||||
*/
|
||||
public static void shutdownAndAwaitTermination(ExecutorService pool) {
|
||||
if (pool != null && !pool.isShutdown()) {
|
||||
pool.shutdown();
|
||||
try {
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
pool.shutdownNow();
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
log.info("Pool did not terminate");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
pool.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印线程异常信息
|
||||
*/
|
||||
public static void printException(Runnable r, Throwable t) {
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
log.error(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.hula.ai.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.hula.ai.core.AiModelFactory;
|
||||
import com.hula.ai.core.AiModelFactoryImpl;
|
||||
import com.hula.ai.core.model.*;
|
||||
import com.hula.ai.core.model.silicon.SiliconFlowApiConstants;
|
||||
import com.hula.ai.core.model.silicon.SiliconFlowChatModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusServiceClientProperties;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreProperties;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreProperties;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
|
||||
import org.springframework.ai.embedding.BatchingStrategy;
|
||||
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
|
||||
import org.springframework.ai.model.tool.ToolCallingManager;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
|
||||
import org.springframework.ai.tokenizer.TokenCountEstimator;
|
||||
import org.springframework.ai.vectorstore.VectorStore;
|
||||
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({HulaAiProperties.class,
|
||||
QdrantVectorStoreProperties.class, // 解析 Qdrant 配置
|
||||
RedisVectorStoreProperties.class, // 解析 Redis 配置
|
||||
MilvusVectorStoreProperties.class,
|
||||
MilvusServiceClientProperties.class // 解析 Milvus 配置
|
||||
})
|
||||
@Slf4j
|
||||
public class AiAutoConfiguration {
|
||||
@Bean
|
||||
public AiModelFactory aiModelFactory() {
|
||||
return new AiModelFactoryImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.deepseek.enable", havingValue = "true")
|
||||
public DeepSeekChatModel deepSeekChatModel(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.DeepSeekProperties properties = hulaAiProperties.getDeepseek();
|
||||
return buildDeepSeekChatModel(properties);
|
||||
}
|
||||
|
||||
public DeepSeekChatModel buildDeepSeekChatModel(HulaAiProperties.DeepSeekProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(DeepSeekChatModel.MODEL_DEFAULT);
|
||||
}
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(DeepSeekChatModel.BASE_URL)
|
||||
.apiKey(properties.getApiKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new DeepSeekChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.doubao.enable", havingValue = "true")
|
||||
public DouBaoChatModel douBaoChatClient(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.DouBaoProperties properties = hulaAiProperties.getDoubao();
|
||||
return buildDouBaoChatClient(properties);
|
||||
}
|
||||
|
||||
public DouBaoChatModel buildDouBaoChatClient(HulaAiProperties.DouBaoProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(DouBaoChatModel.MODEL_DEFAULT);
|
||||
}
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(DouBaoChatModel.BASE_URL)
|
||||
.apiKey(properties.getApiKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new DouBaoChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.siliconflow.enable", havingValue = "true")
|
||||
public SiliconFlowChatModel siliconFlowChatClient(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.SiliconFlowProperties properties = hulaAiProperties.getSiliconflow();
|
||||
return buildSiliconFlowChatClient(properties);
|
||||
}
|
||||
|
||||
public SiliconFlowChatModel buildSiliconFlowChatClient(HulaAiProperties.SiliconFlowProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(SiliconFlowApiConstants.MODEL_DEFAULT);
|
||||
}
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
|
||||
.apiKey(properties.getApiKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new SiliconFlowChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.hunyuan.enable", havingValue = "true")
|
||||
public HunYuanChatModel hunYuanChatClient(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.HunYuanProperties properties = hulaAiProperties.getHunyuan();
|
||||
return buildHunYuanChatClient(properties);
|
||||
}
|
||||
|
||||
public HunYuanChatModel buildHunYuanChatClient(HulaAiProperties.HunYuanProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(HunYuanChatModel.MODEL_DEFAULT);
|
||||
}
|
||||
// 特殊:由于混元大模型不提供 deepseek,而是通过知识引擎,所以需要区分下 URL
|
||||
if (StrUtil.isEmpty(properties.getBaseUrl())) {
|
||||
properties.setBaseUrl(
|
||||
StrUtil.startWithIgnoreCase(properties.getModel(), "deepseek") ? HunYuanChatModel.DEEP_SEEK_BASE_URL
|
||||
: HunYuanChatModel.BASE_URL);
|
||||
}
|
||||
// 创建 OpenAiChatModel、HunYuanChatModel 对象
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(properties.getBaseUrl())
|
||||
.apiKey(properties.getApiKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new HunYuanChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.xinghuo.enable", havingValue = "true")
|
||||
public XingHuoChatModel xingHuoChatClient(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.XingHuoProperties properties = hulaAiProperties.getXinghuo();
|
||||
return buildXingHuoChatClient(properties);
|
||||
}
|
||||
|
||||
public XingHuoChatModel buildXingHuoChatClient(HulaAiProperties.XingHuoProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(XingHuoChatModel.MODEL_DEFAULT);
|
||||
}
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(XingHuoChatModel.BASE_URL)
|
||||
.apiKey(properties.getAppKey() + ":" + properties.getSecretKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new XingHuoChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.baichuan.enable", havingValue = "true")
|
||||
public BaiChuanChatModel baiChuanChatClient(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.BaiChuanProperties properties = hulaAiProperties.getBaichuan();
|
||||
return buildBaiChuanChatClient(properties);
|
||||
}
|
||||
|
||||
public BaiChuanChatModel buildBaiChuanChatClient(HulaAiProperties.BaiChuanProperties properties) {
|
||||
if (StrUtil.isEmpty(properties.getModel())) {
|
||||
properties.setModel(BaiChuanChatModel.MODEL_DEFAULT);
|
||||
}
|
||||
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
|
||||
.openAiApi(OpenAiApi.builder()
|
||||
.baseUrl(BaiChuanChatModel.BASE_URL)
|
||||
.apiKey(properties.getApiKey())
|
||||
.build())
|
||||
.defaultOptions(OpenAiChatOptions.builder()
|
||||
.model(properties.getModel())
|
||||
.temperature(properties.getTemperature())
|
||||
.maxTokens(properties.getMaxTokens())
|
||||
.topP(properties.getTopP())
|
||||
.build())
|
||||
.toolCallingManager(getToolCallingManager())
|
||||
.build();
|
||||
return new BaiChuanChatModel(openAiChatModel);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.midjourney.enable", havingValue = "true")
|
||||
public MidjourneyApi midjourneyApi(HulaAiProperties hulaAiProperties) {
|
||||
HulaAiProperties.MidjourneyProperties config = hulaAiProperties.getMidjourney();
|
||||
return new MidjourneyApi(config.getBaseUrl(), config.getApiKey(), config.getNotifyUrl());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "hula.ai.suno.enable", havingValue = "true")
|
||||
public SunoApi sunoApi(HulaAiProperties hulaAiProperties) {
|
||||
return new SunoApi(hulaAiProperties.getSuno().getBaseUrl());
|
||||
}
|
||||
|
||||
// ========== RAG 相关 ==========
|
||||
|
||||
@Bean
|
||||
public TokenCountEstimator tokenCountEstimator() {
|
||||
return new JTokkitTokenCountEstimator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BatchingStrategy batchingStrategy() {
|
||||
return new TokenCountBatchingStrategy();
|
||||
}
|
||||
|
||||
private static ToolCallingManager getToolCallingManager() {
|
||||
return SpringUtil.getBean(ToolCallingManager.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.hula.ai.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@ConfigurationProperties(prefix = "hula.ai")
|
||||
@Configuration
|
||||
@Data
|
||||
public class HulaAiProperties {
|
||||
/**
|
||||
* DeepSeek
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private DeepSeekProperties deepseek;
|
||||
|
||||
/**
|
||||
* 字节豆包
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private DouBaoProperties doubao;
|
||||
|
||||
/**
|
||||
* 腾讯混元
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private HunYuanProperties hunyuan;
|
||||
|
||||
/**
|
||||
* 硅基流动
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private SiliconFlowProperties siliconflow;
|
||||
|
||||
/**
|
||||
* 讯飞星火
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private XingHuoProperties xinghuo;
|
||||
|
||||
/**
|
||||
* 百川
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private BaiChuanProperties baichuan;
|
||||
|
||||
/**
|
||||
* Midjourney 绘图
|
||||
*/
|
||||
private MidjourneyProperties midjourney;
|
||||
|
||||
/**
|
||||
* Suno 音乐
|
||||
*/
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private SunoProperties suno;
|
||||
|
||||
@Data
|
||||
public static class DeepSeekProperties {
|
||||
|
||||
private String enable;
|
||||
private String apiKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DouBaoProperties {
|
||||
|
||||
private String enable;
|
||||
private String apiKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HunYuanProperties {
|
||||
|
||||
private String enable;
|
||||
private String baseUrl;
|
||||
private String apiKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SiliconFlowProperties {
|
||||
|
||||
private String enable;
|
||||
private String apiKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class XingHuoProperties {
|
||||
|
||||
private String enable;
|
||||
private String appId;
|
||||
private String appKey;
|
||||
private String secretKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class BaiChuanProperties {
|
||||
|
||||
private String enable;
|
||||
private String apiKey;
|
||||
|
||||
private String model;
|
||||
private Double temperature;
|
||||
private Integer maxTokens;
|
||||
private Double topP;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MidjourneyProperties {
|
||||
|
||||
private String enable;
|
||||
private String baseUrl;
|
||||
|
||||
private String apiKey;
|
||||
private String notifyUrl;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SunoProperties {
|
||||
|
||||
private boolean enable = false;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
package com.hula.ai.config;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.hula.ai.client.enums.ChatModelEnum;
|
||||
import com.hula.ai.common.constant.AiConstants;
|
||||
import com.hula.ai.common.constant.StringPoolConstant;
|
||||
import com.hula.ai.common.enums.IntegerEnum;
|
||||
import com.hula.ai.config.dto.BaseInfoDTO;
|
||||
import com.hula.ai.gpt.pojo.vo.OpenkeyVO;
|
||||
import com.hula.ai.gpt.service.IOpenkeyService;
|
||||
import com.hula.ai.llm.chatglm.ChatGLMClient;
|
||||
import com.hula.ai.llm.deepseek.DeepSeekStreamClient;
|
||||
import com.hula.ai.llm.deepseek.constant.DeepSeekConst;
|
||||
import com.hula.ai.llm.doubao.DouBaoClient;
|
||||
import com.hula.ai.llm.internlm.InternlmClient;
|
||||
import com.hula.ai.llm.locallm.LocalLMClient;
|
||||
import com.hula.ai.llm.moonshot.MoonshotClient;
|
||||
import com.hula.ai.llm.openai.OpenAiClient;
|
||||
import com.hula.ai.llm.openai.OpenAiStreamClient;
|
||||
import com.hula.ai.llm.openai.function.KeyRandomStrategy;
|
||||
import com.hula.ai.llm.openai.interceptor.OpenAILogger;
|
||||
import com.hula.ai.llm.spark.SparkClient;
|
||||
import com.hula.ai.llm.tongyi.TongYiClient;
|
||||
import com.hula.ai.llm.wenxin.WenXinClient;
|
||||
import com.hula.core.user.service.ConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 初始化大模型bean
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class InitBean {
|
||||
@Autowired
|
||||
private IOpenkeyService openkeyService;
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Bean
|
||||
public OpenAiStreamClient openAiStreamClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.OPENAI.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到ChatGpt模型token数据");
|
||||
return new OpenAiStreamClient();
|
||||
}
|
||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
OkHttpClient okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// 如使用代理 请更换为代理地址
|
||||
//.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)))
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
BaseInfoDTO baseInfo = configService.getBeanByName(AiConstants.BASE_INFO, BaseInfoDTO.class);
|
||||
String apiHost = null;
|
||||
if (baseInfo.getProxyType().equals(IntegerEnum.THREE.getValue()) && StrUtil.isEmpty((baseInfo.getProxyAddress()))) {
|
||||
if (!baseInfo.getProxyAddress().contains(StringPoolConstant.COLON)) {
|
||||
log.error("代理地址错误");
|
||||
return new OpenAiStreamClient();
|
||||
}
|
||||
String[] proxyAddress = baseInfo.getProxyAddress().split(StringPoolConstant.COLON);
|
||||
okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// 如使用代理 请更换为代理地址
|
||||
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress[0], Integer.valueOf(proxyAddress[1]))))
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
} else if (baseInfo.getProxyType().equals(IntegerEnum.TWO.getValue()) && StrUtil.isEmpty((baseInfo.getProxyServer()))) {
|
||||
apiHost = baseInfo.getProxyServer();
|
||||
}
|
||||
return OpenAiStreamClient
|
||||
.builder()
|
||||
.apiHost(apiHost)
|
||||
.apiKey(openkeys.stream().map(v -> v.getAppKey()).collect(Collectors.toList()))
|
||||
//自定义key使用策略 默认随机策略
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAiClient openAiClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.MOONSHOT.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到ChatGpt模型token数据");
|
||||
return new OpenAiClient();
|
||||
}
|
||||
//本地开发需要配置代理地址
|
||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
// 如使用代理 请更换为代理地址
|
||||
//.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)))
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
BaseInfoDTO baseInfo = configService.getBeanByName(AiConstants.BASE_INFO, BaseInfoDTO.class);
|
||||
String apiHost = null;
|
||||
if (baseInfo.getProxyType().equals(IntegerEnum.THREE.getValue()) && StrUtil.isEmpty((baseInfo.getProxyAddress()))) {
|
||||
if (!baseInfo.getProxyAddress().contains(StringPoolConstant.COLON)) {
|
||||
log.error("代理地址错误");
|
||||
return new OpenAiClient();
|
||||
}
|
||||
String[] proxyAddress = baseInfo.getProxyAddress().split(StringPoolConstant.COLON);
|
||||
okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// 如使用代理 请更换为代理地址
|
||||
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress[0], Integer.valueOf(proxyAddress[1]))))
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
} else if (baseInfo.getProxyType().equals(IntegerEnum.TWO.getValue()) && StrUtil.isNotEmpty(baseInfo.getProxyServer())) {
|
||||
apiHost = baseInfo.getProxyServer();
|
||||
}
|
||||
return OpenAiClient
|
||||
.builder()
|
||||
.apiHost(apiHost)
|
||||
.apiKey(openkeys.stream().map(v -> v.getAppKey()).collect(Collectors.toList()))
|
||||
//自定义key使用策略 默认随机策略
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 文心一言
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public WenXinClient wenXinClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.WENXIN.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到文心一言模型token数据");
|
||||
return new WenXinClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
if (StrUtil.isEmpty(openkey.getAppKey()) || StrUtil.isEmpty(openkey.getAppSecret())) {
|
||||
log.error("未获取到文心一言模型token数据");
|
||||
return new WenXinClient();
|
||||
}
|
||||
return WenXinClient.builder().logLevel(HttpLoggingInterceptor.Level.BASIC)
|
||||
.apiKey(openkey.getAppKey()).secretKey(openkey.getAppSecret()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通义千问
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public TongYiClient tongYiClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.TONGYI.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到通义千问模型token数据");
|
||||
return new TongYiClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
return new TongYiClient(openkey.getAppKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* 讯飞星火
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public SparkClient sparkClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.SPARK.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到智谱清言模型token数据,请添加后需要重启系统");
|
||||
return new SparkClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
return new SparkClient(openkey.getAppId(), openkey.getAppKey(), openkey.getAppSecret());
|
||||
}
|
||||
|
||||
/**
|
||||
* 智谱清言
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ChatGLMClient chatGLMClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.CHATGLM.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到智谱清言模型token数据,请添加后需要重启系统");
|
||||
return new ChatGLMClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
if (StrUtil.isEmpty(openkey.getAppKey())) {
|
||||
log.error("未获取到智谱清言模型token数据");
|
||||
return new ChatGLMClient();
|
||||
}
|
||||
return ChatGLMClient.builder().appKey(openkey.getAppKey()).appSecret(openkey.getAppSecret()).apiSecretKey(openkey.getAppKey()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 月之暗面
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MoonshotClient moonshotClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.MOONSHOT.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到月之暗面模型token数据,请添加后需要重启系统");
|
||||
return new MoonshotClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
if (StrUtil.isEmpty((openkey.getAppKey()))) {
|
||||
log.error("未获取到月之暗面模型token数据");
|
||||
return new MoonshotClient();
|
||||
}
|
||||
return MoonshotClient.builder().apiKey(openkey.getAppKey()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* DeepSeek
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public DeepSeekStreamClient deepSeekStreamClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.DEEPSEEK.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到DeepSeek模型token数据");
|
||||
return new DeepSeekStreamClient();
|
||||
}
|
||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
OkHttpClient okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// 如使用代理 请更换为代理地址
|
||||
//.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)))
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
return DeepSeekStreamClient
|
||||
.builder()
|
||||
.apiHost(DeepSeekConst.HOST)
|
||||
.apiKey(openkeys.stream().map(v -> v.getAppKey()).collect(Collectors.toList()))
|
||||
//自定义key使用策略 默认随机策略
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 豆包
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public DouBaoClient douBaoClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.DOUBAO.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到豆包模型token数据,请添加后需要重启系统");
|
||||
return new DouBaoClient();
|
||||
}
|
||||
if (CollUtil.isNotEmpty(openkeys)) {
|
||||
return DouBaoClient.builder().apiKey(openkeys.get(0).getAppKey()).build();
|
||||
}
|
||||
return DouBaoClient.builder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 书生·浦语
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public InternlmClient internlmClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.INTERNLM.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
log.error("未加载到书生浦语模型token数据,请添加后需要重启系统");
|
||||
return new InternlmClient();
|
||||
}
|
||||
OpenkeyVO openkey = openkeys.get(0);
|
||||
if (StrUtil.isEmpty((openkey.getAppKey()))) {
|
||||
log.error("未获取到书生浦语模型token数据");
|
||||
return new InternlmClient();
|
||||
}
|
||||
return InternlmClient.builder().token(openkey.getAppKey()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalLM 本地模型
|
||||
* 支持Langchain-Chatchat、Ollama、GiteeAI、扣子、FastGPT、LinkAI、Dify
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public LocalLMClient localLMClient() {
|
||||
List<OpenkeyVO> openkeys = openkeyService.listOpenkeyByModel(ChatModelEnum.LOCALLM.getValue());
|
||||
if (CollUtil.isEmpty(openkeys)) {
|
||||
return LocalLMClient.builder().apiKey(openkeys.get(0).getAppKey()).build();
|
||||
}
|
||||
return LocalLMClient.builder().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.hula.ai.config;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigurationProperties(prefix = "hula.security")
|
||||
@Configuration
|
||||
@Validated
|
||||
@Data
|
||||
public class SecurityProperties {
|
||||
|
||||
/**
|
||||
* HTTP 请求时,访问令牌的请求 Header
|
||||
*/
|
||||
@NotEmpty(message = "Token Header 不能为空")
|
||||
private String tokenHeader = "Authorization";
|
||||
/**
|
||||
* HTTP 请求时,访问令牌的请求参数
|
||||
*
|
||||
* 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接
|
||||
*/
|
||||
@NotEmpty(message = "Token Parameter 不能为空")
|
||||
private String tokenParameter = "token";
|
||||
|
||||
/**
|
||||
* mock 模式的开关
|
||||
*/
|
||||
@NotNull(message = "mock 模式的开关不能为空")
|
||||
private Boolean mockEnable = false;
|
||||
/**
|
||||
* mock 模式的密钥
|
||||
* 一定要配置密钥,保证安全性
|
||||
*/
|
||||
@NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。
|
||||
private String mockSecret = "test";
|
||||
|
||||
/**
|
||||
* 免登录的 URL 列表
|
||||
*/
|
||||
private List<String> permitAllUrls = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* PasswordEncoder 加密复杂度,越高开销越大
|
||||
*/
|
||||
private Integer passwordEncoderLength = 4;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.hula.ai.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* APP信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class AppInfoDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 是否无限制访问GPT
|
||||
*/
|
||||
private Integer isGPTLimit;
|
||||
|
||||
/**
|
||||
* 是否开启兑换码
|
||||
*/
|
||||
private Integer isRedemption;
|
||||
|
||||
/**
|
||||
* 是否开启短信
|
||||
*/
|
||||
private Integer isSms;
|
||||
|
||||
/**
|
||||
* 是否开启分享
|
||||
*/
|
||||
private Integer isShare;
|
||||
|
||||
/**
|
||||
* 分享赠送次数
|
||||
*/
|
||||
private Integer shareNum;
|
||||
|
||||
/**
|
||||
* 免费体验次数
|
||||
*/
|
||||
private Integer freeNum;
|
||||
|
||||
/**
|
||||
* H5地址
|
||||
*/
|
||||
private String h5Url;
|
||||
|
||||
/**
|
||||
* 首页公告
|
||||
*/
|
||||
private String homeNotice;
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.hula.ai.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 基础信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/5/6
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class BaseInfoDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* 内容安全审查接口 0 不检查 1 检查
|
||||
*/
|
||||
private Integer contentSecurity;
|
||||
|
||||
/**
|
||||
* 站点名称
|
||||
*/
|
||||
private String siteTitle;
|
||||
|
||||
/**
|
||||
* 站点logo
|
||||
*/
|
||||
private String siteLogo;
|
||||
|
||||
/**
|
||||
* 代理方案 1 无需代理 2 反向代理 3 本地代理
|
||||
*/
|
||||
private Integer proxyType;
|
||||
|
||||
/**
|
||||
* 反代地址
|
||||
*/
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* 本地代理地址
|
||||
*/
|
||||
private String proxyAddress;
|
||||
|
||||
/**
|
||||
* 域名
|
||||
*/
|
||||
private String domain;
|
||||
|
||||
/**
|
||||
* 站点版权
|
||||
*/
|
||||
private String copyright;
|
||||
|
||||
/**
|
||||
* 站点描述
|
||||
*/
|
||||
private String descrip;
|
||||
|
||||
/**
|
||||
* 关键词
|
||||
*/
|
||||
private List<String> keywords;
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.hula.ai.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 基础信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/5/6
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class ExtraInfoDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* oss类型
|
||||
*/
|
||||
private Integer ossType;
|
||||
|
||||
/**
|
||||
* 上传大小限制
|
||||
*/
|
||||
private String uploadSize;
|
||||
|
||||
/**
|
||||
* oss区域
|
||||
*/
|
||||
private String endpoint;
|
||||
|
||||
/**
|
||||
* oss仓库
|
||||
*/
|
||||
private String bucketName;
|
||||
|
||||
/**
|
||||
* osskey
|
||||
*/
|
||||
private String ossKeyId;
|
||||
|
||||
/**
|
||||
* oss密钥
|
||||
*/
|
||||
private String ossKeySecret;
|
||||
|
||||
/**
|
||||
* 短信类型
|
||||
*/
|
||||
private Integer smsType;
|
||||
|
||||
/**
|
||||
* 短信区域id
|
||||
*/
|
||||
private String smsRegionId;
|
||||
|
||||
/**
|
||||
* 短信应用id (阿里云sms没有)
|
||||
*/
|
||||
private String smsAppId;
|
||||
|
||||
/**
|
||||
* 短信key
|
||||
*/
|
||||
private String smsKeyId;
|
||||
|
||||
/**
|
||||
* 短信密钥
|
||||
*/
|
||||
private String smsKeySecret;
|
||||
|
||||
/**
|
||||
* 短信签名
|
||||
*/
|
||||
private String smsSign;
|
||||
|
||||
/**
|
||||
* 注册模版
|
||||
*/
|
||||
private String registerTemplate;
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.hula.ai.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 微信信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/5/6
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@Data
|
||||
public class WxInfoDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 是否使用小程序
|
||||
*/
|
||||
private Integer isWxapp;
|
||||
|
||||
/**
|
||||
* 小程序id
|
||||
*/
|
||||
private String wxAppId;
|
||||
|
||||
/**
|
||||
* 小程序密钥
|
||||
*/
|
||||
private String wxAppSecret;
|
||||
|
||||
/**
|
||||
* 是否使用公众号
|
||||
*/
|
||||
private Integer isMp;
|
||||
|
||||
/**
|
||||
* 公众号id
|
||||
*/
|
||||
private String mpAppId;
|
||||
|
||||
/**
|
||||
* 公众号密钥
|
||||
*/
|
||||
private String mpSecret;
|
||||
|
||||
/**
|
||||
* 是否开启微信支付
|
||||
*/
|
||||
private Integer isWxPay;
|
||||
|
||||
/**
|
||||
* 是否开启服务商支付
|
||||
*/
|
||||
private Integer isWxSpPay;
|
||||
|
||||
/**
|
||||
* 服务商AppId
|
||||
*/
|
||||
private String spAppId;
|
||||
|
||||
/**
|
||||
* 服务商商户号
|
||||
*/
|
||||
private String spMchId;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* V3密钥
|
||||
*/
|
||||
private String apiV3Key;
|
||||
|
||||
/**
|
||||
* 应用私钥
|
||||
*/
|
||||
private String privateKey;
|
||||
|
||||
/**
|
||||
* 证书序列号
|
||||
*/
|
||||
private String mchSerialNo;
|
||||
|
||||
/**
|
||||
* 支付证书信息
|
||||
*/
|
||||
private String certPath;
|
||||
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package com.hula.ai.controller.app;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.hula.ai.client.model.command.ChatCommand;
|
||||
import com.hula.ai.common.enums.StatusEnum;
|
||||
import com.hula.ai.gpt.pojo.param.AgreementParam;
|
||||
import com.hula.ai.gpt.pojo.vo.AgreementVO;
|
||||
import com.hula.ai.gpt.service.IAgreementService;
|
||||
import com.hula.ai.gpt.service.IAssistantService;
|
||||
import com.hula.ai.gpt.service.IAssistantTypeService;
|
||||
import com.hula.ai.llm.base.service.LLMService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 获取小程序基础信息接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/5/4
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/app/api")
|
||||
public class AppApiController {
|
||||
@Autowired
|
||||
private IAssistantTypeService assistantTypeService;
|
||||
@Autowired
|
||||
private IAssistantService assistantService;
|
||||
@Autowired
|
||||
private IAgreementService contentService;
|
||||
@Autowired
|
||||
private LLMService llmService;
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/content/agreement/{type}")
|
||||
public ApiResult getAgreement(@PathVariable("type") Integer type) {
|
||||
List<AgreementVO> contents = contentService.listContent(new AgreementParam(StatusEnum.ENABLED.getValue(), type));
|
||||
if (CollUtil.isEmpty(contents)) {
|
||||
return ApiResult.success();
|
||||
}
|
||||
return ApiResult.success(contents.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统内容信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/content/{type}")
|
||||
public ApiResult listContent(@PathVariable("type") Integer type) {
|
||||
return ApiResult.success(contentService.listContent(new AgreementParam(StatusEnum.ENABLED.getValue(), type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容详情
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/content/detail/{id}")
|
||||
public ApiResult getContent(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(contentService.getContentById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Ai分类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/assistant/type")
|
||||
public ApiResult listAssistantType() {
|
||||
AgreementParam param = new AgreementParam();
|
||||
param.setStatus(StatusEnum.ENABLED.getValue());
|
||||
return ApiResult.success(assistantTypeService.listAssistantType(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Ai助手
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/assistant")
|
||||
public ApiResult listAssistantByType(@RequestParam AgreementParam param) {
|
||||
param.setStatus(StatusEnum.ENABLED.getValue());
|
||||
return ApiResult.success(assistantService.listAssistantByApp(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Ai助手
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023/1/9
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/assistant/{id}")
|
||||
public ApiResult getAssistantById(@PathVariable Long id) {
|
||||
return assistantService.getAssistantById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机获取Ai助手
|
||||
*
|
||||
* @author: 乾乾
|
||||
* @date: 2025/03/07
|
||||
*/
|
||||
@GetMapping("/assistant/random")
|
||||
public ApiResult listAssistant(AgreementParam param) {
|
||||
param.setStatus(StatusEnum.ENABLED.getValue());
|
||||
if(ObjectUtil.isNull(param.getSize()) || param.getSize() == 0){
|
||||
param.setSize(3);
|
||||
}
|
||||
param.setCurrent(new Random().nextInt(3));
|
||||
return ApiResult.success(assistantService.listAssistantByApp(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提问
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
*/
|
||||
@PostMapping("/chat")
|
||||
public ApiResult sendMessage(@RequestBody ChatCommand command) {
|
||||
command.setApi(true);
|
||||
return ApiResult.success(llmService.chat(command));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
package com.hula.ai.controller.app;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.hula.ai.client.enums.ChatStatusEnum;
|
||||
import com.hula.ai.client.model.command.ChatCommand;
|
||||
import com.hula.ai.client.model.command.CompletionsParam;
|
||||
import com.hula.ai.client.service.GptService;
|
||||
import com.hula.ai.framework.validator.base.BaseAssert;
|
||||
import com.hula.ai.gpt.pojo.entity.ChatMessage;
|
||||
import com.hula.ai.gpt.pojo.param.ChatParam;
|
||||
import com.hula.ai.gpt.pojo.vo.ChatMessageVO;
|
||||
import com.hula.ai.gpt.pojo.vo.ChatVO;
|
||||
import com.hula.ai.gpt.service.IChatMessageService;
|
||||
import com.hula.ai.gpt.service.IChatService;
|
||||
import com.hula.ai.llm.base.service.LLMService;
|
||||
import com.hula.common.domain.vo.res.CursorPageBaseResp;
|
||||
import com.hula.core.chat.domain.vo.request.ChatMessagePageReq;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import com.hula.utils.RequestHolder;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 对话接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@RestController(value = "ChatAiController")
|
||||
@RequestMapping("/chat")
|
||||
public class ChatController {
|
||||
@Autowired
|
||||
private IChatService chatService;
|
||||
@Autowired
|
||||
private IChatMessageService chatMessageService;
|
||||
@Autowired
|
||||
private GptService gptService;
|
||||
@Autowired
|
||||
private LLMService llmService;
|
||||
|
||||
/**
|
||||
* 获取聊天列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("list")
|
||||
public ApiResult listChat(@RequestBody ChatParam param) {
|
||||
param.setUid(RequestHolder.get().getUid());
|
||||
return ApiResult.success(chatService.listChat(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除聊天列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/del/{chatNumber}")
|
||||
public ApiResult<Integer> deleteChat(@PathVariable("chatNumber") String chatNumber) {
|
||||
return ApiResult.success(chatService.removeChatByChatNumber(chatNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天内容列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/message")
|
||||
public ApiResult<List<ChatMessageVO>> listChatMessage(ChatParam param) {
|
||||
BaseAssert.isBlankOrNull(param.getChatNumber(), "缺少会话标识");
|
||||
param.setStatus(ChatStatusEnum.SUCCESS.getValue());
|
||||
return ApiResult.success(chatMessageService.listChatMessage(param));
|
||||
}
|
||||
|
||||
@GetMapping("/ai/message")
|
||||
public ApiResult<CursorPageBaseResp<ChatMessage>> getChatMessagePage(@Valid ChatMessagePageReq request) {
|
||||
return ApiResult.success(chatMessageService.getChatMessagePage(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天内容
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/message/{conversationId}")
|
||||
public ApiResult listChatMessageById(@PathVariable String conversationId) {
|
||||
return ApiResult.returnResult("获取", ObjectUtil.isNotNull(chatMessageService.getChatByMessageId(conversationId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除聊天内容
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/message/{conversationId}")
|
||||
public ApiResult removeChatMessageById(@PathVariable String conversationId) {
|
||||
return ApiResult.returnResult("删除", chatMessageService.removeChatMessageByMessageId(conversationId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建对话
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult<ChatVO> saveChat(@RequestBody ChatCommand command) {
|
||||
command.setUid(RequestHolder.get().getUid());
|
||||
return ApiResult.success(chatService.saveSSEChat(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/message")
|
||||
public ApiResult sendMessage(@Validated @RequestBody ChatCommand command) {
|
||||
command.setUid(RequestHolder.get().getUid());
|
||||
command.setOperater(command.getUid());
|
||||
command = gptService.validateGptCommand(command);
|
||||
return ApiResult.success(gptService.chatMessage(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建sse连接
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/sse/create")
|
||||
public SseEmitter createConnect() {
|
||||
return llmService.createSse(RequestHolder.get().getUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
*/
|
||||
@GetMapping("/sse/close")
|
||||
public void closeConnect() {
|
||||
llmService.closeSse(RequestHolder.get().getUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话响应
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping(value = "/completions", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public void completions(HttpServletResponse response, @RequestBody CompletionsParam completionsParam) {
|
||||
Boolean isWs = false;
|
||||
if (StrUtil.isNotEmpty(completionsParam.getWs())) {
|
||||
isWs = Boolean.valueOf(completionsParam.getWs());
|
||||
}
|
||||
llmService.sseChat(response, isWs, RequestHolder.get().getUid(), completionsParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步响应
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/16
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/completions/sync")
|
||||
public ApiResult syncCompletions(@RequestBody ChatCommand command) {
|
||||
command.setUid(RequestHolder.get().getUid());
|
||||
return ApiResult.success(llmService.chat(command));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.hula.ai.controller.app;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.hula.ai.client.model.command.DeleteFileParam;
|
||||
import com.hula.ai.client.model.command.FileParam;
|
||||
import com.hula.ai.client.model.command.UploadParam;
|
||||
import com.hula.ai.framework.util.file.FileUploadResponse;
|
||||
import com.hula.ai.llm.base.service.LLMService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件管理
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/13
|
||||
* @version: 1.0.0
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
public class FileController {
|
||||
@Autowired
|
||||
private LLMService llmService;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @author: 乾乾
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public ApiResult<FileUploadResponse> uploadFile(@Validated @ModelAttribute UploadParam param, @RequestParam("file") MultipartFile file) {
|
||||
return ApiResult.success(llmService.uploadFile(file, param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件列表
|
||||
*
|
||||
* @author: 乾乾
|
||||
*/
|
||||
@GetMapping("/fileList")
|
||||
public ApiResult<JSONArray> fileList(@Validated FileParam param) {
|
||||
return ApiResult.success(llmService.fileList(param.getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @author: 乾乾
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
public ApiResult<Boolean> fileList(@Validated @RequestBody DeleteFileParam param) {
|
||||
return ApiResult.success(llmService.deleteFile(param));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.hula.ai.controller.app;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.hula.ai.common.utils.DateUtil;
|
||||
import com.hula.ai.gpt.pojo.param.StatisticsParam;
|
||||
import com.hula.ai.gpt.service.IStatisticsService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 统计接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/statistics")
|
||||
public class StatisticsController {
|
||||
@Autowired
|
||||
private IStatisticsService statisticsService;
|
||||
|
||||
/**
|
||||
* 获取总数据
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
*/
|
||||
@GetMapping("/index/total")
|
||||
public ApiResult getTotalData() {
|
||||
return ApiResult.success(statisticsService.getTotalData());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取折线图数据
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
*/
|
||||
@GetMapping("/index/line")
|
||||
public ApiResult getLineData(@RequestParam StatisticsParam param) {
|
||||
if (ObjectUtil.isNull(param.getStartDate()) && ObjectUtil.isNull(param.getEndDate())) {
|
||||
LocalDate endDate = LocalDate.now();
|
||||
LocalDate startDate = LocalDate.now().plusWeeks(-1);
|
||||
param.setStartDate(DateUtil.formatLocalDate(startDate));
|
||||
param.setEndDate(DateUtil.formatLocalDate(endDate));
|
||||
}
|
||||
return ApiResult.success(statisticsService.getLineData(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取雷达图数据
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
*/
|
||||
@GetMapping("/index/raddar")
|
||||
public ApiResult getRaddarData(@RequestParam StatisticsParam param) {
|
||||
LocalDate endDate = LocalDate.now();
|
||||
LocalDate startDate = LocalDate.now().plusWeeks(-1);
|
||||
|
||||
param.setStartDate(DateUtil.formatLocalDate(startDate));
|
||||
param.setEndDate(DateUtil.formatLocalDate(endDate));
|
||||
return ApiResult.success(statisticsService.getRaddarData(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取饼图数据
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
*/
|
||||
@GetMapping("/index/pie")
|
||||
public ApiResult getPieData(@RequestParam StatisticsParam param) {
|
||||
return ApiResult.success(statisticsService.getPieData(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取柱状图图数据
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025/03/07
|
||||
* @version: 1.2.8
|
||||
*/
|
||||
@GetMapping("/index/bar")
|
||||
public ApiResult getBarData(@RequestParam StatisticsParam param) {
|
||||
LocalDate endDate = LocalDate.now();
|
||||
LocalDate startDate = LocalDate.now().plusWeeks(-1);
|
||||
param.setStartDate(DateUtil.formatLocalDate(startDate));
|
||||
param.setEndDate(DateUtil.formatLocalDate(endDate));
|
||||
return ApiResult.success(statisticsService.getBarData(param));
|
||||
}
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.hula.ai.controller.chat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.hula.ai.common.pojo.PageResult;
|
||||
import com.hula.ai.controller.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import com.hula.ai.controller.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import com.hula.ai.controller.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import com.hula.ai.controller.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import com.hula.ai.dal.chat.AiChatConversationDO;
|
||||
import com.hula.ai.service.chat.AiChatConversationService;
|
||||
import com.hula.ai.service.chat.AiChatMessageService;
|
||||
import com.hula.ai.utils.BeanUtils;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import com.hula.utils.RequestHolder;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.hula.ai.common.pojo.CommonResult.success;
|
||||
import static com.hula.common.utils.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - AI 聊天对话")
|
||||
@RestController
|
||||
@RequestMapping("/ai/chat/conversation")
|
||||
@Validated
|
||||
public class AiChatConversationController {
|
||||
|
||||
@Resource
|
||||
private AiChatConversationService chatConversationService;
|
||||
@Resource
|
||||
private AiChatMessageService chatMessageService;
|
||||
|
||||
@PostMapping("/create-my")
|
||||
@Operation(summary = "创建【我的】聊天对话")
|
||||
public ApiResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
|
||||
return success(chatConversationService.createChatConversationMy(createReqVO, RequestHolder.get().getUid()));
|
||||
}
|
||||
|
||||
@PutMapping("/update-my")
|
||||
@Operation(summary = "更新【我的】聊天对话")
|
||||
public ApiResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) {
|
||||
chatConversationService.updateChatConversationMy(updateReqVO, RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/my-list")
|
||||
@Operation(summary = "获得【我的】聊天对话列表")
|
||||
public ApiResult<List<AiChatConversationRespVO>> getChatConversationMyList() {
|
||||
List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(RequestHolder.get().getUid());
|
||||
return success(BeanUtils.toBean(list, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获得【我的】聊天对话")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public ApiResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(id);
|
||||
if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), RequestHolder.get().getUid())) {
|
||||
conversation = null;
|
||||
}
|
||||
return success(BeanUtils.toBean(conversation, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除聊天对话")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationMy(id, RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-by-unpinned")
|
||||
@Operation(summary = "删除未置顶的聊天对话")
|
||||
public ApiResult<Boolean> deleteChatConversationMyByUnpinned() {
|
||||
chatConversationService.deleteChatConversationMyByUnpinned(RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 对话管理 ==========
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得对话分页", description = "用于【对话管理】菜单")
|
||||
public ApiResult<PageResult<AiChatConversationRespVO>> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
|
||||
PageResult<AiChatConversationDO> pageResult = chatConversationService.getChatConversationPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
// 拼接关联数据
|
||||
Map<Long, Integer> messageCountMap = chatMessageService.getChatMessageCountMap(
|
||||
convertList(pageResult.getList(), AiChatConversationDO::getId));
|
||||
return success(BeanUtils.toBean(pageResult, AiChatConversationRespVO.class,
|
||||
conversation -> conversation.setMessageCount(messageCountMap.getOrDefault(conversation.getId(), 0))));
|
||||
}
|
||||
|
||||
@Operation(summary = "管理员删除对话")
|
||||
@DeleteMapping("/delete-by-admin")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteChatConversationByAdmin(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationByAdmin(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package com.hula.ai.controller.chat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.hula.ai.common.pojo.PageResult;
|
||||
import com.hula.ai.controller.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import com.hula.ai.controller.chat.vo.message.AiChatMessageRespVO;
|
||||
import com.hula.ai.controller.chat.vo.message.AiChatMessageSendReqVO;
|
||||
import com.hula.ai.controller.chat.vo.message.AiChatMessageSendRespVO;
|
||||
import com.hula.ai.dal.chat.AiChatConversationDO;
|
||||
import com.hula.ai.dal.chat.AiChatMessageDO;
|
||||
import com.hula.ai.dal.knowledge.AiKnowledgeDocumentDO;
|
||||
import com.hula.ai.dal.knowledge.AiKnowledgeSegmentDO;
|
||||
import com.hula.ai.dal.model.AiChatRoleDO;
|
||||
import com.hula.ai.service.chat.AiChatConversationService;
|
||||
import com.hula.ai.service.chat.AiChatMessageService;
|
||||
import com.hula.ai.service.knowledge.AiKnowledgeDocumentService;
|
||||
import com.hula.ai.service.knowledge.AiKnowledgeSegmentService;
|
||||
import com.hula.ai.service.model.AiChatRoleService;
|
||||
import com.hula.ai.utils.BeanUtils;
|
||||
import com.hula.ai.utils.MapUtils;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import com.hula.utils.RequestHolder;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.hula.ai.common.pojo.CommonResult.success;
|
||||
import static com.hula.common.utils.CollectionUtils.*;
|
||||
|
||||
|
||||
@Tag(name = "管理后台 - 聊天消息")
|
||||
@RestController
|
||||
@RequestMapping("/ai/chat/message")
|
||||
@Slf4j
|
||||
public class AiChatMessageController {
|
||||
|
||||
@Resource
|
||||
private AiChatMessageService chatMessageService;
|
||||
@Resource
|
||||
private AiChatConversationService chatConversationService;
|
||||
@Resource
|
||||
private AiChatRoleService chatRoleService;
|
||||
@Resource
|
||||
private AiKnowledgeSegmentService knowledgeSegmentService;
|
||||
@Resource
|
||||
private AiKnowledgeDocumentService knowledgeDocumentService;
|
||||
|
||||
@Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢")
|
||||
@PostMapping("/send")
|
||||
public ApiResult<AiChatMessageSendRespVO> sendMessage(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
|
||||
return success(chatMessageService.sendMessage(sendReqVO, RequestHolder.get().getUid()));
|
||||
}
|
||||
|
||||
@Operation(summary = "发送消息(流式)", description = "流式返回,响应较快")
|
||||
@PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<ApiResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
|
||||
return chatMessageService.sendChatMessageStream(sendReqVO, RequestHolder.get().getUid());
|
||||
}
|
||||
|
||||
@Operation(summary = "获得指定对话的消息列表")
|
||||
@GetMapping("/list-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public ApiResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId(
|
||||
@RequestParam("conversationId") Long conversationId) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId);
|
||||
if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), RequestHolder.get().getUid())) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 1. 获取消息列表
|
||||
List<AiChatMessageDO> messageList = chatMessageService.getChatMessageListByConversationId(conversationId);
|
||||
if (CollUtil.isEmpty(messageList)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
|
||||
// 2. 拼接数据,主要是知识库段落信息
|
||||
Map<Long, AiKnowledgeSegmentDO> segmentMap = knowledgeSegmentService.getKnowledgeSegmentMap(convertListByFlatMap(messageList,
|
||||
message -> CollUtil.isEmpty(message.getSegmentIds()) ? null : message.getSegmentIds().stream()));
|
||||
Map<Long, AiKnowledgeDocumentDO> documentMap = knowledgeDocumentService.getKnowledgeDocumentMap(
|
||||
convertList(segmentMap.values(), AiKnowledgeSegmentDO::getDocumentId));
|
||||
List<AiChatMessageRespVO> messageVOList = BeanUtils.toBean(messageList, AiChatMessageRespVO.class);
|
||||
for (int i = 0; i < messageList.size(); i++) {
|
||||
AiChatMessageDO message = messageList.get(i);
|
||||
if (CollUtil.isEmpty(message.getSegmentIds())) {
|
||||
continue;
|
||||
}
|
||||
// 设置知识库段落信息
|
||||
messageVOList.get(i).setSegments(convertList(message.getSegmentIds(), segmentId -> {
|
||||
AiKnowledgeSegmentDO segment = segmentMap.get(segmentId);
|
||||
if (segment == null) {
|
||||
return null;
|
||||
}
|
||||
AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId());
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
return new AiChatMessageRespVO.KnowledgeSegment().setId(segment.getId()).setContent(segment.getContent())
|
||||
.setDocumentId(segment.getDocumentId()).setDocumentName(document.getName());
|
||||
}));
|
||||
}
|
||||
return success(messageVOList);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除消息")
|
||||
@DeleteMapping("/delete")
|
||||
@Parameter(name = "id", required = true, description = "消息编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteChatMessage(@RequestParam("id") Long id) {
|
||||
chatMessageService.deleteChatMessage(id, RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除指定对话的消息")
|
||||
@DeleteMapping("/delete-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
|
||||
chatMessageService.deleteChatMessageByConversationId(conversationId, RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 对话管理 ==========
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得消息分页", description = "用于【对话管理】菜单")
|
||||
public ApiResult<PageResult<AiChatMessageRespVO>> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) {
|
||||
PageResult<AiChatMessageDO> pageResult = chatMessageService.getChatMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
// 拼接数据
|
||||
Map<Long, AiChatRoleDO> roleMap = chatRoleService.getChatRoleMap(
|
||||
convertSet(pageResult.getList(), AiChatMessageDO::getRoleId));
|
||||
return success(BeanUtils.toBean(pageResult, AiChatMessageRespVO.class,
|
||||
respVO -> MapUtils.findAndThen(roleMap, respVO.getRoleId(),
|
||||
role -> respVO.setRoleName(role.getName()))));
|
||||
}
|
||||
|
||||
@Operation(summary = "管理员删除消息")
|
||||
@DeleteMapping("/delete-by-admin")
|
||||
@Parameter(name = "id", required = true, description = "消息编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteChatMessageByAdmin(@RequestParam("id") Long id) {
|
||||
chatMessageService.deleteChatMessageByAdmin(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.hula.ai.controller.chat.vo.conversation;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话创建【我的】 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationCreateMyReqVO {
|
||||
|
||||
@Schema(description = "聊天角色编号", example = "666")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "知识库编号", example = "1204")
|
||||
private Long knowledgeId;
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.hula.ai.controller.chat.vo.conversation;
|
||||
|
||||
import com.hula.ai.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.hula.utils.DateUtil.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话的分页 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "对话标题", example = "你好")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.hula.ai.controller.chat.vo.conversation;
|
||||
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import com.hula.ai.dal.model.AiChatRoleDO;
|
||||
import com.hula.ai.dal.model.AiModelDO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话 Response VO")
|
||||
@Data
|
||||
public class AiChatConversationRespVO implements VO {
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "对话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "角色编号", example = "1")
|
||||
@Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = {"name", "avatar"}, refs = {"roleName", "roleAvatar"})
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = "name", ref = "modelName")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ERNIE-Bot-turbo-0922")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
private String modelName;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer maxContexts;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 关联 role 信息 ==========
|
||||
|
||||
@Schema(description = "角色头像", example = "https://www.iocoder.cn/1.png")
|
||||
private String roleAvatar;
|
||||
|
||||
@Schema(description = "角色名字", example = "小黄")
|
||||
private String roleName;
|
||||
|
||||
// ========== 仅在【对话管理】时加载 ==========
|
||||
|
||||
@Schema(description = "消息数量", example = "20")
|
||||
private Integer messageCount;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.hula.ai.controller.chat.vo.conversation;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话更新【我的】 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationUpdateMyReqVO {
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "对话编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "对话标题", example = "我是一个标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "是否置顶", example = "true")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "模型编号", example = "1")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "知识库编号", example = "1")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "10")
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.hula.ai.controller.chat.vo.message;
|
||||
|
||||
|
||||
import com.hula.ai.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.hula.utils.DateUtil.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息的分页 Request VO")
|
||||
@Data
|
||||
public class AiChatMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "对话编号", example = "2048")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "消息内容", example = "你好")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.hula.ai.controller.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息 Response VO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AiChatMessageRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "回复消息编号", example = "1024")
|
||||
private Long replyId;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role")
|
||||
private String type; // 参见 MessageType 枚举类
|
||||
|
||||
@Schema(description = "用户编号", example = "4096")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "角色编号", example = "888")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "是否携带上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean useContext;
|
||||
|
||||
@Schema(description = "知识库段落编号数组", example = "[1,2,3]")
|
||||
private List<Long> segmentIds;
|
||||
|
||||
@Schema(description = "知识库段落数组")
|
||||
private List<KnowledgeSegment> segments;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-05-12 12:51")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 仅在【对话管理】时加载 ==========
|
||||
|
||||
@Schema(description = "角色名字", example = "小黄")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "知识库段落", example = "Java 开发手册")
|
||||
@Data
|
||||
public static class KnowledgeSegment {
|
||||
|
||||
@Schema(description = "段落编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long documentId;
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品使用手册")
|
||||
private String documentName;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.hula.ai.controller.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
|
||||
@Data
|
||||
public class AiChatMessageSendReqVO {
|
||||
|
||||
@Schema(description = "聊天对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "聊天对话编号不能为空")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "帮我写个 Java 算法")
|
||||
@NotEmpty(message = "聊天内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "是否携带上下文", example = "true")
|
||||
private Boolean useContext;
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.hula.ai.controller.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息发送 Response VO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AiChatMessageSendRespVO {
|
||||
|
||||
@Schema(description = "发送消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Message send;
|
||||
|
||||
@Schema(description = "接收消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Message receive;
|
||||
|
||||
@Schema(description = "消息")
|
||||
@Data
|
||||
public static class Message {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role")
|
||||
private String type; // 参见 MessageType 枚举类
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "知识库段落编号数组", example = "[1,2,3]")
|
||||
private List<Long> segmentIds;
|
||||
|
||||
@Schema(description = "知识库段落数组")
|
||||
private List<AiChatMessageRespVO.KnowledgeSegment> segments;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.AgreementCommand;
|
||||
import com.hula.ai.gpt.pojo.param.AgreementParam;
|
||||
import com.hula.ai.gpt.pojo.vo.AgreementVO;
|
||||
import com.hula.ai.gpt.service.IAgreementService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 内容管理接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/content")
|
||||
public class AgreementController {
|
||||
@Resource
|
||||
private IAgreementService contentService;
|
||||
|
||||
/**
|
||||
* 查询内容管理分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<AgreementVO>> pageContent(@RequestParam AgreementParam param) {
|
||||
return ApiResult.success(contentService.pageContent(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询内容管理列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<AgreementVO>> listContent(@RequestBody AgreementParam param) {
|
||||
return ApiResult.success(contentService.listContent(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容管理详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<AgreementVO> getContentById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(contentService.getContentById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增内容管理
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveContent(@Validated @RequestBody AgreementCommand command) {
|
||||
contentService.saveContent(command);
|
||||
return ApiResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改内容管理
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateContent(@Validated @RequestBody AgreementCommand command) {
|
||||
return ApiResult.returnResult("修改", contentService.updateContent(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除内容管理
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeContentByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", contentService.removeContentByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.AssistantCommand;
|
||||
import com.hula.ai.gpt.pojo.param.AssustantParams;
|
||||
import com.hula.ai.gpt.pojo.vo.AssistantVO;
|
||||
import com.hula.ai.gpt.service.IAssistantService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI助理功能接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025-03-06
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/assistant")
|
||||
public class AssistantController {
|
||||
@Resource
|
||||
private IAssistantService assistantService;
|
||||
|
||||
/**
|
||||
* 查询AI助理功能分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<AssistantVO>> pageAssistant(@RequestParam AssustantParams param) {
|
||||
return ApiResult.success(assistantService.pageAssistant(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询AI助理功能列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<AssistantVO>> listAssistant(@RequestBody AssustantParams param) {
|
||||
return ApiResult.success(assistantService.listAssistant(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AI助理功能详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<AssistantVO> getAssistantById(@PathVariable("id") Long id) {
|
||||
return assistantService.getAssistantById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增AI助理功能
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveAssistant(@Validated @RequestBody AssistantCommand command) {
|
||||
return assistantService.saveAssistant(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改AI助理功能
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateAssistant(@Validated @RequestBody AssistantCommand command) {
|
||||
return assistantService.updateAssistant(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除AI助理功能
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeAssistantByIds(@PathVariable List<Long> ids) {
|
||||
return assistantService.removeAssistantByIds(ids);
|
||||
}
|
||||
|
||||
}
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.AssistantTypeCommand;
|
||||
import com.hula.ai.gpt.pojo.param.AgreementParam;
|
||||
import com.hula.ai.gpt.pojo.param.AssustantTypeParams;
|
||||
import com.hula.ai.gpt.pojo.vo.AssistantTypeVO;
|
||||
import com.hula.ai.gpt.service.IAssistantTypeService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 助手分类接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/assistant-type")
|
||||
public class AssistantTypeController {
|
||||
@Resource
|
||||
private IAssistantTypeService assistantTypeService;
|
||||
|
||||
/**
|
||||
* 查询助手分类分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<AssistantTypeVO>> pageAssistantType(@RequestParam AssustantTypeParams param) {
|
||||
return ApiResult.success(assistantTypeService.pageAssistantType(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询助手分类列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<AssistantTypeVO>> listAssistantType(@RequestBody AgreementParam param) {
|
||||
return ApiResult.success(assistantTypeService.listAssistantType(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取助手分类详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<AssistantTypeVO> getAssistantTypeById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(assistantTypeService.getAssistantTypeById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增助手分类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveAssistantType(@Validated @RequestBody AssistantTypeCommand command) {
|
||||
return ApiResult.returnResult("新增", assistantTypeService.saveAssistantType(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改助手分类
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateAssistantType(@Validated @RequestBody AssistantTypeCommand command) {
|
||||
return ApiResult.returnResult("修改", assistantTypeService.updateAssistantType(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除助手分类
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-11-22
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeAssistantTypeByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", assistantTypeService.removeAssistantTypeByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.param.ChatParam;
|
||||
import com.hula.ai.gpt.pojo.vo.ChatVO;
|
||||
import com.hula.ai.gpt.service.IChatService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 聊天摘要接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController(value = "ChatAiListController")
|
||||
@RequestMapping("/gpt/chat")
|
||||
public class ChatController {
|
||||
@Resource
|
||||
private IChatService chatService;
|
||||
|
||||
/**
|
||||
* 查询聊天摘要分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<ChatVO>> pageChat(@RequestParam ChatParam param) {
|
||||
return ApiResult.success(chatService.pageChat(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询聊天摘要列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<ChatVO>> listChat(@RequestBody ChatParam param) {
|
||||
return ApiResult.success(chatService.listChat(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天摘要详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<ChatVO> getChatById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(chatService.getChatById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除聊天摘要
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeChatByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.success(chatService.removeChatByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.entity.ChatMessage;
|
||||
import com.hula.ai.gpt.pojo.param.ChatMessageParam;
|
||||
import com.hula.ai.gpt.pojo.param.ChatParam;
|
||||
import com.hula.ai.gpt.pojo.vo.ChatMessageVO;
|
||||
import com.hula.ai.gpt.service.IChatMessageService;
|
||||
import com.hula.common.domain.vo.res.CursorPageBaseResp;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 对话消息接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/chat-message")
|
||||
public class ChatMessageController {
|
||||
@Resource
|
||||
private IChatMessageService chatMessageService;
|
||||
|
||||
/**
|
||||
* 查询对话消息分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<ChatMessageVO>> pageChatMessage(@RequestParam ChatMessageParam param) {
|
||||
return ApiResult.success(chatMessageService.pageChatMessage(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询对话消息列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<ChatMessageVO>> listChatMessage(@RequestBody ChatParam param) {
|
||||
return ApiResult.success(chatMessageService.listChatMessage(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对话消息详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<ChatMessageVO> getChatMessageById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(chatMessageService.getChatMessageById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除对话消息
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeChatMessageByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", chatMessageService.removeChatMessageByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.CombCommand;
|
||||
import com.hula.ai.gpt.pojo.param.CombParam;
|
||||
import com.hula.ai.gpt.pojo.vo.CombVO;
|
||||
import com.hula.ai.gpt.service.ICombService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会员套餐接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2025-03-07
|
||||
* 得其道 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/comb")
|
||||
public class CombController {
|
||||
@Resource
|
||||
private ICombService combService;
|
||||
|
||||
/**
|
||||
* 查询会员套餐分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<CombVO>> pageComb(CombParam param) {
|
||||
return ApiResult.success(combService.pageComb(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会员套餐列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<CombVO>> listComb(@RequestBody CombParam param) {
|
||||
return ApiResult.success(combService.listComb(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员套餐详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<CombVO> getCombById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(combService.getCombById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增会员套餐
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveComb(@Validated @RequestBody CombCommand command) {
|
||||
return ApiResult.returnResult("新增", combService.saveComb(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改会员套餐
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateComb(@Validated @RequestBody CombCommand command) {
|
||||
return ApiResult.returnResult("修改", combService.updateComb(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除会员套餐
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeCombByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", combService.removeCombByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.ModelCommand;
|
||||
import com.hula.ai.gpt.pojo.param.ModelParam;
|
||||
import com.hula.ai.gpt.pojo.vo.ModelVO;
|
||||
import com.hula.ai.gpt.service.IModelService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 大模型信息接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/model")
|
||||
public class ModelController {
|
||||
@Resource
|
||||
private IModelService modelService;
|
||||
|
||||
/**
|
||||
* 获取用户模型接口
|
||||
*/
|
||||
@GetMapping("/userModel")
|
||||
public ApiResult<List<ModelVO>> getUserModel(ModelParam param) {
|
||||
param.setStatus(1);
|
||||
return ApiResult.success(modelService.listModel(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询大模型信息分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<ModelVO>> pageModel(ModelParam param) {
|
||||
return ApiResult.success(modelService.pageModel(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询大模型信息列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<ModelVO>> listModel(@RequestBody ModelParam params) {
|
||||
return ApiResult.success(modelService.listModel(params));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大模型信息详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<ModelVO> getModelById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(modelService.getModelById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增大模型信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveModel(@Validated @RequestBody ModelCommand command) {
|
||||
return ApiResult.returnResult("新增", modelService.saveModel(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改大模型信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateModel(@Validated @RequestBody ModelCommand command) {
|
||||
return ApiResult.returnResult("修改", modelService.updateModel(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除大模型信息
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-12-01
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeModelByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", modelService.removeModelByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.OpenkeyCommand;
|
||||
import com.hula.ai.gpt.pojo.param.OpenKeyParam;
|
||||
import com.hula.ai.gpt.pojo.vo.OpenkeyVO;
|
||||
import com.hula.ai.gpt.service.IOpenkeyService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* openai token接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/openkey")
|
||||
public class OpenkeyController {
|
||||
@Resource
|
||||
private IOpenkeyService openkeyService;
|
||||
|
||||
/**
|
||||
* 查询openai token分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<OpenkeyVO>> pageOpenkey(OpenKeyParam param) {
|
||||
return ApiResult.success(openkeyService.pageOpenkey(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询openai token列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<OpenkeyVO>> listOpenkey(@RequestBody OpenKeyParam param) {
|
||||
return ApiResult.success(openkeyService.listOpenkey(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取openai token详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<OpenkeyVO> getOpenkeyById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(openkeyService.getOpenkeyById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增openai token
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveOpenkey(@Validated @RequestBody OpenkeyCommand command) {
|
||||
return ApiResult.returnResult("新增", openkeyService.saveOpenkey(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改openai token
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateOpenkey(@Validated @RequestBody OpenkeyCommand command) {
|
||||
return ApiResult.returnResult("编辑", openkeyService.updateOpenkey(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除openai token
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeOpenkeyByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", openkeyService.removeOpenkeyByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.OrderCommand;
|
||||
import com.hula.ai.gpt.pojo.param.OrderParam;
|
||||
import com.hula.ai.gpt.pojo.vo.OrderVO;
|
||||
import com.hula.ai.gpt.service.IOrderService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/order")
|
||||
public class OrderController {
|
||||
@Resource
|
||||
private IOrderService orderService;
|
||||
|
||||
/**
|
||||
* 查询订单分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<OrderVO>> pageOrder(OrderParam param) {
|
||||
return ApiResult.success(orderService.pageOrder(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<OrderVO>> listOrder(@RequestBody OrderParam param) {
|
||||
return ApiResult.success(orderService.listOrder(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<OrderVO> getOrderById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(orderService.getOrderById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveOrder(@Validated @RequestBody OrderCommand command) {
|
||||
return ApiResult.returnResult("新增", orderService.saveOrder(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改订单
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateOrder(@Validated @RequestBody OrderCommand command) {
|
||||
return ApiResult.returnResult("修改", orderService.updateOrder(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除订单
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeOrderByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", orderService.removeOrderByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.hula.ai.controller.gpt;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.hula.ai.gpt.pojo.command.RedemptionCommand;
|
||||
import com.hula.ai.gpt.pojo.param.RedemptionParam;
|
||||
import com.hula.ai.gpt.pojo.vo.RedemptionVO;
|
||||
import com.hula.ai.gpt.service.IRedemptionService;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 兑换码接口
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
* 得其道
|
||||
* 乾乾
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/gpt/redemption")
|
||||
public class RedemptionController {
|
||||
@Resource
|
||||
private IRedemptionService redemptionService;
|
||||
|
||||
/**
|
||||
* 查询兑换码分页列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ApiResult<IPage<RedemptionVO>> pageRedemption(@RequestParam RedemptionParam param) {
|
||||
return ApiResult.success(redemptionService.pageRedemption(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询兑换码列表
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ApiResult<List<RedemptionVO>> listRedemption(@RequestBody RedemptionParam param) {
|
||||
return ApiResult.success(redemptionService.listRedemption(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取兑换码详细信息
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public ApiResult<RedemptionVO> getRedemptionById(@PathVariable("id") Long id) {
|
||||
return ApiResult.success(redemptionService.getRedemptionById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增兑换码
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResult saveRedemption(@Validated @RequestBody RedemptionCommand command) {
|
||||
return ApiResult.returnResult("保存", redemptionService.saveRedemption(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改兑换码
|
||||
*
|
||||
* @author: 云裂痕
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PutMapping
|
||||
public ApiResult updateRedemption(@Validated @RequestBody RedemptionCommand command) {
|
||||
return ApiResult.returnResult("修改", redemptionService.updateRedemption(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除兑换码
|
||||
*
|
||||
* @author: 云裂痕 false
|
||||
* @date: 2023-04-28
|
||||
* @version: 1.0.0
|
||||
*/
|
||||
@PostMapping("/{ids}")
|
||||
public ApiResult removeRedemptionByIds(@PathVariable List<Long> ids) {
|
||||
return ApiResult.returnResult("删除", redemptionService.removeRedemptionByIds(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
### 生成图片:OpenAI(DALL)
|
||||
POST {{baseUrl}}/ai/image/draw
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "OpenAI",
|
||||
"prompt": "可爱的小喵星人",
|
||||
"model": "dall-e-3",
|
||||
"height": "1024",
|
||||
"width": "1024",
|
||||
"options": {
|
||||
"style": "vivid"
|
||||
}
|
||||
}
|
||||
|
||||
### 生成图片:StableDiffusion
|
||||
POST {{baseUrl}}/ai/image/draw
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "StableDiffusion",
|
||||
"prompt": "中国长城",
|
||||
"model": "stable-diffusion-v1-6",
|
||||
"height": "1024",
|
||||
"width": "1024",
|
||||
"style": "vivid"
|
||||
}
|
||||
|
||||
### 生成图片:生成图片(Midjourney)
|
||||
POST {{baseUrl}}/ai/image/midjourney/imagine
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"prompt": "中国旗袍",
|
||||
"model": "midjourney",
|
||||
"width": "1",
|
||||
"height": "1",
|
||||
"version": "6.0"
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.hula.ai.controller.image;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.hula.ai.common.pojo.PageResult;
|
||||
import com.hula.ai.controller.image.vo.*;
|
||||
import com.hula.ai.controller.image.vo.midjourney.AiMidjourneyActionReqVO;
|
||||
import com.hula.ai.controller.image.vo.midjourney.AiMidjourneyImagineReqVO;
|
||||
import com.hula.ai.core.model.MidjourneyApi;
|
||||
import com.hula.ai.dal.image.AiImageDO;
|
||||
import com.hula.ai.service.image.AiImageService;
|
||||
import com.hula.ai.utils.BeanUtils;
|
||||
import com.hula.domain.vo.res.ApiResult;
|
||||
import com.hula.utils.RequestHolder;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.hula.ai.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - AI 绘画")
|
||||
@RestController
|
||||
@RequestMapping("/ai/image")
|
||||
@Slf4j
|
||||
public class AiImageController {
|
||||
|
||||
@Resource
|
||||
private AiImageService imageService;
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获取【我的】绘图分页")
|
||||
public ApiResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated AiImagePageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePageMy(RequestHolder.get().getUid(), pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/public-page")
|
||||
@Operation(summary = "获取公开的绘图分页")
|
||||
public ApiResult<PageResult<AiImageRespVO>> getImagePagePublic(AiImagePublicPageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePagePublic(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获取【我的】绘图记录")
|
||||
@Parameter(name = "id", required = true, description = "绘画编号", example = "1024")
|
||||
public ApiResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) {
|
||||
AiImageDO image = imageService.getImage(id);
|
||||
if (image == null || ObjUtil.notEqual(RequestHolder.get().getUid(), image.getUserId())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(image, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/my-list-by-ids")
|
||||
@Operation(summary = "获取【我的】绘图记录列表")
|
||||
@Parameter(name = "ids", required = true, description = "绘画编号数组", example = "1024,2048")
|
||||
public ApiResult<List<AiImageRespVO>> getImageListMyByIds(@RequestParam("ids") List<Long> ids) {
|
||||
List<AiImageDO> imageList = imageService.getImageList(ids);
|
||||
imageList.removeIf(item -> !ObjUtil.equal(RequestHolder.get().getUid(), item.getUserId()));
|
||||
return success(BeanUtils.toBean(imageList, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "生成图片")
|
||||
@PostMapping("/draw")
|
||||
public ApiResult<Long> drawImage(@Valid @RequestBody AiImageDrawReqVO drawReqVO) {
|
||||
return success(imageService.drawImage(RequestHolder.get().getUid(), drawReqVO));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除【我的】绘画记录")
|
||||
@DeleteMapping("/delete-my")
|
||||
@Parameter(name = "id", required = true, description = "绘画编号", example = "1024")
|
||||
public ApiResult<Boolean> deleteImageMy(@RequestParam("id") Long id) {
|
||||
imageService.deleteImageMy(id, RequestHolder.get().getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ================ midjourney 专属 ================
|
||||
|
||||
@Operation(summary = "【Midjourney】生成图片")
|
||||
@PostMapping("/midjourney/imagine")
|
||||
public ApiResult<Long> midjourneyImagine(@Valid @RequestBody AiMidjourneyImagineReqVO reqVO) {
|
||||
Long imageId = imageService.midjourneyImagine(RequestHolder.get().getUid(), reqVO);
|
||||
return success(imageId);
|
||||
}
|
||||
|
||||
@Operation(summary = "【Midjourney】通知图片进展", description = "由 Midjourney Proxy 回调")
|
||||
@PostMapping("/midjourney/notify") // 必须是 POST 方法,否则会报错
|
||||
@PermitAll
|
||||
public ApiResult<Boolean> midjourneyNotify(@Valid @RequestBody MidjourneyApi.Notify notify) {
|
||||
imageService.midjourneyNotify(notify);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "【Midjourney】Action 操作(二次生成图片)", description = "例如说:放大、缩小、U1、U2 等")
|
||||
@PostMapping("/midjourney/action")
|
||||
public ApiResult<Long> midjourneyAction(@Valid @RequestBody AiMidjourneyActionReqVO reqVO) {
|
||||
Long imageId = imageService.midjourneyAction(RequestHolder.get().getUid(), reqVO);
|
||||
return success(imageId);
|
||||
}
|
||||
|
||||
// ================ 绘图管理 ================
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得绘画分页")
|
||||
public ApiResult<PageResult<AiImageRespVO>> getImagePage(@Valid AiImagePageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新绘画")
|
||||
public ApiResult<Boolean> updateImage(@Valid @RequestBody AiImageUpdateReqVO updateReqVO) {
|
||||
imageService.updateImage(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除绘画")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public ApiResult<Boolean> deleteImage(@RequestParam("id") Long id) {
|
||||
imageService.deleteImage(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.hula.ai.controller.image.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.springframework.ai.openai.OpenAiImageOptions;
|
||||
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画 Request VO")
|
||||
@Data
|
||||
public class AiImageDrawReqVO {
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "模型编号不能为空")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "画一个长城")
|
||||
@NotEmpty(message = "提示词不能为空")
|
||||
@Size(max = 1200, message = "提示词最大 1200")
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 1. dall-e-2 模型:256x256、512x512、1024x1024
|
||||
* 2. dall-e-3 模型:1024x1024, 1792x1024, 或 1024x1792
|
||||
*/
|
||||
@Schema(description = "图片高度")
|
||||
@NotNull(message = "图片高度不能为空")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "图片宽度")
|
||||
@NotNull(message = "图片宽度不能为空")
|
||||
private Integer width;
|
||||
|
||||
// ========== 各平台绘画的拓展参数 ==========
|
||||
|
||||
/**
|
||||
* 绘制参数,不同 platform 的不同参数
|
||||
*
|
||||
* 1. {@link OpenAiImageOptions}
|
||||
* 2. {@link StabilityAiImageOptions}
|
||||
*/
|
||||
@Schema(description = "绘制参数")
|
||||
private Map<String, String> options;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.hula.ai.controller.image.vo;
|
||||
|
||||
import com.hula.ai.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.hula.utils.DateUtil.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画分页 Request VO")
|
||||
@Data
|
||||
public class AiImagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "28987")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "提示词", example = "1")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "绘画状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否发布", example = "1")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.hula.ai.controller.image.vo;
|
||||
|
||||
import com.hula.ai.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画公开的分页 Request VO")
|
||||
@Data
|
||||
public class AiImagePublicPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "提示词")
|
||||
private String prompt;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.hula.ai.controller.image.vo;
|
||||
|
||||
import com.hula.ai.core.model.MidjourneyApi;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画 Response VO")
|
||||
@Data
|
||||
public class AiImageRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
private String platform; // 参见 AiPlatformEnum 枚举
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "南极的小企鹅")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "绘画状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "public")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "图片地址", example = "https://www.iocoder.cn/1.png")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "绘画错误信息", example = "图片错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "绘制参数")
|
||||
private Map<String, String> options;
|
||||
|
||||
@Schema(description = "mj buttons 按钮")
|
||||
private List<MidjourneyApi.Button> buttons;
|
||||
|
||||
@Schema(description = "完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hula.ai.controller.image.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画修改 Request VO")
|
||||
@Data
|
||||
public class AiImageUpdateReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否发布", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.hula.ai.controller.image.vo.midjourney;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘图操作(Midjourney) Request VO")
|
||||
@Data
|
||||
public class AiMidjourneyActionReqVO {
|
||||
|
||||
@Schema(description = "图片编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "操作按钮编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "MJ::JOB::variation::4::06aa3e66-0e97-49cc-8201-e0295d883de4")
|
||||
@NotEmpty(message = "操作按钮编号不能为空")
|
||||
private String customId;
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.hula.ai.controller.image.vo.midjourney;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画生成(Midjourney) Request VO")
|
||||
@Data
|
||||
public class AiMidjourneyImagineReqVO {
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "中国神龙")
|
||||
@NotEmpty(message = "提示词不能为空!")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "模型编号不能为空")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片宽度不能为空")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片高度不能为空")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.0")
|
||||
@NotEmpty(message = "版本号不能为空")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "参考图", example = "https://www.iocoder.cn/x.png")
|
||||
private String referImageUrl;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user