feat(metis-starter): 添加模型平台相关功能

- 新增日期格式枚举类 DateFormattersEnum
- 添加 Jackson 自动配置类 JacksonAutoConfiguration
- 创建基础实体类 Model 和 ModelPlatform
- 实现 ModelPlatform 相关的转换类、信息类、Mapper 和 Service
- 添加 LLM 模型服务接口和实现类
- 新增 LLM 模型类型枚举 ModelTypeEnum
- 定义平台模型列表接口 PlatformModeList
This commit is contained in:
2025-04-26 22:36:52 +08:00
parent ddb5f4e36c
commit 61047720ab
13 changed files with 488 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.metis.config;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.stream.Stream;
@Getter
@AllArgsConstructor
public enum DateFormatterEnum {
/**
* 时间格式
*/
COMMON_DATE_TIME(0, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())),
COMMON_SHORT_DATE(1, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneId.systemDefault())),
COMMON_MONTH_DAY(2, DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.systemDefault())),
COMMON_MONTH(3, DateTimeFormatter.ofPattern("yyyy-MM").withZone(ZoneId.systemDefault())),
YEAR(4, DateTimeFormatter.ofPattern("yyyy").withZone(ZoneId.systemDefault())),
COLON_DELIMITED_TIME(5, DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.systemDefault())),
COLON_DELIMITED_SHORT_TIME(6, DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault())),
CHINESE_DATE_TIME(7, DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒").withZone(ZoneId.systemDefault())),
CHINESE_SHORT_DATE(8, DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分").withZone(ZoneId.systemDefault())),
CHINESE_DATE(9, DateTimeFormatter.ofPattern("yyyy年MM月dd日").withZone(ZoneId.systemDefault())),
CHINESE_MONTH(10, DateTimeFormatter.ofPattern("yyyy年MM月").withZone(ZoneId.systemDefault())),
CHINESE_YEAR(11, DateTimeFormatter.ofPattern("yyyy年").withZone(ZoneId.systemDefault())),
CHINESE_TIME(12, DateTimeFormatter.ofPattern("HH时mm分ss秒").withZone(ZoneId.systemDefault())),
CHINESE_SHORT_TIME(13, DateTimeFormatter.ofPattern("HH时mm分").withZone(ZoneId.systemDefault()));
private final Integer code;
private final DateTimeFormatter dateTimeFormatter;
public static DateFormatterEnum findByCode(int code){
return Stream.of(values())
.filter(e -> e.getCode().equals(code))
.findAny()
.orElse(null);
}
}

View File

@@ -0,0 +1,144 @@
package com.metis.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
* 杰克逊自动配置
*
* @author clay
* @date 2025/04/26
*/
@Order(Integer.MIN_VALUE)
@AutoConfiguration
@AllArgsConstructor
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class)
public class JacksonAutoConfiguration {
/**
* Jackson2ObjectMapperBuilder
*
* @return {@link Jackson2ObjectMapperBuilder}
*/
@Bean
@Primary
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.locale(Locale.CHINA);
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
//时间类型支持
JavaTimeModule javaTimeModule = buildJavaTimeModule();
//其他类型支持
SimpleModule simpleModule = buildSimpleModule();
builder.modules(javaTimeModule,simpleModule);
return builder;
}
/**
* ObjectMapper
*
* @param builder 建设者
* @return {@link ObjectMapper}
*/
@Bean
@Primary
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.findAndRegisterModules();
// 其他配置
// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true);
objectMapper.configure(JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION, true);
//开启整数反序列化时使用长整型long的选项。确保处理的数据不会因类型限制丢失信息
objectMapper.configure(DeserializationFeature.USE_LONG_FOR_INTS, true);
//开启输出缩进功能。这通常用于美化JSON格式输出使结构更清晰易读
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
//禁用报错
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
/**
* 构建简单模块
*
* @return {@link SimpleModule}
*/
private SimpleModule buildSimpleModule() {
SimpleModule simpleModule = new SimpleModule();
//BigInteger
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
simpleModule.addDeserializer(BigInteger.class, new NumberDeserializers.BigIntegerDeserializer());
//Long
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addDeserializer(Long.class, new NumberDeserializers.LongDeserializer(Long.class, null));
//BigDecimal
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
simpleModule.addDeserializer(BigDecimal.class, new NumberDeserializers.BigDecimalDeserializer());
return simpleModule;
}
/**
* 构建Java时间模块
*
* @return {@link JavaTimeModule}
*/
private JavaTimeModule buildJavaTimeModule() {
// 添加自定义序列化和反序列化器
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateFormatterEnum.COMMON_DATE_TIME.getDateTimeFormatter()));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateFormatterEnum.COMMON_DATE_TIME.getDateTimeFormatter()));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateFormatterEnum.COMMON_MONTH_DAY.getDateTimeFormatter()));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateFormatterEnum.COLON_DELIMITED_TIME.getDateTimeFormatter()));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateFormatterEnum.COMMON_MONTH_DAY.getDateTimeFormatter()));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateFormatterEnum.COLON_DELIMITED_TIME.getDateTimeFormatter()));
//不提供 java.util.Date 的序列化处理,全项目禁用 java.util.Date 类
return javaTimeModule;
}
}

