mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-31 09:30:05 +08:00
【新增】AI:API 密钥管理
This commit is contained in:
parent
04cb9bad5b
commit
caca47b6d7
@ -3,13 +3,14 @@ package cn.iocoder.yudao.module.ai;
|
|||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System 错误码枚举类
|
* AI 错误码枚举类
|
||||||
*
|
*
|
||||||
* system 系统,使用 1-002-000-000 段
|
* ai 系统,使用 1-040-000-000 段
|
||||||
*/
|
*/
|
||||||
public interface ErrorCodeConstants {
|
public interface ErrorCodeConstants {
|
||||||
|
|
||||||
// ========== 模块 ai 错误码区间 [1-022-000-000 ~ 1-023-000-000) ==========
|
// ========== API 密钥 1-040-000-000 ==========
|
||||||
|
ErrorCode API_KEY_NOT_EXISTS = new ErrorCode(1_040_000_000, "AI API 密钥不存在");
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
|
|
||||||
@ -37,4 +38,5 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} ");
|
ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} ");
|
||||||
ErrorCode AI_MODAL_DISABLE_NOT_USED = new ErrorCode(1_022_000_084, "AI 模型禁用不能使用!");
|
ErrorCode AI_MODAL_DISABLE_NOT_USED = new ErrorCode(1_022_000_084, "AI 模型禁用不能使用!");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
/**
|
|
||||||
* author: fansili
|
|
||||||
* time: 2024/3/3 18:14
|
|
||||||
*/
|
|
||||||
package cn.iocoder.yudao.module.ai;
|
|
@ -0,0 +1,72 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.model;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyRespVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
||||||
|
import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
|
||||||
|
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.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - AI API 密钥")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ai/api-key")
|
||||||
|
@Validated
|
||||||
|
public class AiApiKeyController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AiApiKeyService apiKeyService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建AI API 密钥")
|
||||||
|
@PreAuthorize("@ss.hasPermission('ai:api-key:create')")
|
||||||
|
public CommonResult<Long> createApiKey(@Valid @RequestBody AiApiKeySaveReqVO createReqVO) {
|
||||||
|
return success(apiKeyService.createApiKey(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新AI API 密钥")
|
||||||
|
@PreAuthorize("@ss.hasPermission('ai:api-key:update')")
|
||||||
|
public CommonResult<Boolean> updateApiKey(@Valid @RequestBody AiApiKeySaveReqVO updateReqVO) {
|
||||||
|
apiKeyService.updateApiKey(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除AI API 密钥")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('ai:api-key:delete')")
|
||||||
|
public CommonResult<Boolean> deleteApiKey(@RequestParam("id") Long id) {
|
||||||
|
apiKeyService.deleteApiKey(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得AI API 密钥")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('ai:api-key:query')")
|
||||||
|
public CommonResult<AiApiKeyRespVO> getApiKey(@RequestParam("id") Long id) {
|
||||||
|
AiApiKeyDO apiKey = apiKeyService.getApiKey(id);
|
||||||
|
return success(BeanUtils.toBean(apiKey, AiApiKeyRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得AI API 密钥分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('ai:api-key:query')")
|
||||||
|
public CommonResult<PageResult<AiApiKeyRespVO>> getApiKeyPage(@Valid AiApiKeyPageReqVO pageReqVO) {
|
||||||
|
PageResult<AiApiKeyDO> pageResult = apiKeyService.getApiKeyPage(pageReqVO);
|
||||||
|
return success(BeanUtils.toBean(pageResult, AiApiKeyRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI API 密钥分页 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class AiApiKeyPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "名称", example = "文心一言")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "平台", example = "OpenAI")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "状态", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI API 密钥 Response VO")
|
||||||
|
@Data
|
||||||
|
public class AiApiKeyRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC")
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI API 密钥新增/修改 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AiApiKeySaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言")
|
||||||
|
@NotEmpty(message = "名称不能为空")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC")
|
||||||
|
@NotEmpty(message = "密钥不能为空")
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||||
|
@NotEmpty(message = "平台不能为空")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "状态不能为空")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,5 @@
|
|||||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model;
|
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.ai.AiPlatformEnum;
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
@ -31,18 +31,16 @@ public class AiApiKeyDO extends BaseDO {
|
|||||||
* 名称
|
* 名称
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
/**
|
||||||
|
* 密钥
|
||||||
|
*/
|
||||||
|
private String apiKey;
|
||||||
/**
|
/**
|
||||||
* 平台
|
* 平台
|
||||||
*
|
*
|
||||||
* 枚举 {@link AiPlatformEnum}
|
* 枚举 {@link AiPlatformEnum}
|
||||||
*/
|
*/
|
||||||
private String platform;
|
private String platform;
|
||||||
/**
|
|
||||||
* 用途
|
|
||||||
*
|
|
||||||
* TODO 芋艿:枚举;chat、image
|
|
||||||
*/
|
|
||||||
private Integer type;
|
|
||||||
/**
|
/**
|
||||||
* API 地址
|
* API 地址
|
||||||
*/
|
*/
|
||||||
@ -54,6 +52,4 @@ public class AiApiKeyDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
// TODO 芋艿:proxyUrl 代理地址
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.dal.mysql.model;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI API 密钥 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AiApiKeyMapper extends BaseMapperX<AiApiKeyDO> {
|
||||||
|
|
||||||
|
default PageResult<AiApiKeyDO> selectPage(AiApiKeyPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<AiApiKeyDO>()
|
||||||
|
.likeIfPresent(AiApiKeyDO::getName, reqVO.getName())
|
||||||
|
.eqIfPresent(AiApiKeyDO::getPlatform, reqVO.getPlatform())
|
||||||
|
.eqIfPresent(AiApiKeyDO::getStatus, reqVO.getStatus())
|
||||||
|
.orderByDesc(AiApiKeyDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.service.model;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI API 密钥 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface AiApiKeyService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建AI API 密钥
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createApiKey(@Valid AiApiKeySaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新AI API 密钥
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateApiKey(@Valid AiApiKeySaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除AI API 密钥
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteApiKey(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得AI API 密钥
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return AI API 密钥
|
||||||
|
*/
|
||||||
|
AiApiKeyDO getApiKey(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得AI API 密钥分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return AI API 密钥分页
|
||||||
|
*/
|
||||||
|
PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.service.model;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
||||||
|
import cn.iocoder.yudao.module.ai.dal.mysql.model.AiApiKeyMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.API_KEY_NOT_EXISTS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI API 密钥 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class AiApiKeyServiceImpl implements AiApiKeyService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AiApiKeyMapper apiKeyMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createApiKey(AiApiKeySaveReqVO createReqVO) {
|
||||||
|
// 插入
|
||||||
|
AiApiKeyDO apiKey = BeanUtils.toBean(createReqVO, AiApiKeyDO.class);
|
||||||
|
apiKeyMapper.insert(apiKey);
|
||||||
|
// 返回
|
||||||
|
return apiKey.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateApiKey(AiApiKeySaveReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
validateApiKeyExists(updateReqVO.getId());
|
||||||
|
// 更新
|
||||||
|
AiApiKeyDO updateObj = BeanUtils.toBean(updateReqVO, AiApiKeyDO.class);
|
||||||
|
apiKeyMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteApiKey(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
validateApiKeyExists(id);
|
||||||
|
// 删除
|
||||||
|
apiKeyMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateApiKeyExists(Long id) {
|
||||||
|
if (apiKeyMapper.selectById(id) == null) {
|
||||||
|
throw exception(API_KEY_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AiApiKeyDO getApiKey(Long id) {
|
||||||
|
return apiKeyMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO) {
|
||||||
|
return apiKeyMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
// TODO 芋艿:这块,看看要不要调整下;
|
||||||
/**
|
/**
|
||||||
* ai 模型平台
|
* ai 模型平台
|
||||||
*
|
*
|
||||||
@ -16,11 +17,10 @@ import java.util.List;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum AiPlatformEnum {
|
public enum AiPlatformEnum {
|
||||||
|
|
||||||
|
|
||||||
YI_YAN("yiyan", "一言"),
|
YI_YAN("yiyan", "一言"),
|
||||||
QIAN_WEN("qianwen", "千问"),
|
QIAN_WEN("qianwen", "千问"),
|
||||||
XING_HUO("xinghuo", "星火"),
|
XING_HUO("xinghuo", "星火"),
|
||||||
OPEN_AI("openai", "openAi"),
|
OPEN_AI("openai", "openAi"), // TODO 芋艿:OpenAI
|
||||||
OPEN_AI_DALL("dall", "dall"),
|
OPEN_AI_DALL("dall", "dall"),
|
||||||
MIDJOURNEY("midjourney", "midjourney"),
|
MIDJOURNEY("midjourney", "midjourney"),
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user