瀏覽代碼

【代码优化】AI:音乐生成产物上传至内部文件服务

xiaoxin 1 年之前
父節點
當前提交
bdd7d0c1fd

+ 2 - 2
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java

@@ -15,8 +15,8 @@ import java.util.Arrays;
 @Getter
 public enum AiMusicGenerateModeEnum implements IntArrayValuable {
 
-    LYRIC(1, "歌词模式"),
-    DESCRIPTION(2, "描述模式");
+    DESCRIPTION(1, "描述模式"),
+    LYRIC(2, "歌词模式");
 
     /**
      * 模式

+ 4 - 5
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java

@@ -20,21 +20,20 @@ public class AiSunoGenerateReqVO {
      * 1. 描述模式:描述词 + 是否纯音乐 + 模型 TODO @xin:目前貌似描述词没弄对?看着不是 prompt 字段(也可能我弄错了)。可以微信再沟通下哈
      * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 TODO @xin:目前这块少传递了标题;
      */
-    @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @Schema(description = "生成模式 1.描述模式 2. 歌词模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @NotNull(message = "生成模式不能为空")
     private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举
 
-    @Schema(description = "用于生成音乐音频的提示", requiredMode = Schema.RequiredMode.REQUIRED,
+    @Schema(description = "用于生成音乐音频的提示 1.描述模式:音乐/歌词说明 2.歌词模式:歌词", requiredMode = Schema.RequiredMode.REQUIRED,
             example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。")
     private String prompt;
 
     @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true")
     private Boolean makeInstrumental;
 
-    // TODO @xin:看了下这个字段,发现最终还是 model 合适点;因为它其实是模型
-    @Schema(description = "模型版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5")
+    @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5")
     @NotEmpty(message = "模型不能为空")
-    private String modelVersion; // 参见 AiModelEnum 枚举
+    private String model; // 参见 AiModelEnum 枚举
 
     @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]")
     private List<String> tags;

+ 36 - 19
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.service.music;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.text.StrPool;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicPageReqVO;
@@ -12,6 +13,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO;
 import cn.iocoder.yudao.module.ai.dal.mysql.music.AiMusicMapper;
 import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum;
 import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -38,6 +40,9 @@ public class AiMusicServiceImpl implements AiMusicService {
     @Resource
     private AiMusicMapper musicMapper;
 
+    @Resource
+    private FileApi fileApi;
+
     @Override
     public List<Long> generateMusic(Long userId, AiSunoGenerateReqVO reqVO) {
         // 1. 调用 Suno 生成音乐
@@ -45,12 +50,12 @@ public class AiMusicServiceImpl implements AiMusicService {
         if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) {
             // 1.1 歌词模式
             SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest(
-                    reqVO.getPrompt(), reqVO.getModelVersion(), CollUtil.join(reqVO.getTags(), StrPool.COMMA), reqVO.getTitle());
+                    reqVO.getPrompt(), reqVO.getModel(), CollUtil.join(reqVO.getTags(), StrPool.COMMA), reqVO.getTitle());
             musicDataList = sunoApi.customGenerate(generateRequest);
         } else if (Objects.equals(AiMusicGenerateModeEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) {
             // 1.2 描述模式
             SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest(
-                    reqVO.getPrompt(), reqVO.getModelVersion(), reqVO.getMakeInstrumental());
+                    reqVO.getPrompt(), reqVO.getModel(), reqVO.getMakeInstrumental());
             musicDataList = sunoApi.generate(generateRequest);
         } else {
             throw new IllegalArgumentException(StrUtil.format("未知生成模式({})", reqVO));
@@ -90,23 +95,6 @@ public class AiMusicServiceImpl implements AiMusicService {
         return streamingTask.size();
     }
 
-    /**
-     * 构建 AiMusicDO 集合
-     *
-     * @param musicList suno 音乐任务列表
-     * @return AiMusicDO 集合
-     */
-    private static List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicList) {
-        // TODO @xin:成功的情况下,需要下载到自己的文件服务器。参考图片的处理
-        return convertList(musicList, musicData -> new AiMusicDO()
-                .setTaskId(musicData.id()).setModel(musicData.modelName())
-                .setPrompt(musicData.prompt()).setGptDescriptionPrompt(musicData.gptDescriptionPrompt())
-                .setAudioUrl(musicData.audioUrl()).setVideoUrl(musicData.videoUrl()).setImageUrl(musicData.imageUrl())
-                .setTitle(musicData.title()).setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA))
-                .setStatus(Objects.equals("complete", musicData.status()) ?
-                        AiMusicStatusEnum.SUCCESS.getStatus() : AiMusicStatusEnum.IN_PROGRESS.getStatus()));
-    }
-
     @Override
     public void updateMusicPublicStatus(AiMusicUpdatePublicStatusReqVO updateReqVO) {
         // 校验存在
@@ -134,4 +122,33 @@ public class AiMusicServiceImpl implements AiMusicService {
         return musicMapper.selectPage(pageReqVO);
     }
 
+    /**
+     * 构建 AiMusicDO 集合
+     *
+     * @param musicList suno 音乐任务列表
+     * @return AiMusicDO 集合
+     */
+    private List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicList) {
+        return convertList(musicList, musicData -> new AiMusicDO()
+                .setTaskId(musicData.id()).setModel(musicData.modelName())
+                .setPrompt(musicData.prompt()).setGptDescriptionPrompt(musicData.gptDescriptionPrompt())
+                .setAudioUrl(createFile(musicData.audioUrl())).setVideoUrl(createFile(musicData.videoUrl())).setImageUrl(createFile(musicData.imageUrl()))
+                .setTitle(musicData.title()).setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA))
+                .setStatus(Objects.equals("complete", musicData.status()) ?
+                        AiMusicStatusEnum.SUCCESS.getStatus() : AiMusicStatusEnum.IN_PROGRESS.getStatus()));
+    }
+
+    /**
+     * 将生成的音频文件上传到文件服务器
+     *
+     * @param url 音频文件地址
+     * @return 内部文件地址
+     */
+    private String createFile(String url) {
+        if (StrUtil.isBlank(url)) {
+            return null;
+        }
+        byte[] bytes = HttpUtil.downloadBytes(url);
+        return fileApi.createFile(bytes);
+    }
 }