Commit c77fc954d20b6badae1d0f1512f3652a054e9f1f

Authored by 芋道源码
Committed by Gitee
2 parents 05e4ccac 44a0b04d

!6 【解决todo】AI:音乐接入

Merge pull request !6 from 小新/master-jdk21-ai
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateEnum.java renamed to yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.ai.enums.music; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.ai.enums.music;
3 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 -// TODO @xiaoxin:这个也叫 AiMusicGenerateModeEnum 吧。虽然长,但是和项目统一一点。  
7 /** 6 /**
8 * AI 音乐状态的枚举 7 * AI 音乐状态的枚举
9 * 8 *
@@ -11,27 +10,18 @@ import lombok.Getter; @@ -11,27 +10,18 @@ import lombok.Getter;
11 */ 10 */
12 @AllArgsConstructor 11 @AllArgsConstructor
13 @Getter 12 @Getter
14 -public enum AiMusicGenerateEnum { 13 +public enum AiMusicGenerateModeEnum {
15 14
16 - LYRIC("1", "歌词模式"),  
17 - DESCRIPTION("2", "描述模式"); 15 + LYRIC(1, "歌词模式"),
  16 + DESCRIPTION(2, "描述模式");
18 17
19 /** 18 /**
20 * 模式 19 * 模式
21 */ 20 */
22 - private final String mode; 21 + private final Integer mode;
23 /** 22 /**
24 * 模式名 23 * 模式名
25 */ 24 */
26 private final String name; 25 private final String name;
27 26
28 - public static AiMusicGenerateEnum valueOfMode(String mode) {  
29 - for (AiMusicGenerateEnum modeEnum : AiMusicGenerateEnum.values()) {  
30 - if (modeEnum.getMode().equals(mode)) {  
31 - return modeEnum;  
32 - }  
33 - }  
34 - throw new IllegalArgumentException("未知模式: " + mode);  
35 - }  
36 -  
37 } 27 }
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicStatusEnum.java
@@ -12,14 +12,14 @@ import lombok.Getter; @@ -12,14 +12,14 @@ import lombok.Getter;
12 @Getter 12 @Getter
13 public enum AiMusicStatusEnum { 13 public enum AiMusicStatusEnum {
14 14
15 - // @xin 文档中无失败这个返回值 TODO @xin:用 Integer 哈。另外个枚举类也是  
16 - STREAMING("10", "进行中"),  
17 - COMPLETE("20", "完成"); 15 + // @xin 文档中无失败这个返回值
  16 + STREAMING(10, "进行中"),
  17 + COMPLETE(20, "完成");
18 18
19 /** 19 /**
20 * 状态 20 * 状态
21 */ 21 */
22 - private final String status; 22 + private final Integer status;
23 23
24 /** 24 /**
25 * 状态名 25 * 状态名
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.music.vo; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotBlank; 4 import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
5 import lombok.Data; 6 import lombok.Data;
6 7
7 import java.util.List; 8 import java.util.List;
@@ -10,20 +11,19 @@ import java.util.List; @@ -10,20 +11,19 @@ import java.util.List;
10 @Data 11 @Data
11 public class AiSunoGenerateReqVO { 12 public class AiSunoGenerateReqVO {
12 13
13 - // TODO @xin:每个参数,必要的是否必填校验  
14 - @Schema(description = "用于生成音乐音频的提示", example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") 14 + @Schema(description = "用于生成音乐音频的提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。")
15 private String prompt; 15 private String prompt;
16 16
17 - @Schema(description = "是否纯音乐", example = "true") 17 + @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true")
18 private Boolean makeInstrumental; 18 private Boolean makeInstrumental;
19 19
20 - @Schema(description = "模型版本, 默认 chirp-v3.5", example = "chirp-v3.5") 20 + @Schema(description = "模型版本, 默认 chirp-v3.5", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "chirp-v3.5")
21 private String modelVersion; // 参见 AiModelEnum 枚举 21 private String modelVersion; // 参见 AiModelEnum 枚举
22 22
23 - @Schema(description = "音乐风格", example = "[\"pop\",\"jazz\",\"punk\"]") 23 + @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]")
24 private List<String> tags; 24 private List<String> tags;
25 25
26 - @Schema(description = "音乐/歌曲名称", example = "夜空中最亮的星") 26 + @Schema(description = "音乐/歌曲名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "夜空中最亮的星")
27 private String title; 27 private String title;
28 28
29 @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno") 29 @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno")
@@ -31,7 +31,7 @@ public class AiSunoGenerateReqVO { @@ -31,7 +31,7 @@ public class AiSunoGenerateReqVO {
31 private String platform; // 参见 AiPlatformEnum 枚举 31 private String platform; // 参见 AiPlatformEnum 枚举
32 32
33 @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 33 @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
34 - @NotBlank(message = "生成模式不能为空")  
35 - private String generateMode; // 参见 AiMusicGenerateEnum 枚举 34 + @NotNull(message = "生成模式不能为空")
  35 + private Integer generateMode; // 参见 AiMusicGenerateEnum 枚举
36 36
37 } 37 }
38 \ No newline at end of file 38 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
@@ -63,7 +63,7 @@ public class AiMusicDO extends BaseDO { @@ -63,7 +63,7 @@ public class AiMusicDO extends BaseDO {
63 * <p> 63 * <p>
64 * 枚举 {@link AiMusicStatusEnum} 64 * 枚举 {@link AiMusicStatusEnum}
65 */ 65 */
66 - private String status; 66 + private Integer status;
67 67
68 /** 68 /**
69 * 描述词 69 * 描述词
@@ -77,7 +77,7 @@ public class AiMusicDO extends BaseDO { @@ -77,7 +77,7 @@ public class AiMusicDO extends BaseDO {
77 /** 77 /**
78 * 生成模式 78 * 生成模式
79 */ 79 */
80 - private String generateMode; 80 + private Integer generateMode;
81 81
82 /** 82 /**
83 * 平台 83 * 平台
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.music; 1 package cn.iocoder.yudao.module.ai.dal.mysql.music;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
4 import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; 5 import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO;
5 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
6 7
  8 +import java.util.List;
  9 +
7 /** 10 /**
8 * AI 音乐 Mapper 11 * AI 音乐 Mapper
9 - * @author xiaoxin 12 + *
  13 + * @author xiaoxin
10 */ 14 */
11 @Mapper 15 @Mapper
12 public interface AiMusicMapper extends BaseMapperX<AiMusicDO> { 16 public interface AiMusicMapper extends BaseMapperX<AiMusicDO> {
  17 +
  18 + default List<AiMusicDO> selectListByStatus(Integer status) {
  19 + return selectList(new LambdaQueryWrapperX<AiMusicDO>()
  20 + .eq(AiMusicDO::getStatus, status));
  21 + }
  22 +
13 } 23 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/job/sun/AiSunoSyncJob.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/job/music/AiSunoSyncJob.java
1 -package cn.iocoder.yudao.module.ai.job.sun; 1 +package cn.iocoder.yudao.module.ai.job.music;
2 2
3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 import cn.iocoder.yudao.module.ai.service.music.AiMusicService; 4 import cn.iocoder.yudao.module.ai.service.music.AiMusicService;
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java
1 package cn.iocoder.yudao.module.ai.service.music; 1 package cn.iocoder.yudao.module.ai.service.music;
2 2
3 import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; 3 import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO;
4 -import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO;  
5 4
6 import java.util.List; 5 import java.util.List;
7 6
@@ -21,25 +20,9 @@ public interface AiMusicService { @@ -21,25 +20,9 @@ public interface AiMusicService {
21 List<Long> generateMusic(AiSunoGenerateReqVO reqVO); 20 List<Long> generateMusic(AiSunoGenerateReqVO reqVO);
22 21
23 /** 22 /**
24 - * 获取未完成状态的任务  
25 - *  
26 - * @return 未完成任务列表  
27 - */  
28 - List<AiMusicDO> getUnCompletedTask();  
29 -  
30 - /**  
31 * 同步音乐任务 23 * 同步音乐任务
32 * 24 *
33 * @return 同步数量 25 * @return 同步数量
34 */ 26 */
35 Integer syncMusic(); 27 Integer syncMusic();
36 -  
37 - /**  
38 - * 批量更新音乐信息  
39 - *  
40 - * @param musicDOS 音乐信息  
41 - * @return 是否成功  
42 - */  
43 - Boolean updateBatch(List<AiMusicDO> musicDOS);  
44 -  
45 } 28 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java
@@ -8,15 +8,13 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -8,15 +8,13 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; 8 import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO;
9 import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; 9 import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO;
10 import cn.iocoder.yudao.module.ai.dal.mysql.music.AiMusicMapper; 10 import cn.iocoder.yudao.module.ai.dal.mysql.music.AiMusicMapper;
11 -import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateEnum; 11 +import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum;
12 import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; 12 import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum;
13 -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;  
14 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
15 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
16 import org.springframework.stereotype.Service; 15 import org.springframework.stereotype.Service;
17 16
18 import java.util.*; 17 import java.util.*;
19 -import java.util.stream.Collectors;  
20 18
21 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 19 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
22 20
@@ -38,87 +36,54 @@ public class AiMusicServiceImpl implements AiMusicService { @@ -38,87 +36,54 @@ public class AiMusicServiceImpl implements AiMusicService {
38 @Override 36 @Override
39 public List<Long> generateMusic(AiSunoGenerateReqVO reqVO) { 37 public List<Long> generateMusic(AiSunoGenerateReqVO reqVO) {
40 List<SunoApi.MusicData> musicDataList; 38 List<SunoApi.MusicData> musicDataList;
41 - if (Objects.equals(AiMusicGenerateEnum.LYRIC.getMode(), reqVO.getGenerateMode())) { 39 + if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) {
42 // 1.1 歌词模式 40 // 1.1 歌词模式
43 SunoApi.MusicGenerateRequest sunoReq = new SunoApi.MusicGenerateRequest( 41 SunoApi.MusicGenerateRequest sunoReq = new SunoApi.MusicGenerateRequest(
44 reqVO.getPrompt(), reqVO.getModelVersion(), CollUtil.join(reqVO.getTags(), StrPool.COMMA), reqVO.getTitle()); 42 reqVO.getPrompt(), reqVO.getModelVersion(), CollUtil.join(reqVO.getTags(), StrPool.COMMA), reqVO.getTitle());
45 musicDataList = sunoApi.customGenerate(sunoReq); 43 musicDataList = sunoApi.customGenerate(sunoReq);
46 - } else if (Objects.equals(AiMusicGenerateEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) { 44 + } else if (Objects.equals(AiMusicGenerateModeEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) {
47 // 1.2 描述模式 45 // 1.2 描述模式
48 SunoApi.MusicGenerateRequest sunoReq = new SunoApi.MusicGenerateRequest( 46 SunoApi.MusicGenerateRequest sunoReq = new SunoApi.MusicGenerateRequest(
49 reqVO.getPrompt(), reqVO.getModelVersion(), reqVO.getMakeInstrumental()); 47 reqVO.getPrompt(), reqVO.getModelVersion(), reqVO.getMakeInstrumental());
50 musicDataList = sunoApi.generate(sunoReq); 48 musicDataList = sunoApi.generate(sunoReq);
51 } else { 49 } else {
52 - // TODO @xin:不用 log error,直接抛异常,吧 reqVO 呆进去,有全局处理的哈  
53 - log.error("未知的生成模式:{}", reqVO.getGenerateMode());  
54 - throw new IllegalArgumentException("未知的生成模式"); 50 + throw new IllegalArgumentException(StrUtil.format("未知生成模式({})", reqVO));
55 } 51 }
56 -  
57 // 2. 插入数据库 52 // 2. 插入数据库
58 - // TODO @xin:因为 insertMusicData 复用的比较少,所以不用愁单独的方法,直接写在这里就好啦  
59 - return insertMusicData(musicDataList, reqVO.getGenerateMode(), reqVO.getPlatform());  
60 - } 53 + if (CollUtil.isEmpty(musicDataList)) {
61 54
62 - // TODO @xin:1)service 里面,不要直接查询 db;2)不要用 ne,用 STREAMING 哈  
63 - @Override  
64 - public List<AiMusicDO> getUnCompletedTask() {  
65 - return musicMapper.selectList(new LambdaQueryWrapper<AiMusicDO>().ne(AiMusicDO::getStatus, AiMusicStatusEnum.COMPLETE.getStatus())); 55 + return Collections.emptyList();
  56 + }
  57 + List<AiMusicDO> aiMusicDOList = CollectionUtils.convertList(buildMusicDOList(musicDataList), musicDO ->
  58 + musicDO.setUserId(getLoginUserId())
  59 + .setGenerateMode(reqVO.getGenerateMode())
  60 + .setPlatform(reqVO.getPlatform()
  61 + ));
  62 + musicMapper.insertBatch(aiMusicDOList);
  63 + return CollectionUtils.convertList(aiMusicDOList, AiMusicDO::getId);
66 } 64 }
67 65
68 @Override 66 @Override
69 public Integer syncMusic() { 67 public Integer syncMusic() {
70 - List<AiMusicDO> unCompletedTask = this.getUnCompletedTask();  
71 - if (CollUtil.isEmpty(unCompletedTask)) {  
72 - // TODO @xin:这里不用打,反正 Job 也打了  
73 - log.info("Suno 无进行中任务需要更新!"); 68 + List<AiMusicDO> streamingTask = musicMapper.selectListByStatus(AiMusicStatusEnum.STREAMING.getStatus());
  69 + if (CollUtil.isEmpty(streamingTask)) {
74 return 0; 70 return 0;
75 } 71 }
76 - log.info("[syncMusic][Suno 开始同步, 共 ({}) 个任务]", unCompletedTask.size()); 72 + log.info("[syncMusic][Suno 开始同步, 共 ({}) 个任务]", streamingTask.size());
77 // GET 请求,为避免参数过长,分批次处理 73 // GET 请求,为避免参数过长,分批次处理
78 - // TODO @xin:建议批量更大一些。  
79 - CollUtil.split(unCompletedTask, 4).forEach(chunk -> {  
80 - // TODO @xin:可以使用 CollectionUtils 里的 map 转换  
81 - Map<String, Long> taskIdMap = CollUtil.toMap(chunk, new HashMap<>(), AiMusicDO::getTaskId, AiMusicDO::getId); 74 + CollUtil.split(streamingTask, 36).forEach(chunk -> {
  75 + Map<String, Long> taskIdMap = CollectionUtils.convertMap(chunk, AiMusicDO::getTaskId, AiMusicDO::getId);
82 List<SunoApi.MusicData> musicTaskList = sunoApi.getMusicList(new ArrayList<>(taskIdMap.keySet())); 76 List<SunoApi.MusicData> musicTaskList = sunoApi.getMusicList(new ArrayList<>(taskIdMap.keySet()));
83 - // TODO @xin:查询不到,直接 return;这样真正逻辑的 85 - 87 就不用多一层括号  
84 - if (CollUtil.isNotEmpty(musicTaskList)) {  
85 - List<AiMusicDO> aiMusicDOS = buildMusicDOList(musicTaskList);  
86 - //回填id  
87 - aiMusicDOS.forEach(aiMusicDO -> aiMusicDO.setId(taskIdMap.get(aiMusicDO.getTaskId())));  
88 - this.updateBatch(aiMusicDOS);  
89 - } else { 77 + if (CollUtil.isEmpty(musicTaskList)) {
90 log.warn("Suno 任务同步失败, 任务ID: [{}]", taskIdMap.keySet()); 78 log.warn("Suno 任务同步失败, 任务ID: [{}]", taskIdMap.keySet());
  79 + return;
91 } 80 }
  81 + List<AiMusicDO> aiMusicDOS = buildMusicDOList(musicTaskList);
  82 + //回填id
  83 + aiMusicDOS.forEach(aiMusicDO -> aiMusicDO.setId(taskIdMap.get(aiMusicDO.getTaskId())));
  84 + musicMapper.updateBatch(aiMusicDOS);
92 }); 85 });
93 - return unCompletedTask.size();  
94 - }  
95 -  
96 - // TODO @xin:这个方法,看着不用啦  
97 - @Override  
98 - public Boolean updateBatch(List<AiMusicDO> musicDOS) {  
99 - return musicMapper.updateBatch(musicDOS);  
100 - }  
101 -  
102 - /**  
103 - * 新增音乐数据并提交 suno任务  
104 - *  
105 - * @param musicDataList 音乐数据列表  
106 - * @return 音乐id集合  
107 - */  
108 - private List<Long> insertMusicData(List<SunoApi.MusicData> musicDataList, String generateMode, String platform) {  
109 - if (CollUtil.isEmpty(musicDataList)) {  
110 - return Collections.emptyList();  
111 - }  
112 - List<AiMusicDO> aiMusicDOList = buildMusicDOList(musicDataList).stream()  
113 - .map(musicDO -> musicDO.setUserId(getLoginUserId())  
114 - .setGenerateMode(generateMode)  
115 - .setPlatform(platform))  
116 - .toList();  
117 - musicMapper.insertBatch(aiMusicDOList);  
118 - // TODO @xin:用 CollectionUtils 简化操作  
119 - return aiMusicDOList.stream()  
120 - .map(AiMusicDO::getId)  
121 - .collect(Collectors.toList()); 86 + return streamingTask.size();
122 } 87 }
123 88
124 /** 89 /**
@@ -128,20 +93,12 @@ public class AiMusicServiceImpl implements AiMusicService { @@ -128,20 +93,12 @@ public class AiMusicServiceImpl implements AiMusicService {
128 * @return AiMusicDO 集合 93 * @return AiMusicDO 集合
129 */ 94 */
130 private static List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicTaskList) { 95 private static List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicTaskList) {
131 - // TODO @xin:想通的变量,放在同一行,避免过长。  
132 return CollectionUtils.convertList(musicTaskList, musicData -> new AiMusicDO() 96 return CollectionUtils.convertList(musicTaskList, musicData -> new AiMusicDO()
133 .setTaskId(musicData.id()) 97 .setTaskId(musicData.id())
134 - .setPrompt(musicData.prompt())  
135 - .setGptDescriptionPrompt(musicData.gptDescriptionPrompt())  
136 - .setAudioUrl(musicData.audioUrl())  
137 - .setVideoUrl(musicData.videoUrl())  
138 - .setImageUrl(musicData.imageUrl())  
139 - .setLyric(musicData.lyric())  
140 - .setTitle(musicData.title())  
141 - .setStatus(Objects.equals("complete", musicData.status()) ? AiMusicStatusEnum.COMPLETE.getStatus() : AiMusicStatusEnum.STREAMING.getStatus())  
142 - .setModel(musicData.modelName())  
143 - // TODO @xin:可以用 hutool 的 StrUtil 的 split 之类的  
144 - .setTags(StrUtil.isNotBlank(musicData.tags()) ? List.of(musicData.tags().split(StrPool.COMMA)) : null));  
145 - } 98 + .setPrompt(musicData.prompt()).setGptDescriptionPrompt(musicData.gptDescriptionPrompt())
  99 + .setAudioUrl(musicData.audioUrl()).setVideoUrl(musicData.videoUrl()).setImageUrl(musicData.imageUrl())
  100 + .setTitle(musicData.title()).setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA))
  101 + .setModel(musicData.modelName()).setStatus(Objects.equals("complete", musicData.status()) ? AiMusicStatusEnum.COMPLETE.getStatus() : AiMusicStatusEnum.STREAMING.getStatus()));
146 102
  103 + }
147 } 104 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java
@@ -19,7 +19,7 @@ import java.util.function.Predicate; @@ -19,7 +19,7 @@ import java.util.function.Predicate;
19 19
20 /** 20 /**
21 * Suno API 21 * Suno API
22 - * 22 + * <p>
23 * 对接 Suno Proxy:<a href="https://github.com/gcui-art/suno-api">suno-api</a> 23 * 对接 Suno Proxy:<a href="https://github.com/gcui-art/suno-api">suno-api</a>
24 * 24 *
25 * @author xiaoxin 25 * @author xiaoxin
yudao-server/src/main/resources/application.yaml
@@ -200,7 +200,7 @@ yudao.ai: @@ -200,7 +200,7 @@ yudao.ai:
200 notify-url: http://java.nat300.top/admin-api/ai/image/midjourney/notify 200 notify-url: http://java.nat300.top/admin-api/ai/image/midjourney/notify
201 suno: 201 suno:
202 enable: true 202 enable: true
203 - base-url: https://suno-imrqwwui8-status2xxs-projects.vercel.app 203 + base-url: https://suno-om0w1cy6e-status2xxs-projects.vercel.app
204 204
205 --- #################### 芋道相关配置 #################### 205 --- #################### 芋道相关配置 ####################
206 206