Преглед на файлове

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

YunaiV преди 1 година
родител
ревизия
75a91a2c46

+ 2 - 0
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;
 @Getter
 public enum AiMusicGenerateEnum {
 
+    // TODO @xin:用数字哈。项目目前枚举都是数字
     LYRIC("lyric", "歌词模式"),
     DESCRIPTION("description", "描述模式");
 
@@ -32,4 +33,5 @@ public enum AiMusicGenerateEnum {
         }
         throw new IllegalArgumentException("未知模式: " + mode);
     }
+
 }

+ 1 - 0
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;
 @Getter
 public enum AiMusicStatusEnum {
 
+    // TODO @xin:用数字哈。项目目前枚举都是数字
     // @xin 文档中无失败这个返回值
     STREAMING("streaming", "进行中"),
     COMPLETE("complete", "完成");

+ 3 - 2
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;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
-@Tag(name = "管理后台 - AI 音乐生成")
+@Tag(name = "管理后台 - AI 音乐")
 @RestController
 @RequestMapping("/ai/music")
-@RequiredArgsConstructor
+@RequiredArgsConstructor // TODO @xin:通过 @Resource 注入哈
 public class AiMusicController {
 
+    // TODO @xin:变量不用有 ai 前缀
     private final AiMusicService aiMusicService;
 
     @PostMapping("/generate")

+ 3 - 2
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;
 
 import java.util.List;
 
-
+// TODO @xin:1)ai 前缀;2)AiSunoGenerateReqVO,要有生成哈。3)swaggger 缺少的属性,也最好加下,类似 example,类上的 swagger 等
 /**
  * @author xiaoxin
  */
@@ -19,7 +19,8 @@ public class SunoReqVO {
     @Schema(description = "是否纯音乐")
     private Boolean makeInstrumental;
 
-    @Schema(description = "模型版本 ")
+    // TODO @xin:我们自己是不是用 modelVersion?还是什么梗精准,减少非必要的缩写
+    @Schema(description = "模型版本")
     private String mv;
 
     @Schema(description = "音乐风格")

+ 2 - 2
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;
 
 import java.util.List;
 
+// TODO @xin:注释完善下
 /**
  * @Author xiaoxin
  * @Date 2024/6/5
@@ -94,7 +95,6 @@ public class AiMusicDO extends BaseDO {
      */
     private String errorMessage;
 
-
     /**
      * 音乐风格标签
      */
@@ -106,7 +106,7 @@ public class AiMusicDO extends BaseDO {
      */
     private String taskId;
 
-
+    // TODO @xin:用     @TableField(typeHandler = JacksonTypeHandler.class) 替代即可
     public static class AiMusicTagsHandler extends AbstractJsonTypeHandler<Object> {
 
         @Override

+ 2 - 0
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;
 import java.util.List;
 import java.util.Map;
 
+// TODO @xin:不要直接叫这个名字哈,要有它的目的
 /**
  * 处理 Suno Job
  * @author xiaoxin
@@ -30,6 +31,7 @@ public class SunoJob implements JobHandler {
 
     @Override
     public String execute(String param) {
+        // TODO @xin:可以考虑,整个逻辑都下沉到 Service 里,有点类似 AccessLogCleanJob
         List<AiMusicDO> unCompletedTask = musicService.getUnCompletedTask();
 
         if (CollUtil.isEmpty(unCompletedTask)) {

+ 4 - 2
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 {
                 .setTags(StrUtil.isNotBlank(musicData.tags()) ? List.of(musicData.tags().split(StrPool.COMMA)) : null);
     }
 
-    public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> musicDataList) {
-        return musicDataList.stream()
+    // TODO @xin:一般情况下,不用 convert,直接逻辑里 convert 就好啦。
+    public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> list) {
+        // TODO @xin:可以使用 CollectionUtils.convertList 简洁一点
+        return list.stream()
                 .map(AiMusicConvert::convertFrom)
                 .collect(Collectors.toList());
     }

+ 0 - 4
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;
  */
 public interface AiMusicService {
 
-
     /**
      * 音乐生成
      *
@@ -21,7 +20,6 @@ public interface AiMusicService {
      */
     List<Long> generateMusic(SunoReqVO reqVO);
 
-
     /**
      * 获取未完成状态的任务
      *
@@ -29,8 +27,6 @@ public interface AiMusicService {
      */
     List<AiMusicDO> getUnCompletedTask();
 
-
     Boolean updateBatch(List<AiMusicDO> aiMusicDOList);
 
-
 }

+ 3 - 0
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
 
 /**
  * AI 音乐 Service 实现类
+ *
  * @author xiaoxin
  */
 @Service
@@ -29,11 +30,13 @@ public class AiMusicServiceImpl implements AiMusicService {
 
     @Resource
     private SunoApi sunoApi;
+
     @Resource
     private AiMusicMapper musicMapper;
 
     @Override
     public List<Long> generateMusic(SunoReqVO reqVO) {
+        // TODO @xin:是不是可以 if else 调用对应的 API,然后 insertMusicData 逻辑
         AiMusicGenerateEnum generateEnum = AiMusicGenerateEnum.valueOfMode(reqVO.getGenerateMode());
         return switch (generateEnum) {
             case DESCRIPTION -> descriptionMode(reqVO);

+ 6 - 7
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;
 
 /**
  * Suno API
- * <b>
- * 文档地址:https://github.com/status2xx/suno-api/blob/main/README_CN.md
+ *
+ * 对接 Suno Proxy:<a href="https://github.com/gcui-art/suno-api">suno-api</a>
  *
  * @author xiaoxin
  */
@@ -31,14 +31,14 @@ public class SunoApi {
 
     private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful();
 
-    private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION = reqParam -> response -> response.bodyToMono(String.class)
-            .handle((respBody, sink) -> {
+    private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
+            reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
                 HttpRequest request = response.request();
-                log.error("[suno-api] 调用失败!请求方式:[{}], 请求地址:[{}], 请求参数:[{}], 响应数据: [{}]", request.getMethod(), request.getURI(), reqParam, respBody);
+                log.error("[suno-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
+                        request.getMethod(), request.getURI(), reqParam, responseBody);
                 sink.error(new IllegalStateException("[suno-api] 调用失败!"));
             });
 
-
     public SunoApi(String baseUrl) {
         this.webClient = WebClient.builder()
                 .baseUrl(baseUrl)
@@ -111,7 +111,6 @@ public class SunoApi {
                 .block();
     }
 
-
     /**
      * 根据提示生成音频
      *