View File

@@ -0,0 +1,16 @@
package com.metis.convert;
import com.metis.domain.entity.ModelPlatform;
import com.metis.domain.entity.ModelPlatformInfo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ModelPlatformConvert {
ModelPlatformConvert INSTANCE = Mappers.getMapper(ModelPlatformConvert.class);
ModelPlatformInfo toInfo(ModelPlatform modelPlatform);
}

View File

@@ -0,0 +1,64 @@
package com.metis.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.metis.domain.SimpleBaseEntity;
import com.metis.enums.ModelTypeEnum;
import com.metis.enums.YesOrNoEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* llm model平台
*
* @author clay
* @date 2025/04/26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("model_platform")
public class ModelPlatform extends SimpleBaseEntity {
/**
* 主键
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 名字
*/
private String name;
/**
* 类型
*/
private ModelTypeEnum type;
/**
* 自定义类型
*/
private String customType;
/**
* 请求地址
*/
private String url;
/**
* api密匙
*/
private String apiKey;
/**
* 状态
*/
private YesOrNoEnum state;
/**
* 描述
*/
private String description;
}

View File

@@ -0,0 +1,28 @@
package com.metis.domain.entity;
import com.metis.enums.ModelTypeEnum;
import lombok.Data;
@Data
public class ModelPlatformInfo {
/**
* 名字
*/
private String name;
/**
* 类型
*/
private ModelTypeEnum type;
/**
* 请求地址
*/
private String url;
/**
* api密匙
*/
private String apiKey;
}

View File

@@ -0,0 +1,12 @@
package com.metis.domain.entity.base;
import lombok.Data;
@Data
public class Model {
private String name;
}

View File

@@ -0,0 +1,51 @@
package com.metis.enums;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Optional;
/**
* llm 类型 枚举
*
* @author clay
* @date 2025/04/26
*/
@Getter
@AllArgsConstructor
public enum ModelTypeEnum implements BaseEnum<ModelTypeEnum> {
CUSTOM(0, "自定义"),
OPEN_AI(1, "OpenAI"),
OLLAMA(2, "Ollama"),
;
@JsonValue
private final Integer code;
private final String name;
/**
* 根据 code 转换枚举
*
* @param code 编码
* @return 枚举
*/
public static Optional<ModelTypeEnum> of(Integer code) {
return Optional.ofNullable(BaseEnum.parseByCode(ModelTypeEnum.class, code));
}
/**
* 枚举序列化器(前端传code时自动转换为对应枚举)
*
* @param code 编码
* @return 枚举
*/
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static ModelTypeEnum get(Integer code) {
return BaseEnum.parseByCode(ModelTypeEnum.class, code);
}
}

View File

@@ -0,0 +1,19 @@
package com.metis.llm;
import com.metis.domain.entity.base.Model;
import java.util.List;
public interface ModelService {
/**
* 列表
*
* @param modelId llm id
* @return {@link List }<{@link Model }>
*/
List<Model> listModel(Long modelId);
}

View File

@@ -0,0 +1,23 @@
package com.metis.llm;
import com.metis.domain.entity.ModelPlatform;
import com.metis.domain.entity.base.Model;
import com.metis.enums.ModelTypeEnum;
import java.util.List;
public interface PlatformModeList {
List<Model> modelList(ModelPlatform modelPlatform);
/**
* 得到类型
*
* @return {@link ModelTypeEnum }
*/
ModelTypeEnum getType();
}

View File

@@ -0,0 +1,31 @@
package com.metis.llm.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.metis.domain.entity.ModelPlatform;
import com.metis.domain.entity.base.Model;
import com.metis.llm.ModelService;
import com.metis.service.ModelPlatformService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class ModelServiceImpl implements ModelService {
private final ModelPlatformService modelPlatformService;
@Override
public List<Model> listModel(Long modelId) {
Assert.isTrue(ObjectUtil.isNotNull(modelId), "模型平台ID不能为空");
ModelPlatform modelPlatform = modelPlatformService.getById(modelId);
Assert.isTrue(ObjectUtil.isNotNull(modelPlatform), "模型平台不存在");
return List.of();
}
}

View File

@@ -0,0 +1,18 @@
package com.metis.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.metis.domain.entity.ModelPlatform;
/**
* LLM模型平台映射器
*
* @author clay
* @date 2025/04/26
*/
public interface ModelPlatformMapper extends BaseMapper<ModelPlatform> {
}

View File

@@ -0,0 +1,14 @@
package com.metis.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.metis.domain.entity.ModelPlatform;
/**
* LLM模型平台服务
*
* @author clay
* @date 2025/04/26
*/
public interface ModelPlatformService extends IService<ModelPlatform> {
}

View File

@@ -0,0 +1,25 @@
package com.metis.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.metis.domain.entity.ModelPlatform;
import com.metis.mapper.ModelPlatformMapper;
import com.metis.service.ModelPlatformService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* LLM模型平台服务实现
*
* @author clay
* @date 2025/04/26
*/
@Slf4j
@Service
public class ModelPlatformServiceImpl extends ServiceImpl<ModelPlatformMapper, ModelPlatform>
implements ModelPlatformService {
}