feat(ai): 添加AI模型管理和分段上传功能
- 创建AI模型版本管理表tz_ai_model并添加相关索引 - 添加AiModelController、AiModelService等完整的模型管理接口 - 实现模型创建、更新、删除、分页查询等功能 - 添加模型状态更新功能支持启用禁用等状态变更 - 在S3FileClient中实现分段上传uploadMultipart方法 - 扩展FileApi接口增加createFileMultipart分段上传接口 - 修改Nacos配置将命名空间从dev改为具体ID值 - 在SecurityConfiguration中开放AI模型管理接口权限
This commit is contained in:
@@ -111,3 +111,26 @@ CREATE TABLE `tz_ai_dialog_message`
|
|||||||
) ENGINE = InnoDB COMMENT ='ai-对话消息表';
|
) ENGINE = InnoDB COMMENT ='ai-对话消息表';
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `tz_ai_model`;
|
||||||
|
CREATE TABLE `tz_ai_model`
|
||||||
|
(
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`model_name` varchar(128) NOT NULL COMMENT '模型名称',
|
||||||
|
`version` varchar(32) NOT NULL COMMENT '版本号',
|
||||||
|
`load_percentage` decimal(5,4) NULL DEFAULT 0.0000 COMMENT '负载百分比',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 0 COMMENT '状态(0-禁用 1-启用 2-测试中 3-已废弃)',
|
||||||
|
`description` varchar(500) NULL DEFAULT '' COMMENT '版本描述',
|
||||||
|
`creator` varchar(64) NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
INDEX `idx_model_name` (`model_name` ASC) USING BTREE,
|
||||||
|
INDEX `idx_version` (`version` ASC) USING BTREE,
|
||||||
|
INDEX `idx_status` (`status` ASC) USING BTREE,
|
||||||
|
INDEX `idx_create_time` (`create_time` ASC) USING BTREE
|
||||||
|
) ENGINE = InnoDB COMMENT = 'AI模型版本管理表';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,4 +59,10 @@ public interface FileApi {
|
|||||||
*/
|
*/
|
||||||
@PostMapping(PREFIX + "/create")
|
@PostMapping(PREFIX + "/create")
|
||||||
CommonResult<String> createFile(@Valid @RequestBody FileCreateReqDTO createReqDTO);
|
CommonResult<String> createFile(@Valid @RequestBody FileCreateReqDTO createReqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分段上传文件
|
||||||
|
*/
|
||||||
|
@PostMapping(PREFIX + "/create-multipart")
|
||||||
|
CommonResult<String> createFileMultipart(@Valid @RequestBody FileCreateReqDTO createReqDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package com.tashow.cloud.fileapi.api.file.dto;
|
|||||||
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
/** RPC 服务 - 文件创建 Request DTO */
|
/** RPC 服务 - 文件创建 Request DTO */
|
||||||
@Data
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
public class FileCreateReqDTO {
|
public class FileCreateReqDTO {
|
||||||
|
|
||||||
/** 原文件名称 */
|
/** 原文件名称 */
|
||||||
@@ -13,9 +15,10 @@ public class FileCreateReqDTO {
|
|||||||
/** 文件路径 */
|
/** 文件路径 */
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
/**
|
/** 文件访问地址 */
|
||||||
* 文件内容
|
private String url;
|
||||||
*/
|
|
||||||
|
/** 文件内容 */
|
||||||
@NotEmpty(message = "文件内容不能为空")
|
@NotEmpty(message = "文件内容不能为空")
|
||||||
private byte[] content;
|
private byte[] content;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.tashow.cloud.ai.controller.admin.model;
|
||||||
|
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelPageReqVO;
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelRespVO;
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelSaveReqVO;
|
||||||
|
import com.tashow.cloud.ai.dal.dataobject.model.AiModelDO;
|
||||||
|
import com.tashow.cloud.ai.service.model.AiModelService;
|
||||||
|
import com.tashow.cloud.common.pojo.CommonResult;
|
||||||
|
import com.tashow.cloud.common.pojo.PageResult;
|
||||||
|
import com.tashow.cloud.common.util.object.BeanUtils;
|
||||||
|
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 org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import static com.tashow.cloud.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - AI模型管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ai/model")
|
||||||
|
@Validated
|
||||||
|
public class AiModelController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AiModelService modelService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建模型")
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<Long> createModel(@Valid @RequestBody AiModelSaveReqVO createReqVO) {
|
||||||
|
return success(modelService.createModel(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新模型")
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<Boolean> updateModel(@Valid @RequestBody AiModelSaveReqVO updateReqVO) {
|
||||||
|
modelService.updateModel(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除模型")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<Boolean> deleteModel(@RequestParam("id") Long id) {
|
||||||
|
modelService.deleteModel(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得模型")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<AiModelRespVO> getModel(@RequestParam("id") Long id) {
|
||||||
|
AiModelDO model = modelService.getModel(id);
|
||||||
|
return success(BeanUtils.toBean(model, AiModelRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得模型分页")
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<PageResult<AiModelRespVO>> getModelPage(@Valid AiModelPageReqVO pageReqVO) {
|
||||||
|
PageResult<AiModelDO> pageResult = modelService.getModelPage(pageReqVO);
|
||||||
|
return success(BeanUtils.toBean(pageResult, AiModelRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update-status")
|
||||||
|
@Operation(summary = "更新状态")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@Parameter(name = "status", description = "状态(0-禁用 1-启用 2-测试中 3-已废弃)", required = true)
|
||||||
|
@PermitAll
|
||||||
|
public CommonResult<Boolean> updateStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
|
||||||
|
modelService.updateStatus(id, status);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.tashow.cloud.ai.controller.admin.model.vo;
|
||||||
|
|
||||||
|
import com.tashow.cloud.common.pojo.PageParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI模型分页 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class AiModelPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "模型名称(模糊查询)", example = "宠物声音翻译")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "版本号(精确查询)", example = "v1.0.0")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0-禁用 1-启用 2-测试中 3-已废弃)", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.tashow.cloud.ai.controller.admin.model.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI模型 Response VO")
|
||||||
|
@Data
|
||||||
|
public class AiModelRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模型名称", example = "模型")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "版本号", example = "v1.0.0")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Schema(description = "负载", example = "0.75")
|
||||||
|
private BigDecimal loadPercentage;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0-禁用 1-启用 2-测试中 3-已废弃)", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "版本描述", example = "描述")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.tashow.cloud.ai.controller.admin.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI模型新增/修改 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AiModelSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "宠物声音翻译模型")
|
||||||
|
@NotBlank(message = "模型名称不能为空")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0")
|
||||||
|
@NotBlank(message = "版本号不能为空")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Schema(description = "负载百分比(0.0-1.0)", example = "0.75")
|
||||||
|
private BigDecimal loadPercentage;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0-禁用 1-启用 2-测试中 3-已废弃)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "状态不能为空")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "版本描述", example = "优化了翻译准确率")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.tashow.cloud.ai.dal.dataobject.model;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模型管理 DO
|
||||||
|
*
|
||||||
|
* @author tashow
|
||||||
|
*/
|
||||||
|
@TableName("tz_ai_model")
|
||||||
|
@KeySequence("tz_ai_model_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AiModelDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型名称
|
||||||
|
*/
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 版本号
|
||||||
|
*/
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 负载百分比(0.0-1.0)
|
||||||
|
*/
|
||||||
|
private BigDecimal loadPercentage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0-禁用 1-启用 2-测试中 3-已废弃)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 版本描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.tashow.cloud.ai.dal.mysql.model;
|
||||||
|
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelPageReqVO;
|
||||||
|
import com.tashow.cloud.ai.dal.dataobject.model.AiModelDO;
|
||||||
|
import com.tashow.cloud.common.pojo.PageResult;
|
||||||
|
import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模型管理 Mapper
|
||||||
|
*
|
||||||
|
* @author tashow
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AiModelMapper extends BaseMapperX<AiModelDO> {
|
||||||
|
|
||||||
|
default PageResult<AiModelDO> selectPage(AiModelPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<AiModelDO>()
|
||||||
|
.likeIfPresent(AiModelDO::getModelName, reqVO.getModelName())
|
||||||
|
.eqIfPresent(AiModelDO::getVersion, reqVO.getVersion())
|
||||||
|
.eqIfPresent(AiModelDO::getStatus, reqVO.getStatus())
|
||||||
|
.orderByDesc(AiModelDO::getCreateTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,6 +32,8 @@ public class SecurityConfiguration {
|
|||||||
.requestMatchers(adminSeverContextPath + "/**").permitAll();
|
.requestMatchers(adminSeverContextPath + "/**").permitAll();
|
||||||
// 文件读取
|
// 文件读取
|
||||||
registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
|
registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
|
||||||
|
// AI模型管理接口
|
||||||
|
registry.requestMatchers("/ai/model/**").permitAll();
|
||||||
// RPC 服务的安全配置
|
// RPC 服务的安全配置
|
||||||
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.tashow.cloud.ai.service.model;
|
||||||
|
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelPageReqVO;
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelSaveReqVO;
|
||||||
|
import com.tashow.cloud.ai.dal.dataobject.model.AiModelDO;
|
||||||
|
import com.tashow.cloud.common.pojo.PageResult;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模型管理 Service 接口
|
||||||
|
*
|
||||||
|
* @author tashow
|
||||||
|
*/
|
||||||
|
public interface AiModelService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建模型
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createModel(@Valid AiModelSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新模型
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateModel(@Valid AiModelSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除模型
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteModel(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得模型
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 模型
|
||||||
|
*/
|
||||||
|
AiModelDO getModel(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得模型分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 模型分页
|
||||||
|
*/
|
||||||
|
PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新状态
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @param status 状态
|
||||||
|
*/
|
||||||
|
void updateStatus(Long id, Integer status);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.tashow.cloud.ai.service.model;
|
||||||
|
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelPageReqVO;
|
||||||
|
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelSaveReqVO;
|
||||||
|
import com.tashow.cloud.ai.dal.dataobject.model.AiModelDO;
|
||||||
|
import com.tashow.cloud.ai.dal.mysql.model.AiModelMapper;
|
||||||
|
import com.tashow.cloud.common.pojo.PageResult;
|
||||||
|
import com.tashow.cloud.common.util.object.BeanUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模型管理 Service 实现类
|
||||||
|
*
|
||||||
|
* @author tashow
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class AiModelServiceImpl implements AiModelService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AiModelMapper modelMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createModel(AiModelSaveReqVO createReqVO) {
|
||||||
|
AiModelDO model = BeanUtils.toBean(createReqVO, AiModelDO.class);
|
||||||
|
modelMapper.insert(model);
|
||||||
|
return model.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateModel(AiModelSaveReqVO updateReqVO) {
|
||||||
|
AiModelDO updateObj = BeanUtils.toBean(updateReqVO, AiModelDO.class);
|
||||||
|
modelMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteModel(Long id) {
|
||||||
|
modelMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AiModelDO getModel(Long id) {
|
||||||
|
return modelMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO) {
|
||||||
|
return modelMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateStatus(Long id, Integer status) {
|
||||||
|
AiModelDO updateObj = new AiModelDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setStatus(status);
|
||||||
|
modelMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,12 +7,11 @@ spring:
|
|||||||
username: nacos # Nacos 账号
|
username: nacos # Nacos 账号
|
||||||
password: nacos # Nacos 密码
|
password: nacos # Nacos 密码
|
||||||
discovery: # 【配置中心】配置项
|
discovery: # 【配置中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
# 添加字符编码配置,解决YAML解析时的字符编码问题
|
|
||||||
encode: UTF-8
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import static com.tashow.cloud.common.pojo.CommonResult.success;
|
import static com.tashow.cloud.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||||
@Validated
|
@Validated
|
||||||
public class FileApiImpl implements FileApi {
|
public class FileApiImpl implements FileApi {
|
||||||
@@ -24,4 +25,11 @@ public class FileApiImpl implements FileApi {
|
|||||||
createReqDTO.getContent()));
|
createReqDTO.getContent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<String> createFileMultipart(FileCreateReqDTO createReqDTO) {
|
||||||
|
return success(fileService.createFileMultipart(createReqDTO.getName(), createReqDTO.getPath(),
|
||||||
|
createReqDTO.getContent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,13 @@ import com.amazonaws.services.s3.AmazonS3Client;
|
|||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||||
import com.amazonaws.services.s3.model.ObjectMetadata;
|
import com.amazonaws.services.s3.model.ObjectMetadata;
|
||||||
import com.amazonaws.services.s3.model.S3Object;
|
import com.amazonaws.services.s3.model.S3Object;
|
||||||
|
import com.amazonaws.services.s3.model.*;
|
||||||
import com.tashow.cloud.file.framework.file.core.client.AbstractFileClient;
|
import com.tashow.cloud.file.framework.file.core.client.AbstractFileClient;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +95,32 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
|
|||||||
objectMetadata);
|
objectMetadata);
|
||||||
|
|
||||||
// 拼接返回路径
|
// 拼接返回路径
|
||||||
return config.getDomain() + "/" + path;
|
return config.getDomain() + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分段上传 */
|
||||||
|
public String uploadMultipart(byte[] content, String path, String type) throws Exception {
|
||||||
|
int partSize = 5 * 1024 * 1024;
|
||||||
|
ObjectMetadata metadata = new ObjectMetadata();
|
||||||
|
metadata.setContentType(type);
|
||||||
|
String uploadId = client.initiateMultipartUpload(new InitiateMultipartUploadRequest(config.getBucket(), path, metadata)).getUploadId();
|
||||||
|
try {
|
||||||
|
List<PartETag> partETags = new ArrayList<>();
|
||||||
|
for (int i = 0, partNum = 1; i < content.length; i += partSize, partNum++) {
|
||||||
|
int size = Math.min(partSize, content.length - i);
|
||||||
|
byte[] part = new byte[size];
|
||||||
|
System.arraycopy(content, i, part, 0, size);
|
||||||
|
UploadPartResult result = client.uploadPart(new UploadPartRequest()
|
||||||
|
.withBucketName(config.getBucket()).withKey(path).withUploadId(uploadId)
|
||||||
|
.withPartNumber(partNum).withInputStream(new ByteArrayInputStream(part)).withPartSize(size));
|
||||||
|
partETags.add(result.getPartETag());
|
||||||
|
}
|
||||||
|
client.completeMultipartUpload(new CompleteMultipartUploadRequest(config.getBucket(), path, uploadId, partETags));
|
||||||
|
return config.getDomain() + path;
|
||||||
|
} catch (Exception e) {
|
||||||
|
client.abortMultipartUpload(new AbortMultipartUploadRequest(config.getBucket(), path, uploadId));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public interface FileService {
|
|||||||
*/
|
*/
|
||||||
String createFile(String name, String path, byte[] content);
|
String createFile(String name, String path, byte[] content);
|
||||||
|
|
||||||
|
/** 分段上传文件 */
|
||||||
|
String createFileMultipart(String name, String path, byte[] content);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建文件
|
* 创建文件
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.tashow.cloud.file.dal.dataobject.file.FileDO;
|
|||||||
import com.tashow.cloud.file.dal.mysql.file.FileMapper;
|
import com.tashow.cloud.file.dal.mysql.file.FileMapper;
|
||||||
import com.tashow.cloud.file.framework.file.core.client.FileClient;
|
import com.tashow.cloud.file.framework.file.core.client.FileClient;
|
||||||
import com.tashow.cloud.file.framework.file.core.client.s3.FilePresignedUrlRespDTO;
|
import com.tashow.cloud.file.framework.file.core.client.s3.FilePresignedUrlRespDTO;
|
||||||
|
import com.tashow.cloud.file.framework.file.core.client.s3.S3FileClient;
|
||||||
import com.tashow.cloud.file.framework.file.core.utils.FileTypeUtils;
|
import com.tashow.cloud.file.framework.file.core.utils.FileTypeUtils;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -70,6 +71,30 @@ public class FileServiceImpl implements FileService {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public String createFileMultipart(String name, String path, byte[] content) {
|
||||||
|
String type = FileTypeUtils.getMineType(content, name);
|
||||||
|
if (StrUtil.isEmpty(path)) {
|
||||||
|
path = FileUtils.generatePath(content, name);
|
||||||
|
}
|
||||||
|
if (StrUtil.isEmpty(name)) {
|
||||||
|
name = path;
|
||||||
|
}
|
||||||
|
FileClient client = fileConfigService.getMasterFileClient();
|
||||||
|
Assert.notNull(client, "客户端(master) 不能为空");
|
||||||
|
String url = ((S3FileClient) client).uploadMultipart(content, path, type);
|
||||||
|
FileDO file = new FileDO();
|
||||||
|
file.setConfigId(client.getId());
|
||||||
|
file.setName(name);
|
||||||
|
file.setPath(path);
|
||||||
|
file.setUrl(url);
|
||||||
|
file.setType(type);
|
||||||
|
file.setSize(content.length);
|
||||||
|
fileMapper.insert(file);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createFile(FileCreateReqVO createReqVO) {
|
public Long createFile(FileCreateReqVO createReqVO) {
|
||||||
FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);
|
FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);
|
||||||
|
|||||||
@@ -7,13 +7,11 @@ spring:
|
|||||||
username: nacos # Nacos 账号
|
username: nacos # Nacos 账号
|
||||||
password: nacos # Nacos 密码
|
password: nacos # Nacos 密码
|
||||||
discovery: # 【配置中心】配置项
|
discovery: # 【配置中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ spring:
|
|||||||
username: nacos # Nacos 账号
|
username: nacos # Nacos 账号
|
||||||
password: nacos # Nacos 密码
|
password: nacos # Nacos 密码
|
||||||
discovery: # 【配置中心】配置项
|
discovery: # 【配置中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ spring:
|
|||||||
username: nacos # Nacos 账号
|
username: nacos # Nacos 账号
|
||||||
password: nacos # Nacos 密码
|
password: nacos # Nacos 密码
|
||||||
discovery: # 【配置中心】配置项
|
discovery: # 【配置中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user