Commit 75a91a2c467a52caa844cf86b7dea6572125e939

Authored by YunaiV
1 parent 69b05a30

【代码评审】AI:音乐接入

yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateEnum.java
... ... @@ -12,6 +12,7 @@ import lombok.Getter;
12 12 @Getter
13 13 public enum AiMusicGenerateEnum {
14 14  
  15 + // TODO @xin:用数字哈。项目目前枚举都是数字
15 16 LYRIC("lyric", "歌词模式"),
16 17 DESCRIPTION("description", "描述模式");
17 18  
... ... @@ -32,4 +33,5 @@ public enum AiMusicGenerateEnum {
32 33 }
33 34 throw new IllegalArgumentException("未知模式: " + mode);
34 35 }
  36 +
35 37 }
... ...
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicStatusEnum.java
... ... @@ -12,6 +12,7 @@ import lombok.Getter;
12 12 @Getter
13 13 public enum AiMusicStatusEnum {
14 14  
  15 + // TODO @xin:用数字哈。项目目前枚举都是数字
15 16 // @xin 文档中无失败这个返回值
16 17 STREAMING("streaming", "进行中"),
17 18 COMPLETE("complete", "完成");
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java
... ... @@ -16,12 +16,13 @@ import java.util.List;
16 16  
17 17 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18 18  
19   -@Tag(name = "管理后台 - AI 音乐生成")
  19 +@Tag(name = "管理后台 - AI 音乐")
20 20 @RestController
21 21 @RequestMapping("/ai/music")
22   -@RequiredArgsConstructor
  22 +@RequiredArgsConstructor // TODO @xin:通过 @Resource 注入哈
23 23 public class AiMusicController {
24 24  
  25 + // TODO @xin:变量不用有 ai 前缀
25 26 private final AiMusicService aiMusicService;
26 27  
27 28 @PostMapping("/generate")
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/SunoReqVO.java
... ... @@ -6,7 +6,7 @@ import lombok.Data;
6 6  
7 7 import java.util.List;
8 8  
9   -
  9 +// TODO @xin:1)ai 前缀;2)AiSunoGenerateReqVO,要有生成哈。3)swaggger 缺少的属性,也最好加下,类似 example,类上的 swagger 等
10 10 /**
11 11 * @author xiaoxin
12 12 */
... ... @@ -19,7 +19,8 @@ public class SunoReqVO {
19 19 @Schema(description = "是否纯音乐")
20 20 private Boolean makeInstrumental;
21 21  
22   - @Schema(description = "模型版本 ")
  22 + // TODO @xin:我们自己是不是用 modelVersion?还是什么梗精准,减少非必要的缩写
  23 + @Schema(description = "模型版本")
23 24 private String mv;
24 25  
25 26 @Schema(description = "音乐风格")
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
... ... @@ -12,6 +12,7 @@ import lombok.Data;
12 12  
13 13 import java.util.List;
14 14  
  15 +// TODO @xin:注释完善下
15 16 /**
16 17 * @Author xiaoxin
17 18 * @Date 2024/6/5
... ... @@ -94,7 +95,6 @@ public class AiMusicDO extends BaseDO {
94 95 */
95 96 private String errorMessage;
96 97  
97   -
98 98 /**
99 99 * 音乐风格标签
100 100 */
... ... @@ -106,7 +106,7 @@ public class AiMusicDO extends BaseDO {
106 106 */
107 107 private String taskId;
108 108  
109   -
  109 + // TODO @xin:用 @TableField(typeHandler = JacksonTypeHandler.class) 替代即可
110 110 public static class AiMusicTagsHandler extends AbstractJsonTypeHandler<Object> {
111 111  
112 112 @Override
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/job/SunoJob.java
... ... @@ -15,6 +15,7 @@ import java.util.HashMap;
15 15 import java.util.List;
16 16 import java.util.Map;
17 17  
  18 +// TODO @xin:不要直接叫这个名字哈,要有它的目的
18 19 /**
19 20 * 处理 Suno Job
20 21 * @author xiaoxin
... ... @@ -30,6 +31,7 @@ public class SunoJob implements JobHandler {
30 31  
31 32 @Override
32 33 public String execute(String param) {
  34 + // TODO @xin:可以考虑,整个逻辑都下沉到 Service 里,有点类似 AccessLogCleanJob
33 35 List<AiMusicDO> unCompletedTask = musicService.getUnCompletedTask();
34 36  
35 37 if (CollUtil.isEmpty(unCompletedTask)) {
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicConvert.java
... ... @@ -30,8 +30,10 @@ public class AiMusicConvert {
30 30 .setTags(StrUtil.isNotBlank(musicData.tags()) ? List.of(musicData.tags().split(StrPool.COMMA)) : null);
31 31 }
32 32  
33   - public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> musicDataList) {
34   - return musicDataList.stream()
  33 + // TODO @xin:一般情况下,不用 convert,直接逻辑里 convert 就好啦。
  34 + public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> list) {
  35 + // TODO @xin:可以使用 CollectionUtils.convertList 简洁一点
  36 + return list.stream()
35 37 .map(AiMusicConvert::convertFrom)
36 38 .collect(Collectors.toList());
37 39 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java
... ... @@ -12,7 +12,6 @@ import java.util.List;
12 12 */
13 13 public interface AiMusicService {
14 14  
15   -
16 15 /**
17 16 * 音乐生成
18 17 *
... ... @@ -21,7 +20,6 @@ public interface AiMusicService {
21 20 */
22 21 List<Long> generateMusic(SunoReqVO reqVO);
23 22  
24   -
25 23 /**
26 24 * 获取未完成状态的任务
27 25 *
... ... @@ -29,8 +27,6 @@ public interface AiMusicService {
29 27 */
30 28 List<AiMusicDO> getUnCompletedTask();
31 29  
32   -
33 30 Boolean updateBatch(List<AiMusicDO> aiMusicDOList);
34 31  
35   -
36 32 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java
... ... @@ -21,6 +21,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
21 21  
22 22 /**
23 23 * AI 音乐 Service 实现类
  24 + *
24 25 * @author xiaoxin
25 26 */
26 27 @Service
... ... @@ -29,11 +30,13 @@ public class AiMusicServiceImpl implements AiMusicService {
29 30  
30 31 @Resource
31 32 private SunoApi sunoApi;
  33 +
32 34 @Resource
33 35 private AiMusicMapper musicMapper;
34 36  
35 37 @Override
36 38 public List<Long> generateMusic(SunoReqVO reqVO) {
  39 + // TODO @xin:是不是可以 if else 调用对应的 API,然后 insertMusicData 逻辑
37 40 AiMusicGenerateEnum generateEnum = AiMusicGenerateEnum.valueOfMode(reqVO.getGenerateMode());
38 41 return switch (generateEnum) {
39 42 case DESCRIPTION -> descriptionMode(reqVO);
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java
... ... @@ -19,8 +19,8 @@ import java.util.function.Predicate;
19 19  
20 20 /**
21 21 * Suno API
22   - * <b>
23   - * 文档地址:https://github.com/status2xx/suno-api/blob/main/README_CN.md
  22 + *
  23 + * 对接 Suno Proxy:<a href="https://github.com/gcui-art/suno-api">suno-api</a>
24 24 *
25 25 * @author xiaoxin
26 26 */
... ... @@ -31,14 +31,14 @@ public class SunoApi {
31 31  
32 32 private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful();
33 33  
34   - private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION = reqParam -> response -> response.bodyToMono(String.class)
35   - .handle((respBody, sink) -> {
  34 + private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
  35 + reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
36 36 HttpRequest request = response.request();
37   - log.error("[suno-api] 调用失败!请求方式:[{}], 请求地址:[{}], 请求参数:[{}], 响应数据: [{}]", request.getMethod(), request.getURI(), reqParam, respBody);
  37 + log.error("[suno-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
  38 + request.getMethod(), request.getURI(), reqParam, responseBody);
38 39 sink.error(new IllegalStateException("[suno-api] 调用失败!"));
39 40 });
40 41  
41   -
42 42 public SunoApi(String baseUrl) {
43 43 this.webClient = WebClient.builder()
44 44 .baseUrl(baseUrl)
... ... @@ -111,7 +111,6 @@ public class SunoApi {
111 111 .block();
112 112 }
113 113  
114   -
115 114 /**
116 115 * 根据提示生成音频
117 116 *
... ...